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();
}