c# [FromBody] ignores JsonProperty on HttpPost
我想知道是否还有其他人遇到过这种情况,即在发布JSON时,FromBody属性会忽略包含连字符的JsonProperty PropertyNames。
我已经在下面的代码中注释了输出以演示所发布的内容,我可以使用Request.InputStream来愉快地反序列化HttpPost,但希望有一种使用FromBody Attribute的更简单有效的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | public class Test { [JsonProperty("id")] public int Id { get; set; } [JsonProperty("forename")] public string Forename { get; set; } [JsonProperty("address")] public Address Address { get; set; } [JsonProperty("records-submissions")] public IList<RecordsSubmission> RecordsSubmissions { get; set; } [JsonProperty("anotherrecordssubmissions")] public IList<RecordsSubmission> AnotherRecordsSubmissions { get; set; } } public class Address { [JsonProperty("value")] public string Value { get; set; } } public class RecordsSubmission { [JsonProperty("record-id")] public int RecordId { get; set; } [JsonProperty("timestamp")] public long Timestamp { get; set; } } using (var webClient = new WebClient()) { var address = new Api.Address {Value ="Somewhere"}; var recordSubmission = new Api.RecordsSubmission { RecordId = 2, Timestamp = 1497541704606 }; var recordsSubmissions = new List<Api.RecordsSubmission> {recordSubmission}; var anotherRecordsSubmissions = new List<Api.RecordsSubmission> {recordSubmission}; var test = new Api.Test { Id = 1, Forename ="Joe", Address = address, RecordsSubmissions = recordsSubmissions, AnotherRecordsSubmissions = anotherRecordsSubmissions }; var testSerializeObject = JsonConvert.SerializeObject(test); // testSerializeObject Output // {"id":1,"forename":"Joe","address":{"value":"Somewhere","versions":null},"records-submissions":[{"record-id":2,"timestamp":1497541704606}],"anotherrecordssubmissions":[{"record-id":2,"timestamp":1497541704606}]} var testDeserializeObject = JsonConvert.DeserializeObject<Api.Test>(testSerializeObject); // Correct deserialization occurred, class Test is fully populated var serializeObject = JsonConvert.SerializeObject(testDeserializeObject); // serializeObject Output // {"id":1,"forename":"Joe","address":{"value":"Somewhere","versions":null},"records-submissions":[{"record-id":2,"timestamp":1497541704606}],"anotherrecordssubmissions":[{"record-id":2,"timestamp":1497541704606}]} webClient.Headers.Add(HttpRequestHeader.ContentType,"application/json"); webClient.Encoding = Encoding.UTF8; webClient.UploadString(new Uri("https://localhost:44380/api-test"),"POST", serializeObject); } [System.Web.Mvc.HttpPost] public ActionResult Test([FromBody] Api.Test test) { // The class test is only partially populated, // [FromBody] ignores JsonProperty PropertyNames with hypens // RecordsSubmission with the JsonProperty of"records-submissions" was isgnored and test.RecordsSubmission was null, where as AnotherRecordsSubmissions was fully populated try { var requestInputStream = Request.InputStream; requestInputStream.Seek(0, SeekOrigin.Begin); var json = new StreamReader(requestInputStream).ReadToEnd(); var testDeserializeObject = JsonConvert.DeserializeObject<Api.Test>(json); // Correct deserialization occurred } catch (Exception) { // Do something } return Redirect("/"); } |
更新资料
仍然没有进一步使用[FromBody]来处理连字符,但是使用类似于
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public class JsonNetModelBinder : IModelBinder { public object BindModel(ControllerContext controllerContext, ModelBindingContext modelBindingContext) { controllerContext.HttpContext.Request.InputStream.Position = 0; var inputStream = controllerContext.RequestContext.HttpContext.Request.InputStream; var streamReader = new StreamReader(inputStream, Encoding.UTF8); var json = streamReader.ReadToEnd(); return JsonConvert.DeserializeObject(json, modelBindingContext.ModelType); } } [System.Web.Mvc.HttpPost] public ActionResult Test([ModelBinder(typeof(JsonNetModelBinder))] Api.Test test) { } |
您正在使用
看来MVC和API混在一起了。 FromBody应该在ApiController内部使用(使用System.Web.Http)。但是该方法具有System.Web.Mvc.HttpPost属性(位于控制器内部)。
1 2 | [System.Web.Mvc.HttpPost] public ActionResult Test([FromBody] Api.Test test) |
在这种情况下,因为没有其他参数,因此可以忽略FromBody无关紧要。默认情况下,该请求在'test'参数中反序列化。
因此,问题不在于FromBody。
问题是:该方法应该返回什么?它应该重定向到家庭还是应返回StatusCode(HttpStatusCode.Created)?
如果要重定向,请考虑以POST形式而不是Json形式。这不能解决连字符问题,但这更合乎逻辑。您可以添加一个AntiForgery令牌。
另一个选择是使用DTO而不使用连字符或从InputStream反序列化Json,就像在更新代码中一样。
因此,您可以使用controller类进行此类调用,但是除非您自己进行一些处理json的操作,否则无法解决连字符的问题。
通过将方法移至ApiControler类,可以非常轻松地解决连字符问题。这足以解决连字符问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public class SomeApiController : ApiController { [HttpPost] public IHttpActionResult Test(Api.Test test) { var res = test.RecordsSubmissions; return StatusCode(HttpStatusCode.Created); } // Is equivalent of Test: [HttpPost] public void Test2(Api.Test test) { var res = test.RecordsSubmissions; } } |