ASP.NET 5 MVC 6 RC1 API 中的自定义模型绑定异常

Posted

技术标签:

【中文标题】ASP.NET 5 MVC 6 RC1 API 中的自定义模型绑定异常【英文标题】:Exception with custom model binding in ASP.NET 5 MVC 6 RC1 API 【发布时间】:2016-03-15 19:22:36 【问题描述】:

当尝试在 ASP.NET 5 RC1 中使用自定义模型绑定器进行解析时,我在调用操作时在 Microsoft.AspNet.Mvc.ModelBinding.CompositeModelBinder 中抛出了 NullReferenceException

Startup 中的模型绑定:

public void ConfigureServices(IServiceCollection services)

    services.AddMvc(options =>
    
        options.ModelBinders.Insert(0, new MyCustomModelBinder());

自定义模型绑定器:

public class MyCustomModelBinder : IModelBinder

    public Task<ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext)
    
        if (bindingContext.ModelType == typeof(MyCustomClass) && bindingContext.ValueProvider.GetValue(bindingContext.ModelName) != null)
        
            MyCustomClass model;
            var val = bindingContext.ValueProvider.GetValue(bindingContext.ModelName).FirstValue as string;

            if (MyCustomClass.TryParse(val, out model))
            
                return Task.FromResult(ModelBindingResult.Success(bindingContext.ModelName, model));
            
        

        return null;
    

控制器动作:

[HttpGet]
public IActionResult GetSomething([ModelBinder(BinderType = typeof(MyCustomModelBinder))]MyCustomClass key)

    return Json("Success!");

例外:

System.NullReferenceException:对象引用未设置为实例 的一个对象。在 Microsoft.AspNet.Mvc.ModelBinding.CompositeModelBinder.d__5.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 Microsoft.AspNet.Mvc.Controllers.DefaultControllerActionArgumentBinder.d__6.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 Microsoft.AspNet.Mvc.Controllers.DefaultControllerActionArgumentBinder.d__9.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 Microsoft.AspNet.Mvc.Controllers.DefaultControllerActionArgumentBinder.d__5.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 Microsoft.AspNet.Mvc.Controllers.FilterActionInvoker.d__52.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 Microsoft.AspNet.Mvc.Controllers.FilterActionInvoker.d__51.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 Microsoft.AspNet.Mvc.Controllers.FilterActionInvoker.d__44.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 Microsoft.AspNet.Mvc.Infrastructure.MvcRouteHandler.d__6.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 Microsoft.AspNet.Mvc.Routing.InnerAttributeRoute.d__10.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 Microsoft.AspNet.Routing.RouteCollection.d__9.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 Microsoft.AspNet.Builder.RouterMiddleware.d__4.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 Microsoft.AspNet.Hosting.Internal.RequestServicesContainerMiddleware.d__3.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 Microsoft.AspNet.Hosting.Internal.HostingEngine.c__DisplayClass32_0.d.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)在 Microsoft.AspNet.Server.Kestrel.Http.Frame.d__79.MoveNext()

【问题讨论】:

【参考方案1】:

请在BindModelAsync 方法调用中将return null 更改为return Task.FromResult(ModelBindingResult.NoResult);

在 CompositeModelBinder.cs 的第 64 行 var result = await binder.BindModelAsync(bindingContext); 中,当框架等待为空的 Task 时发生错误

【讨论】:

这解决了问题。它具有误导性,因为 IModelBinder.BindModelAsync 具有以下注释:“返回 null 值表示此模型绑定器无法处理请求。返回 null 可确保运行后续模型绑定器。如果非 null 值表示模型绑定器能够处理请求。” @davenewza 我认为“A null 返回值”是任务的展开值 我认为 beta7 中的情况并非如此。如果我没记错的话,返回 null 是可行的。

以上是关于ASP.NET 5 MVC 6 RC1 API 中的自定义模型绑定异常的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 ASP.NET 5 MVC 6 保护 Web API

在 Entity Framework 7 RC 1 和 ASP.NET MVC 6 中播种初始数据 [重复]

如何在 ASP.NET MVC 5、Entity Framework 6 中使用流利的 API 映射表?

使用 ASP.NET 5 MVC 6 Web API 进行 Cookie 身份验证

ASP.NET 5 MVC 6 CORS vue.js 请求不允许

ASP.NET 5 RC1:System.IO.InvalidDataException:请求内容意外结束