BVe*_*non 2 asp.net-mvc modelbinders
在我的模型中具有以下方法:
public bool ShowShipping() { return Modalities.Scheduled.Has(Item.Modality); }
Run Code Online (Sandbox Code Playgroud)
但是以前是这样的属性:
public bool ShowShipping { get { return Modalities.Scheduled.Has(Item.Modality); } }
Run Code Online (Sandbox Code Playgroud)
访问页面后,整个模型将填充包含Item属性的数据。项包含需要在视图上显示的数据,但没有需要回发的数据。因此,在回发时(是的,post操作将模型作为参数),Item属性保留为空。
这应该不成问题,因为视图中只有一行代码可以访问ShowShipping。因此,我期望除非填充Item,否则它将永远不会被访问。但是在回发时,我遇到了一个错误,该错误发生在击中我的发布操作的第一行之前,并且在ShowShipping中显示空引用错误。因此,我必须假设错误是在将表单数据序列化为模型的新实例时发生的……但是,当整个解决方案中唯一可以访问它的位置是视图中的一行时,为什么要在序列化中调用此属性? ?
小智 5
在System.Web.Mvc版本5.2.3.0中,DefaultModelBinder确实会执行验证,这可能违反了关注点的分离,并且没有一种方法可以通过任何设置或配置将其完全关闭。其他SO帖子提到使用Global.asax.cs Application_Start()方法中的以下代码行关闭值类型的隐式required属性。
DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
Run Code Online (Sandbox Code Playgroud)
请参阅:https : //stackoverflow.com/a/2224651(该站点引用的论坛直接来自asp.net团队)。
但是,这还不够。由于方法中的代码,所有模型类的获取器仍将执行DefaultModelBinder.BindProperty(...)。从源代码...
https://github.com/mono/aspnetwebstack/blob/master/src/System.Web.Mvc/DefaultModelBinder.cs
215 // call into the property's model binder
216 IModelBinder propertyBinder = Binders.GetBinder(propertyDescriptor.PropertyType);
217 object originalPropertyValue = propertyDescriptor.GetValue(bindingContext.Model);
218 ModelMetadata propertyMetadata = bindingContext.PropertyMetadata[propertyDescriptor.Name];
219 propertyMetadata.Model = originalPropertyValue;
220 ModelBindingContext innerBindingContext = new ModelBindingContext()
221 {
222 ModelMetadata = propertyMetadata,
223 ModelName = fullPropertyKey,
224 ModelState = bindingContext.ModelState,
225 ValueProvider = bindingContext.ValueProvider
226 };
227 object newPropertyValue = GetPropertyValue(controllerContext, innerBindingContext, propertyDescriptor, propertyBinder);
Run Code Online (Sandbox Code Playgroud)
第217行是违法者。它会在从请求设置值之前调用getter(此方法的最终目的),显然是这样,它可以将ModelBindingContext参数中的原始值传递给第GetPropertyValue(...)227行的方法。我找不到任何原因。
我在模型类中广泛使用了计算后的属性,如果属性表达式依赖于以前未设置的数据,则肯定会引发异常,因为这可能表明代码中其他地方存在错误。该DefaultModelBinder行为败坏该设计。
为了解决我的问题,我编写了一个自定义模型联编程序,该联编程序重写了该BindProperty(...)方法并删除了对吸气剂的调用。此代码只是原始源代码的副本,减去217和219行。由于未使用模型验证,因此我也删除了243至259行,并且该代码引用了派生类无法访问的私有方法(另一个DefaultModelBinder.BindProperty(...)方法的问题设计)。这是自定义模型活页夹。
public class NoGetterModelBinder : DefaultModelBinder {
protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor) {
string fullPropertyKey = CreateSubPropertyName(bindingContext.ModelName, propertyDescriptor.Name);
if (!bindingContext.ValueProvider.ContainsPrefix(fullPropertyKey)) return;
IModelBinder propertyBinder = Binders.GetBinder(propertyDescriptor.PropertyType);
ModelMetadata propertyMetadata = bindingContext.PropertyMetadata[propertyDescriptor.Name];
ModelBindingContext innerBindingContext = new ModelBindingContext() {
ModelMetadata = propertyMetadata,
ModelName = fullPropertyKey,
ModelState = bindingContext.ModelState,
ValueProvider = bindingContext.ValueProvider,
};
object newPropertyValue = GetPropertyValue(controllerContext, innerBindingContext, propertyDescriptor, propertyBinder);
propertyMetadata.Model = newPropertyValue;
ModelState modelState = bindingContext.ModelState[fullPropertyKey];
if (modelState == null || modelState.Errors.Count == 0) {
if (OnPropertyValidating(controllerContext, bindingContext, propertyDescriptor, newPropertyValue)) {
SetProperty(controllerContext, bindingContext, propertyDescriptor, newPropertyValue);
OnPropertyValidated(controllerContext, bindingContext, propertyDescriptor, newPropertyValue);
}
} else {
SetProperty(controllerContext, bindingContext, propertyDescriptor, newPropertyValue);
}
}
}
Run Code Online (Sandbox Code Playgroud)
您可以将该类放在Web项目中的任何位置,我只是将其放在Global.asax.cs中。然后,再次在Global.asax.cs的中Application_Start(),添加以下代码行,使其成为所有类的默认模型绑定程序...
ModelBinders.Binders.DefaultBinder = new NoGetterModelBinder();
Run Code Online (Sandbox Code Playgroud)
这将防止在模型类上调用getter。
| 归档时间: |
|
| 查看次数: |
102 次 |
| 最近记录: |