问题
I want to bind an interface model from my action method with a request that the content-type is application/json. I'm using the [FromBody] attribute in my action method.
I tried to create a custom modelBinder derived from ComplexTypeModelBinder, by following this link: Custom Model Binding in Asp.net Core, 3: Model Binding Interfaces, but it doesn't work, my model is always null. I learned after that when you use the atribute [FromBody] the BodyModelBinder is called and internally is calling JsonInputFormatter and it doesn't use the custom modelBinder.
I'm looking for a way to bind my interface model. I can use the MVC DI to map each interface with its implementation. My action method is defined as :
public async Task<IActionResult> Create(IOperator user)
{
if (user == null)
{
return this.BadRequest("The user can't not be null");
}
if (!this.ModelState.IsValid)
{
return this.BadRequest(this.ModelState);
}
IOperator op = await this.AuthenticationFrontService.CreateOperatorAsync(user.Login, user.Password, user.FirstName, user.LastName, user.ValidUntil, user.Role, user.Comment);
return new CreatedAtActionResult("Get", "operators", new { id = ((Operator)op).Id }, op);
}
I tried another solution by using the MetadataType attribute in my interface but it doesn't exist in the namespace System.ComponentModel.DataAnnotations and i read that asp.net core mvc doesn't use this attribute Asp.Net MVC MetaDataType Attribute not working. I don't want to install the package microsoft.aspnetcore.mvc.dataannotations in domain model project to use the ModelDataType attribute.
I tried another solution by creating a custom JsonInputFormater in other words i derived the class JsonInputFormatter and by analyzing the source code, i've found that the JsonSerializer couldn't deserialize an interface which is logical. So i'm looking for a solution where i could custom the jsonserializer maybe by using a resolver or a generic converter.
Any help will greatly appreciated.
Thanks.
回答1:
Using an interface is fine for a C# method, but MVC needs to know what concrete type it should instantiate when calling an Action since it's creating it. It doesn't know what type to use, so it can't bind input from Form/QueryString/etc to. Create a very basic model for use in your action that does nothing but implement your interface IOperator
, if your goal was to keep it slim, and set that to your Action parameter and it should work fine.
I have tried using an interface on a action as well, and through my own searching, I found no way to get it to work, other than just using classes instead of interfaces to bind to.
public class Operator : IOperator
{
//Implement interface
}
.
public async Task<IActionResult> Create(Operator user)
{
if (user == null)
{
return this.BadRequest("The user can't not be null");
}
if (!this.ModelState.IsValid)
{
return this.BadRequest(this.ModelState);
}
IOperator op = await this.AuthenticationFrontService.CreateOperatorAsync(user.Login, user.Password, user.FirstName, user.LastName, user.ValidUntil, user.Role, user.Comment);
return new CreatedAtActionResult("Get", "operators", new { id = ((Operator)op).Id }, op);
}
回答2:
This link Asp.net core: Deserializing Json with Dependency Injection gives a solution.
来源:https://stackoverflow.com/questions/45331903/asp-net-core-mvc-model-binding-bind-an-interface-model-using-the-attribute