billbogaiv / hybrid-model-binding

Provides the ability to bind models using both ModelBinder and ValueProvider in ASP.NET Core.
MIT License
104 stars 19 forks source link

An exception when dictionary binding occurs #53

Open AlexanderLapshin opened 3 years ago

AlexanderLapshin commented 3 years ago

The package throws an exception when model has a property of type Dictionary<string, string>.

I have registered HybridModelBinding in startup:

services.AddMvcCore()
    .AddHybridModelBinder()
    .AddApiExplorer();

I have a controller that has one parameter with model

public async Task<IndexModelResponse> CreateIndex(IndexModelRequest command) =>
     await Mediator.Send(command);

I have a model with one property of type Dictionary<string, string>:

public class IndexModel
{
    public IDictionary<string, string> Name { get; set; }
}

If I make a request to this endpoint I have an exception:

System.ArgumentException: The value "[en, Automatic]" is not of type "System.String" and cannot be used in this generic collection. (Parameter 'value') at System.Collections.Generic.List`1.System.Collections.IList.Add(Object item) at HybridModelBinding.HybridModelBinder.BindModelAsync(ModelBindingContext bindingContext) at Microsoft.AspNetCore.Mvc.ModelBinding.ParameterBinder.BindModelAsync(ActionContext actionContext, IModelBinder modelBinder, IValueProvider valueProvider, ParameterDescriptor parameter, ModelMetadata metadata, Object value) at Microsoft.AspNetCore.Mvc.Controllers.ControllerBinderDelegateProvider.<>cDisplayClass0_0.<gBind|0>d.MoveNext() --- End of stack trace from previous location where exception was thrown --- at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.gAwaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.gAwaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope) at Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

Request body:

{
    "Name": {
        "en": "Automatic"
    }
}

And additional question: Can I manually set by attribute when I want to HybridModelBinding, but not automatically when controller has a one parameter?

ASP.NET Core 3.1; SDK 3.1.405 Package version: 0.18.1 -alpha.4

I had tried to downgrade the package version to 0.18.0 and my output change to:

Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1] An unhandled exception has occurred while executing the request. System.ArgumentException: The value "[en, Automatic]" is not of type "System.String" and cannot be used in this generic collection. (Parameter 'value') at System.Collections.Generic.List`1.System.Collections.IList.Add(Object item) at HybridModelBinding.HybridModelBinder.BindModelAsync(ModelBindingContext bindingContext) at Microsoft.AspNetCore.Mvc.ModelBinding.ParameterBinder.BindModelAsync(ActionContext actionContext, IModelBinder modelBinder, IValueProvider valueProvider, ParameterDescriptor parameter, ModelMetadata metadata, Object value) at Microsoft.AspNetCore.Mvc.Controllers.ControllerBinderDelegateProvider.<>cDisplayClass0_0.<gBind|0>d.MoveNext() --- End of stack trace from previous location where exception was thrown --- at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.gAwaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.gAwaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope) at Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)