我必须创建将使用JSON消息的webhook端点 消息以x-www-form-urlencoded格式发送:
key = json
value = {“user_Id”:“728409840”,“call_id”:“1114330”,“answers_time”:“2015-04-16 15:37:47”}
如PostMan所示:
请求如下:
JSON =%7B%22user_Id%22%3A +%22728409840%22%2C +%22call_id%22%3A +%221114330%22%2C%22answered_time%22%3A +%222015-04-16 + 15%3A37%3A47% 22%7D
要从请求中获取值作为我的类(模型),我必须创建包含单个字符串属性的临时对象:
public class Tmp
{
public string json { get; set; }
}
和我的控制器中使用该请求的方法:
[AllowAnonymous]
[Route("save_data")]
[HttpPost]
public IHttpActionResult SaveData(Tmp tmp)
{
JObject json2 = JObject.Parse(tmp.json);
var details = json2.ToObject<CallDetails>();
Debug.WriteLine(details);
//data processing
return Content(HttpStatusCode.OK, "OK", new TextMediaTypeFormatter(), "text/plain");
}
正如你所看到的,Tmp课程毫无用处。
有没有办法将请求数据作为此类获取:
public class CallDetails
{
public string UserId { get; set; }
public string CallId { get; set; }
public string AnsweredTime { get; set; }
}
我知道IModelBinder
课程,但在开始之前,我想知道是否有更简单的方法。
我不能改变网页请求格式,格式我的意思是它总是包含单个键的POST - JSON
你有json字符串作为值。
答案 0 :(得分:2)
您可以使用JsonProperty
属性将json对象属性映射到c#对象属性:
public class CallDetails
{
[JsonProperty("user_id")]
public string UserId { get; set; }
[JsonProperty("call_id")]
public string CallId { get; set; }
[JsonProperty("answered_time")]
public string AnsweredTime { get; set; }
}
然后它可以在没有临时类的情况下使用:
[AllowAnonymous]
[Route("save_data")]
[HttpPost]
public IHttpActionResult SaveData(CallDetails callDetails)
更新。因为数据是以x-www-form-urlencoded的形式发送的 - 我认为你处理它的方式最简单,也不是那么糟糕。如果您想在此处查看其他选项,请参阅其中一些选项:
选项1 - 自定义模型绑定器。像这样:
public class CustomModelBinder : IModelBinder
{
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
{
var body = actionContext.Request.Content.ReadAsStringAsync().Result;
body = body.Replace("json=", "");
var json = HttpUtility.UrlDecode(body);
bindingContext.Model = JsonConvert.DeserializeObject<CallDetails>(json);
return true;
}
}
用法:SaveData([ModelBinder(typeof(CustomModelBinder))]CallDetails callDetails)
。缺点 - 您将失去验证,也可能会失去web api管道中定义的其他内容。
选项2 - DelegatingHandler
public class NormalizeHandler : DelegatingHandler
{
public NormalizeHandler(HttpConfiguration httpConfiguration)
{
InnerHandler = new HttpControllerDispatcher(httpConfiguration);
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var source = await request.Content.ReadAsStringAsync();
source = source.Replace("json=", "");
source = HttpUtility.UrlDecode(source);
request.Content = new StringContent(source, Encoding.UTF8, "application/json");
return await base.SendAsync(request, cancellationToken);
}
}
用法:
[AllowAnonymous]
[HttpPost]
public IHttpActionResult SaveData(CallDetails callDetails)
缺点 - 你需要为它定义自定义路线:
config.Routes.MapHttpRoute(
name: "save_data",
routeTemplate: "save_data",
defaults: new { controller = "YourController", action = "SaveData" },
constraints: null,
handler: new NormalizeHandler(config)
);
答案 1 :(得分:0)
NewtonSoft的Json.NET可以帮助你deserialize an object。如果您的json属性名称与您的实际类名不匹配,您可以编写自定义转换器来帮助。
修改强>
如果您使用的是MVC6,可以试试这个。将您的参数从Tmp
类型更改为CallDetails
类型,并使用属性[FromBody]
进行标记,如下所示:
public IHttpActionResult SaveData([FromBody]CallDetails details)
例如,请参阅&#34;不同的模型绑定&#34;在this post。但是,我仍然认为您需要手动反序列化,因为类CallDetails
的属性名称与传入的JSON属性完全匹配。
答案 2 :(得分:0)
你不要忘记在使用JObject.Parse之前解码编码的url吗?它可能有效。并且对象的属性与json atributes
不匹配