Reputation: 2367
In my Web Api controller I have the below action
public Data GetData(ComplexModel model)
Model is
class ComplexModel
{
int Id { get; set;}
string Name { get; set;}
string AddressLine { get; set;}
}
Can I bind Id
property from a route parameter and Name
& AddressLine
from body?
Following code doesn't work
class ComplexModel
{
[FromRoute]
int Id { get; set;}
[FromBody]
string Name { get; set;}
[FromBody]
string AddressLine { get; set;}
}
Upvotes: 0
Views: 1252
Reputation: 18159
Here is a demo:
ComplexModel:
public class ComplexModel
{
public int Id { get; set; }
public string Name { get; set; }
public string AddressLine { get; set; }
}
Controller:
[Route("api/[controller]")]
[ApiController]
public class ApiController : ControllerBase
{
[Route("/Index/{Id}")]
public IActionResult Index(ComplexModel complexModel)
{
return Ok();
}
}
CustomBinder:
public class CustomBinder:IModelBinder
{
private BodyModelBinder defaultBinder;
public CustomBinder(IList<IInputFormatter> formatters, IHttpRequestStreamReaderFactory readerFactory) // : base(formatters, readerFactory)
{
defaultBinder = new BodyModelBinder(formatters, readerFactory);
}
public async Task BindModelAsync(ModelBindingContext bindingContext)
{
// callinng the default body binder
await defaultBinder.BindModelAsync(bindingContext);
if (bindingContext.Result.IsModelSet)
{
var data = bindingContext.Result.Model as ComplexModel;
if (data != null)
{
var value = bindingContext.ValueProvider.GetValue("Id").FirstValue;
int intValue = 0;
if (int.TryParse(value, out intValue))
{
// Override the Id property
data.Id = intValue;
}
bindingContext.Result = ModelBindingResult.Success(data);
}
}
}
TestModelBinderProvider:
public class TestModelBinderProvider : IModelBinderProvider
{
private readonly IList<IInputFormatter> formatters;
private readonly IHttpRequestStreamReaderFactory readerFactory;
public TestModelBinderProvider(IList<IInputFormatter> formatters, IHttpRequestStreamReaderFactory readerFactory)
{
this.formatters = formatters;
this.readerFactory = readerFactory;
}
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context.Metadata.ModelType == typeof(ComplexModel))
return new CustomBinder(formatters, readerFactory);
return null;
}
}
}
startup.cs:
services.AddMvc()
.AddMvcOptions(options =>
{
IHttpRequestStreamReaderFactory readerFactory = services.BuildServiceProvider().GetRequiredService<IHttpRequestStreamReaderFactory>();
options.ModelBinderProviders.Insert(0, new TestModelBinderProvider(options.InputFormatters, readerFactory));
});
Upvotes: 1