Slack-интеграция в ASP.NET Web-Api 2

Я хочу точно знать, почему это не работает:

[HttpPost]
public IHttpActionResult Post(Slack_Webhook json)
{
    return Ok(json.challenge);
}

public class Slack_Webhook
{
    public string type { get; set; }
    public string token { get; set; }
    public string challenge { get; set; }
}

Официальная документация гласит:

Мы будем отправлять HTTP-запросы POST на этот URL при возникновении событий. Как только вы введете URL, мы отправим запрос с параметром вызова, и ваша конечная точка должна ответить значением запроса.

Это пример объекта (JSON), отправленный Slack:

{
    "token": "Jhj5dZrVaK7ZwHHjRyZWjbDl",
    "challenge": "3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P",
    "type": "url_verification"
}

РЕДАКТИРОВАТЬ: я мог бы написать книгу о коде, который не работает в этом выпуске... вот еще один пример, который не работал - до сих пор не знаю, что не так:

[HttpPost]
public IHttpActionResult Post()
{
    var pairs = Request.GetQueryNameValuePairs();
    bool isValidToken = false;
    string c = "This does not work.";
    foreach(var pair in pairs)
    {
        if (pair.Key == "token")
        {
            if (pair.Value == "<UNIQUETOKEN>")
            {
                isValidToken = true;
            }
        }
        if (pair.Key == "challenge")
        {
            c = pair.Value;
        }
    }
    if (isValidToken == true)
    {
        return Json(new {challenge = c });
    }
    else
    {
        return BadRequest();
    }
}

РЕДАКТИРОВАТЬ 2: Очень интересно, что я получаю NULL в качестве ответа от кода ниже - это означает, что тело полученного POST пусто. Может ли кто-нибудь с работающей Slack-Integration попробовать? Таким образом, их сайт неверен, заявив, что вызов отправлен в теле - где еще это может быть?

// POST: api/Slack
[HttpPost]
public IHttpActionResult Post([FromBody]string json)
{
    return Json(json);
}

EDIT3: эта функция используется для получения необработанного запроса, но внутри тела ничего нет - у меня нет решений... поддержка Slack сказала, что они понятия не имеют о ASP.NET, и я должен спросить здесь о SO для решение. Ну вот опять!;-)

[HttpPost]
public async Task<IHttpActionResult> ReceivePostAsync()
{
    string rawpostdata = await RawContentReader.Read(this.Request);
    return Json(new StringContent( rawpostdata));
}
public class RawContentReader
{
    public static async Task<string> Read(HttpRequestMessage req)
    {
        using (var contentStream = await req.Content.ReadAsStreamAsync())
        {
            contentStream.Seek(0, SeekOrigin.Begin);
            using (var sr = new StreamReader(contentStream))
            {
                return sr.ReadToEnd();
            }
        }
    }
}

Результат (как и ожидалось) выглядит так:

Our Request:
POST
"body": { 
     "type": "url_verification",
     "token": "<token>",
     "challenge": "<challenge>"
}
Your Response:
"code": 200
"error": "challenge_failed"
"body": {
 {"Headers":[{"Key":"Content-Type","Value":["text/plain; charset=utf-8"]}]} 
}

Я думаю, что что-то упустил - есть ли другой способ получить тело POST-запроса? Я имею в виду, я могу получить все остальное - кроме тела (или оно говорит, что оно пустое).

РЕДАКТИРОВАТЬ 4: Я попытался прочитать тело с другой функцией, которую я нашел - без успеха, возвращает пустую строку - но чтобы вы знали, что я уже пробовал, вот оно:

[HttpPost]
public IHttpActionResult ReceivePost()
{
    var bodyStream = new 
    StreamReader(HttpContext.Current.Request.InputStream);
    bodyStream.BaseStream.Seek(0, SeekOrigin.Begin);
    var bodyText = bodyStream.ReadToEnd();
    return Json(bodyText);
}

Пытаясь решить эту проблему, я многому научился, но это кажется настолько невозможным, что я думаю, что никогда не решу это в одиночку. Тысячи попыток с тысячами различных функций - я пробовал сотни параметров и функций во всех WebApi / ASP.NET / MVC / что угодно - почему нет тела? Это существует? Как его / ее зовут? Где оно живет? Я действительно хочу потусоваться с этим параметром, если я когда-нибудь его найду, он должен быть спрятан в конце радуги под горшком с золотом.

2 ответа

Если вы можете использовать ASP.NET Core 2, это поможет:

public async Task<ActionResult> HandleEvent([FromBody] dynamic data)
    => new ContentResult {Content = data.challenge};

Вот как вы можете получить доступ к данным:

[HttpPost]  
[Route("something")]
public JsonResult DoSomething()
{
    var token = HttpContext.Request.Form["token"];

    // Is the same as:
    // var token = Request.Form["token"];

    return new JsonResult(token);
}

Я предлагаю использовать корзину для дальнейшей отладки.

Согласно официальной документации, указанной в OP, вы должны отформатировать свой ответ в зависимости от типа контента, который вы возвращаете.

Возможно, вы не возвращаете значение (вызов) в одном из ожидаемых форматов.

Получив событие, ответьте открытым текстом со значением атрибута вызова. В этом примере это может быть:

HTTP 200 OK
Content-type: text/plain
3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P

Для выполнения вышесказанного вам нужно было бы по-другому вернуть ваш запрос.

[HttpPost]
public IHttpActionResult Post([FromBody]Slack_Webhook json) {
    //Please verify that the token value found in the payload 
    //matches your application's configured Slack token.
    if (ModelState.IsValid && json != null && ValidToken(json.token)) {
        var response = Request.CreateResponse(HttpStatusCode.OK, json.challenge, "text/plain");
        return ResponseMessage(response);
    }
    return BadRequest();
}

Документация также показывает

Или даже JSON:

HTTP 200 OK
Content-type: application/json
{"challenge":"3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P"}

Который снова должен был бы быть отформатирован немного по-другому

[HttpPost]
public IHttpActionResult Post([FromBody]Slack_Webhook json) {
    //Please verify that the token value found in the payload 
    //matches your application's configured Slack token.
    if (ModelState.IsValid && json != null && ValidToken(json.token)) {
        var model = new { challenge = json.challenge };
        return Ok(model);
    }
    return BadRequest();
}
Другие вопросы по тегам