Reputation: 73
I'm having a problem trying to get custom model binders to work as a query parameter like I have gotten to work previously in .net framework 4.7.
To ensure this wasn't a scenario where my object was too complex, I reduced the model to a simple string but even then I cannot get this to work.
I have a simple model I would like to be binded from query parameters.
public class SearchModel {
public string SearchTerms { get; set; }
}
And I have configured the ModelBinder and ModelBinderProvider as shown here like so.
public class TestModelBinder : IModelBinder {
public Task BindModelAsync(ModelBindingContext bindingContext) {
if (bindingContext.ModelType != typeof(SearchModel)) {
throw new ArgumentException($"Invalid binding context supplied {bindingContext.ModelType}");
}
var model = (SearchModel)bindingContext.Model ?? new SearchModel();
var properties = model.GetType().GetProperties();
foreach(var p in properties) {
var value = this.GetValue(bindingContext, p.Name);
p.SetValue(model, Convert.ChangeType(value, p.PropertyType), null);
}
return Task.CompletedTask;
}
protected string GetValue(ModelBindingContext context, string key) {
var result = context.ValueProvider.GetValue(key);
return result.FirstValue;
}
}
public class TestModelBinderProvider : IModelBinderProvider {
public IModelBinder GetBinder(ModelBinderProviderContext context) {
if (context == null) {
throw new ArgumentNullException(nameof(context));
}
if (context.Metadata.ModelType == typeof(SearchModel)) {
var returnType = new BinderTypeModelBinder(typeof(TestModelBinder));
return returnType;
}
return null;
}
}
As stated in the last step in Microsoft documentation I updated my ConfigureServices method in Startup.cs to include the BinderProvider.
services.AddMvc(options => {
options.ModelBinderProviders.Insert(0, new TestModelBinderProvider());
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
But when I call my Search endpoint with a url such as "https://localhost:44387/api/testbinding?searchTerms=newSearch" I am always seeing a return of "request == null True" even though I see it properly hit the custom binding and bind correctly if I step through debugging, can anyone please point me in the right direction as to what I am doing wrong?
[Route("api/[controller]")]
[ApiController]
public class TestBindingController : ControllerBase {
[HttpGet()]
public IActionResult GetResult([FromQuery] SearchModel request) {
return Ok($"request == null {request == null}");
}
}
Upvotes: 1
Views: 2768
Reputation: 13734
I think what you're missing if the statement that sets the result of the model binding operation, as you can see in the AuthorEntityBinder
code sample in this section of the docs:
bindingContext.Result = ModelBindingResult.Success(model);
Your implementation of the model binder does create an instance of SearchModel
, but doesn't feed it back to the model binding context.
As a separate note, I don't think you need to add a custom model binder is the query string segments match the properties names of the model you're trying to bind.
Upvotes: 3