Ich bin stecken mit Bindung eines optionalen Array in einem ASP.NET Core Controller. Das Array enthält Elemente eines benutzerdefinierten Typs. Einzelne Elemente dieses Typs werden mit einem benutzerdefinierten Modellbinder gebunden und in diesem validiert.Modelbinding ein optionales Array eines benutzerdefinierten Modells gebundenen Typ
Beispiel Repo hier: https://github.com/MarcusKohnert/OptionalArrayModelBinding
ich nur zwei Tests von drei in der Probe Testprojekt arbeiten: https://github.com/MarcusKohnert/OptionalArrayModelBinding/blob/master/OptionalArrayModelBindingTest/TestOptionalArrayCustomModelBinder.cs
public class TestOptionalArrayCustomModelBinder
{
private readonly TestServer server;
private readonly HttpClient client;
public TestOptionalArrayCustomModelBinder()
{
server = new TestServer(new WebHostBuilder().UseStartup<Startup>());
client = server.CreateClient();
}
[Fact]
public async Task SuccessWithoutProvidingIds()
{
var response = await client.GetAsync("/api/values");
Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
}
[Fact]
public async Task SuccessWithValidIds()
{
var response = await client.GetAsync("/api/values?ids=aaa001&ids=bbb002");
Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
}
[Fact]
public async Task FailureWithOneInvalidId()
{
var response = await client.GetAsync("/api/values?ids=xaaa001&ids=bbb002");
Assert.Equal(System.Net.HttpStatusCode.BadRequest, response.StatusCode);
}
}
Controller:
[Route("api/[controller]")]
public class ValuesController : Controller
{
[HttpGet]
public IActionResult Get(CustomIdentifier[] ids)
{
if (this.ModelState.IsValid == false) return this.BadRequest();
return this.Ok(ids);
}
}
Startup:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options =>
{
options.ModelBinderProviders.Insert(0, new CutomIdentifierModelBinderProvider());
//options.ModelBinderProviders.Add(new CutomIdentifierModelBinderProvider());
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc();
}
}
Modelbinder:
public class CutomIdentifierModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
//if (context.Metadata.ModelType.IsArray && context.Metadata.ModelType == typeof(CustomIdentifier[]))
//{
// return new ArrayModelBinder<CustomIdentifier>(new CustomIdentifierModelBinder());
//}
if (context.Metadata.ModelType == typeof(CustomIdentifier))
{
return new BinderTypeModelBinder(typeof(CustomIdentifierModelBinder));
}
return null;
}
}
public class CustomIdentifierModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
var attemptedValue = bindingContext.ValueProvider.GetValue(bindingContext.ModelName).ToString();
var parseResult = CustomIdentifier.TryParse(attemptedValue);
if (parseResult.Failed)
{
bindingContext.Result = ModelBindingResult.Failed();
bindingContext.ModelState.AddModelError(bindingContext.ModelName, parseResult.Message.Message);
}
else
{
bindingContext.Model = parseResult.Value;
bindingContext.Result = ModelBindingResult.Success(parseResult.Value);
}
return Task.CompletedTask;
}
}
Die Standard-MVC ArrayModelBinder von T korrekt optionale Arrays bindet und setzt ModelState.IsValid auf true. Wenn ich einen eigenen CustomIdentifierModelBinder verwende, wird ModelState.IsValid jedoch false sein. Leere Arrays werden nicht als gültig erkannt.
Wie kann ich dieses Problem lösen? Danke im Voraus.
Vielen Dank für Ihre Antwort:
Und Sie auch die mitgelieferte ArrayModelBinder von T mit Ihrem eigenen Modelbinder registrieren. Ich konnte nicht glauben, dass du immer wieder einen anderen schreiben musst ... ArrayModelBinder, also musste ich mir den Quellcode von MVC nochmal ansehen. Die in meiner Antwort erwähnte Änderung scheint das Problem in meinem Fall zu lösen. Weiß noch nicht, ob es irgendein Szenario löst. Nochmals vielen Dank, Ihre Antwort hat mich in die richtige Richtung gedrängt. – MarcusK