停止 ASP.NET MVC 调用模型中的所有 getter class
Stop ASP.NET MVC from calling all getters in a model class
如果您在模型 class 上定义以下两个属性,这将在模型绑定期间崩溃并出现 NullReferenceException
:
public Customer Customer { get; private set; } //set in the action method
public bool Name => Customer.Name;
这是因为 Customer
在模型绑定期间仍然为空,并且 ASP.NET MVC 为 Name
调用 getter。
堆栈是:
System.ComponentModel.ReflectPropertyDescriptor.GetValue(Object component) +525
System.Web.Mvc.ModelMetadata.get_Model() +34
System.Web.Mvc.DataAnnotationsModelValidator.Validate(Object container) +151
System.Web.Mvc.<Validate>d__1.MoveNext() +387
System.Web.Mvc.DefaultModelBinder.OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext) +163
System.Web.Mvc.DefaultModelBinder.BindComplexElementalModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Object model) +83
System.Web.Mvc.DefaultModelBinder.BindComplexModel(ControllerContext controllerContext, ModelBindingContext bindingContext) +1754
System.Web.Mvc.ControllerActionInvoker.GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor) +460
System.Web.Mvc.ControllerActionInvoker.GetParameterValues(ControllerContext controllerContext, ActionDescriptor actionDescriptor) +137
System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +982
System.Web.Mvc.<>c__DisplayClass22.<BeginExecuteCore>b__1e() +39
System.Web.Mvc.Async.AsyncResultWrapper.<.cctor>b__0(IAsyncResult asyncResult, Action action) +21
System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +53
System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +36
System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) +38
System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__5(IAsyncResult asyncResult, ProcessRequestState innerState) +44
System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +65
System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +38
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +399
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +137
从堆栈来看,模型验证似乎正在查询 all getters。我没有使用模型验证。
我该如何处理这种情况?我可以让 ASP.NET MVC 在没有任何(明显的)原因的情况下不调用所有 getter 吗?
因此,Model Binder 新建了您的模型的一个实例,然后可能正在对模型的属性进行反射,以查找与 FormCollection 中的值匹配的命名。发生的事情是,当调用危险的 Name 道具时, Customer 道具为空,因此为 NullRef。
.NET 检查这些属性的顺序实际上可能不是随机的,但您的代码将通过这样处理而得到很大改进。直接在默认情况下可为空的 Class 上调用 method/prop 是一个糟糕的主意,除非您检查它是否为空。您在这里有两个选择,或者 (1) 重新设计您的模型 class 以便构造函数初始化 "Customer" 属性,或者 (b) 在 "Name" 中添加空检查] 方法。
这是最简单的方法,可以在抓取它时对其进行 null 检查:
public bool Name => Customer?.Name ?? false;
这并没有解决根本问题,即您的模型将可空属性链接在一起。不要担心模型的构造函数会弄乱模型绑定。 Model Binder 将 (1) 初始化您的模型 class,然后 (2) 尝试对其进行水合。因此,在模型的构造函数中初始化 Customer class/prop 不会影响 UI 字段的任何映射以表示 Customer 的字段。
MVC version 5.2.3中的DefaultModelBinder
除了binding之外还有validation,没有办法完全关闭。其他 SO 帖子提到在 Global.asax.cs、Application_Start()
方法中使用以下代码行关闭值类型的隐式必需属性...
DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
请参阅:(引用了直接来自 asp.net 团队的答案的论坛)。
鉴于您的堆栈跟踪,这可能会解决您眼前的问题。但是,这可能还不够,因为 DefaultModelBinder
甚至在其验证代码之外调用 getter 时没有说明原因(源代码没有说明为什么这样做)。
为了解决我的项目中的问题,我一直使用类似于您的示例的计算属性,我实现了一个基于原始 DefaultModelBinder
源代码的自定义模型联编程序,该联编程序不调用任何 getter。
在此处查看更详细的解释和我的完整解决方案:。
如果您在模型 class 上定义以下两个属性,这将在模型绑定期间崩溃并出现 NullReferenceException
:
public Customer Customer { get; private set; } //set in the action method
public bool Name => Customer.Name;
这是因为 Customer
在模型绑定期间仍然为空,并且 ASP.NET MVC 为 Name
调用 getter。
堆栈是:
System.ComponentModel.ReflectPropertyDescriptor.GetValue(Object component) +525
System.Web.Mvc.ModelMetadata.get_Model() +34
System.Web.Mvc.DataAnnotationsModelValidator.Validate(Object container) +151
System.Web.Mvc.<Validate>d__1.MoveNext() +387
System.Web.Mvc.DefaultModelBinder.OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext) +163
System.Web.Mvc.DefaultModelBinder.BindComplexElementalModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Object model) +83
System.Web.Mvc.DefaultModelBinder.BindComplexModel(ControllerContext controllerContext, ModelBindingContext bindingContext) +1754
System.Web.Mvc.ControllerActionInvoker.GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor) +460
System.Web.Mvc.ControllerActionInvoker.GetParameterValues(ControllerContext controllerContext, ActionDescriptor actionDescriptor) +137
System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +982
System.Web.Mvc.<>c__DisplayClass22.<BeginExecuteCore>b__1e() +39
System.Web.Mvc.Async.AsyncResultWrapper.<.cctor>b__0(IAsyncResult asyncResult, Action action) +21
System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +53
System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +36
System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) +38
System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__5(IAsyncResult asyncResult, ProcessRequestState innerState) +44
System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +65
System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +38
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +399
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +137
从堆栈来看,模型验证似乎正在查询 all getters。我没有使用模型验证。
我该如何处理这种情况?我可以让 ASP.NET MVC 在没有任何(明显的)原因的情况下不调用所有 getter 吗?
因此,Model Binder 新建了您的模型的一个实例,然后可能正在对模型的属性进行反射,以查找与 FormCollection 中的值匹配的命名。发生的事情是,当调用危险的 Name 道具时, Customer 道具为空,因此为 NullRef。
.NET 检查这些属性的顺序实际上可能不是随机的,但您的代码将通过这样处理而得到很大改进。直接在默认情况下可为空的 Class 上调用 method/prop 是一个糟糕的主意,除非您检查它是否为空。您在这里有两个选择,或者 (1) 重新设计您的模型 class 以便构造函数初始化 "Customer" 属性,或者 (b) 在 "Name" 中添加空检查] 方法。
这是最简单的方法,可以在抓取它时对其进行 null 检查:
public bool Name => Customer?.Name ?? false;
这并没有解决根本问题,即您的模型将可空属性链接在一起。不要担心模型的构造函数会弄乱模型绑定。 Model Binder 将 (1) 初始化您的模型 class,然后 (2) 尝试对其进行水合。因此,在模型的构造函数中初始化 Customer class/prop 不会影响 UI 字段的任何映射以表示 Customer 的字段。
MVC version 5.2.3中的DefaultModelBinder
除了binding之外还有validation,没有办法完全关闭。其他 SO 帖子提到在 Global.asax.cs、Application_Start()
方法中使用以下代码行关闭值类型的隐式必需属性...
DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
请参阅:(引用了直接来自 asp.net 团队的答案的论坛)。
鉴于您的堆栈跟踪,这可能会解决您眼前的问题。但是,这可能还不够,因为 DefaultModelBinder
甚至在其验证代码之外调用 getter 时没有说明原因(源代码没有说明为什么这样做)。
为了解决我的项目中的问题,我一直使用类似于您的示例的计算属性,我实现了一个基于原始 DefaultModelBinder
源代码的自定义模型联编程序,该联编程序不调用任何 getter。
在此处查看更详细的解释和我的完整解决方案: