适用于多种类型的 MVC 自定义模型绑定

本文关键字:自定义 模型 绑定 MVC 种类 类型 适用于 | 更新日期: 2023-09-27 18:34:51

我们有一个自定义模型绑定器,它将 json 反序列化为对象列表,我想将该模型绑定器用于多个视图,每个视图使用不同的视图模型。

我们要避免的是必须为每个视图模型注册模型绑定器,如下所示:

ModelBinders.Binders.Add(typeof(ViewModelOne), new JsonPropertyBinder());
ModelBinders.Binders.Add(typeof(ViewModelTwo), new JsonPropertyBinder());

我们要做的是让 ViewModels 从基类派生(他们这样做(并注册该基类:

ModelBinders.Binders.Add(typeof(ViewModelBase), new JsonPropertyBinder());

其中ViewModelOneViewModelTwo继承形式ViewModelBase .我试过这个,但我没有任何运气。那里的问题是,需要自定义绑定的属性不在基本视图模型中。我们真正想要的是一个优雅的解决方案,以通用的方式实现我的模型绑定器。

我们还对要自定义绑定的视图模型中的属性[JsonBindable]自定义属性,然后我在绑定器中检查此属性:

public class JsonPropertyBinder : DefaultModelBinder
    {
        protected override object GetPropertyValue(ControllerContext controllerContext, System.Web.Mvc.ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, System.Web.Mvc.IModelBinder propertyBinder)
        {
            if (propertyDescriptor.Attributes.OfType<Attribute>().Any(x => (x is JsonBindableAttribute)))
            {
                var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName).AttemptedValue;
                return JsonConvert.DeserializeObject(value, propertyDescriptor.PropertyType);
            }
            return base.GetPropertyValue(controllerContext, bindingContext, propertyDescriptor, propertyBinder);
        }
    }

我尝试将 [ModelBinder] 属性添加到我的视图模型中,但没有成功。虽然,我不确定我是否喜欢这种方法,因为我想将活页夹的注册保留在一个地方,而不是分散开来

--编辑--我想我可以创建一个中间类(例如 ViewModelIntermediate (,它将从ViewModelBase继承,仅包含我要自定义绑定的属性,然后ViewModelOneViewModelTwoViewModelIntermediate继承,以便我可以使用派生的 ViewModel 注册一次绑定器,例如

ModelBinders.Binders.Add(typeof(ViewModelIntermediate), new JsonPropertyBinder());

但这似乎是一个笨拙的解决方案。我希望能够声明一次自定义绑定程序并将其用于任何视图模型 - 而不必将我的类抽象为遗忘。

现在我在想我可能必须声明一个新的默认绑定器,它继承自 DefaultModelBinder,并且其中有一些逻辑来检查某些(或自定义(属性并相应地处理它们。 像这样的东西

适用于多种类型的 MVC 自定义模型绑定

我认为您可能正在寻找的是一个自定义模型绑定提供程序......基本上是一个超级抽象,它确定在给定模型类型的情况下使用哪种ModelBinder。

因此,基本上,实现 IModelBinderProvider 接口,并让 GetBinder 方法根据您的条件返回模型绑定器。

public class ViewModelBaseBinderProvider
    : IModelBinderProvider
{
    public IModelBinder GetBinder(Type modelType)
    {
        // this or whatever condition you want to apply to determine
        // if your model binder needs to be used.
        if (typeof(ViewModelBase).IsAssignableFrom(modelType))
            return new JsonPropertyBinder();
        // this means, the view model did not match our criteria   
        // let it flow through the usual model binders.       
        return null;
    }
}

定义自定义提供程序后,在应用程序中注册,如下所示:

ModelBinderProviders.BinderProviders.Add(new ViewModelBaseBinderProvider());

PS Nit:为了清楚起见,我将JsonPropertyBinder重命名为JsonPropertyModelBinder