问题
I just realized that the mapping between the JSON send from a query and my API is not strict.
I give you more explanations:
Here is my C# POCO
public partial class AddressDto
{
public string AddrId { get; set; }
public string Addr1 { get; set; }
public string Addr2 { get; set; }
public string PostalCode { get; set; }
public string City { get; set; }
public string Country { get; set; }
}
And the REST JSON query
PUT http://Localhost:55328/api/ClientAddr/ADD-2059-S002 HTTP/1.1
content-type: application/json
{
"AddrID": "ADD-2059-S002",
"addr1": "B-1/327",
"addr2": "1ST FLOOR",
"city": "Paris",
"Zip_Code": "78956",
"country": "France",
}
The web client send a PUT with Zip_Code in place of PostalCode. PostalCode is not madatory/required. But Zip_Code does not exist in my DTO.
So in my C# code testing the model state won't help.
public HttpResponseMessage Put(string id, AddressDto address)
{
if (!ModelState.IsValid)
return BadRequest(ModelState); // This wont help
}
How can I raise exception when the client is using something in the JSON that is not existing in my DTO (model) ?
回答1:
if you need to identify extra columns and handle that as an error you have to extend IModelBinder interface and tell json deserializer to treat extra column as an error and add that error to ModelState. By that way you can check in controller for ModelState.IsValid. Checkout the below Code
CustomModelBinder
public class CustomModelBinder : IModelBinder
{
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
{
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.MissingMemberHandling = MissingMemberHandling.Error;
ObjToPass obj = new ObjToPass();
;
try
{
ObjToPass s =
JsonConvert.DeserializeObject<ObjToPass>(actionContext.Request.Content.ReadAsStringAsync().Result,
settings);
bindingContext.Model = obj;
}
catch (Exception ex)
{
bindingContext.ModelState.AddModelError("extraColumn", ex.Message);
}
return true;
}
}
public class CustomerOrderModelBinderProvider : ModelBinderProvider
{
public override IModelBinder GetBinder(System.Web.Http.HttpConfiguration configuration, Type modelType)
{
return new CustomModelBinder();
}
}
Object Class that is passed to webapi
public class ObjToPass
{
public int Id { get; set; }
public string Name { get; set; }
}
Controller
[HttpPost]
public void PostValues([ModelBinder(typeof(CustomerOrderModelBinderProvider))] ObjToPass obj)
{
if(!ModelState.IsValid)
{ }
else
{
}
}
This sample holds good for HttpPut as well.
回答2:
"Over-Posting": A client can also send more data than you expected. For example:
Here, the JSON includes a property ("Zip_Code") that does not exist in the Address model. In this case, the JSON formatter simply ignores this value. (The XML formatter does the same.)
https://docs.microsoft.com/en-us/aspnet/web-api/overview/formats-and-model-binding/model-validation-in-aspnet-web-api
来源:https://stackoverflow.com/questions/42709122/strict-mapping-in-web-web-api-over-posting