Teams Bot库的JSON
如果你和我一样,一直使用最新的 asp.net core 来开发teams bot的应用,那么你就会发现当你使用最新的 LTS 3.1版本或者 5.0 版本或者最新的 6.0 版本,asp.net core 默认使用System.Text.Json库,所以当你在处理 Teams 发送来的请求的时候,如果还是使用类似于下面的代码,那很多时候就是发现activity解析不出来,返回的response也不对。
[HttpPost("api/messages")]
public Activity GetMessage([FromBody]Activity activity)
{
....
return new Activity()
{
....
};
}
为什么呢?从 Microsoft.Bot.Schema 的源代码里的 Activity 定义 里可以发现原因:
using System.Collections.Generic;
using Newtonsoft.Json;
namespace Microsoft.Bot.Schema
{
public partial class Activity
{
[JsonProperty(PropertyName = "type")]
public string Type { get; set; }
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "timestamp")]
public System.DateTimeOffset? Timestamp { get; set; }
[JsonProperty(PropertyName = "localTimestamp")]
public System.DateTimeOffset? LocalTimestamp { get; set; }
[JsonProperty(PropertyName = "localTimezone")]
public string LocalTimezone { get; set; }
[JsonProperty(PropertyName = "serviceUrl")]
public string ServiceUrl { get; set; }
[JsonProperty(PropertyName = "channelId")]
public string ChannelId { get; set; }
[JsonProperty(PropertyName = "from")]
public ChannelAccount From { get; set; }
...
}
}
从上面的代码可以看到,Activity 使用了 Newtonsoft.JSON 的 JsonProperty attribute 来说明如何 serialize 和 deserialize。既然是 Newtonsoft.JSON 的 attribute,那肯定对 System.Text.Json 不起作用了,就是说默认的 asp.net core 的 json 不会去读取 JsonProperty attribute。除了 JsonProperty,Microsoft.Bot.Schema和其他bot的库也使用了很多其他 Newtonsoft.JSON 的东西。
现在相信大家知道了原因,那如何解决?有这么几种方法:
- 改变默认的 json,使用 Newtonsoft.JSON
先给项目安装一个库
Install-Package Microsoft.AspNetCore.Mvc.NewtonsoftJson
然后在Startup文件中:
services.AddMvc().AddNewtonsoftJson();
或者
services.AddControllers().AddNewtonsoftJson(); services.AddControllersWithViews().AddNewtonsoftJson(); services.AddRazorPages().AddNewtonsoftJson();
- 手动的使用 Newtonsoft.JSON 来做序列化和反序列化
[HttpPost]
[Route("api/extension")]
public async Task<IActionResult> Post()
{
using var reader = new StreamReader(Request.Body);
var activity = JsonConvert.DeserializeObject<Activity>(await reader.ReadToEndAsync());
...
var responseJson = JsonConvert.SerializeObject(responseActivity);
return Content(responseJson, "application/json");
}
- 自己定义一些需要用到的结构 (只适用于简单的应用,比如:outgoing webhook)
public record Activity
{
[JsonPropertyName("text")]
public string Text { get; init; }
}
上面的 JsonPropertyName 是 System.Text.Json 里的一种 attribute。
不过,最终的解决方案,肯定是微软官方的这些 Bot,Teams 的library可以支持最新的 System.Text.Json,希望这天可以快点到来。
Written on October 10, 2021