我想知道是否有其他人遇到过这种情况,当发布JSON时,FromBody属性会忽略包含超量的JsonProperty PropertyNames。
我已经在下面的代码中评论了输出,以演示发布的内容,我可以使用Request.InputStream快乐地反序列化HttpPost,但希望使用FromBody属性有一个更简单更有效的方法。
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]处理连字符,但使用ModelBinder方法,类似于https://stackoverflow.com/questions/23995210/how-to-use-json-net-for-json-modelbinding-in-an-mvc5-project
上提供的方法提供了一种解决方法,请参阅下面的代码来演示:
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)
{
}
答案 0 :(得分:1)
您正在使用var requestInputStream = Request.InputStream;
,这意味着该方法位于Controller类中。在ApiController类中,这会产生编译错误。
似乎MVC和API混在了一起。 FromBody应该在ApiController中使用(使用System.Web。 Http )。但该方法有一个System.Web。 Mvc .HttpPost属性(位于控制器内)。
[System.Web.Mvc.HttpPost]
public ActionResult Test([FromBody] Api.Test test)
在这种情况下无关紧要,因为没有其他参数可以省略FromBody。默认情况下,请求在'test'参数中反序列化。
所以问题不在于FromBody。
问题是:该方法应该返回什么?它应该重定向到home还是应该用StatusCode(HttpStatusCode.Created)响应?
如果您想重定向,请考虑POST一个表单而不是 Json 。这不能解决连字符问题,但这更符合逻辑。您可以添加AntiForgery令牌。
另一种选择是使用不带连字符的DTO或从InputStream反序列化Json,就像在更新代码中一样。
所以你可以使用控制器类进行这样的调用,但除非你自己动手处理json,否则无法解决问题。
通过将方法移动到ApiControler类,您可以非常轻松地解决连字符问题。 这足以解决连字符问题。
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;
}
}