I'm a bit lost in testing my custom modelbinder that parses a querystring. As the API is given and now must be migrated to .NET CORE, I am not able to change the syntax of the url query parameter. So I can not use the [FromQuery] attribute at the controllers parameter.
The controller is simple:
public class HostListController
: ControllerBase
{
[HttpGet]
public async Task<ActionResult<IList<SomeDto>>> Get(
CustomQueryExpr filter,
[FromQuery] bool pretty)
{
// do some fetch
}
}
And the custom model binder implementation is also straight forward:
public class CustomQueryBinder
: IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
var parser = new QueryParser();
//--- get queryString from request
var queryString = bindingContext.HttpContext.Request.QueryString;
//--- parse string
var queryExpr = parser.Parse(queryString.Value);
bindingContext.Result = ModelBindingResult.Success(queryExpr);
return Task.CompletedTask;
}
}
The concrete implementation of the custom QueryParser is not important, it's method 'Parse' returns a 'CustomQueryExpr' instance in any case.
Now I'm struggling in assembling the test.
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using System.Collections.Generic;
using System.Threading.Tasks;
using Xunit;
public class TestCustomQueryBinder
{
[Fact]
public async Task TestValidQuery_BindModel_ReturnCustomQueryExpr()
{
//--- assemble
var modelMetadata = new EmptyModelMetadataProvider();
var requestFake = new HttpRequestFeature();
requestFake.QueryString = "?filter_arg1=te*t&select=arg1,arg2";
var features = new FeatureCollection();
features.Set<IHttpRequestFeature>(requestFake);
var fakeHttpContext = new DefaultHttpContext(features);
var bindingContext = new DefaultModelBindingContext
{
ModelName = "CustomQueryExpr",
ModelMetadata = modelMetadata.GetMetadataForType(typeof(CustomQueryExpr)),
ActionContext = new ActionContext()
{
HttpContext = fakeHttpContext
}
};
var binder = new CustomQueryBinder();
//--- act
await binder.BindModelAsync(bindingContext);
//--- assert
Assert.NotNull(bindingContext.Result);
Assert.True(bindingContext.Result.IsModelSet);
Assert.True(bindingContext.Result.Model is CustomQueryExpr);
}
}
Works now as expected. Sometimes it helps to simply explain the problem to others to find the own mistake ... forrests and trees.
But I'm sure this solution can be improved, so please add your comments, hints and improvements to learn from.