一、创建自定义模型绑定器:
利用请求数据塑造模型对象并将对象传递给动作参数的过程称为模型绑定(Model Binding)。
大多数时候动作参数是对象的主键或其他唯一标识符,因此我们可以不必在所有的动作中都放置一段重复的数据访问代码(下面代码“\\Before”部分),而是使用一个自定义的模型绑定器(下面代码“\\After”部分)。它能够在动作执行之前加载存储对象,于是动作不再以唯一标识符而是以持久化的对象类型作为参数。
// Before public ViewResult Edit (Guid id) { var profile=_profileRepository.GetById(id); return View(new ProfileEditModel(profile)); } // After public ViewResult Edit (Profile id) { return View(new ProfileEditModel(id)); }
MVC的可扩展性允许我们注册模型绑定器,这是通过为某一模型类型指定应该使用的绑定器来实现的。但是在实体比较多的情况下,比较理想的情况是我们只对一个公共基类型(Common Base Type)的自定义模型绑定器进行一次注册或者让每个自定义绑定器自己决定是否应该绑定。为了实现这一功能我们需要同时提供自定义模型绑定器提供器和自定义模型绑定器。提供器是由MVC框架使用的以决定使用哪一个模型绑定器进行模型绑定。
为了实现一个自定义模型绑定器提供器,我们需要实现IModelBinderProvider接口:
public interface IModelBinderProvider { IModelBinder GetBinder(Type modelType) }
任何想要运用自定义匹配逻辑的IModelBinderProvider的实现只需要检测传过来的模型类型,并判断能否返回自定义模型绑定器实例。
自定义模型绑定器提供器的一个实现:
public class EntityModelBinderProvider:IModelBinderProvider { public IModelBinder GetBinder(Type modelType) { if(!typeof(Entity).IsAssignable(modelType)) return null; return new EntityModelBinder(); } }
上例中我们首先检查modelType参数是否继承于Entity,如果不是则返回null表明该模型绑定器提供器不能为这一给定的类型提供模型绑定器,反之则返回一个EntityModelBinder(实体模型绑定器)的新实例。
完整的模型绑定器需要实现IModelBinder接口:
public class EntityModelBinder:IModelBinder { public object BindModel( ControllerContext controllerContext, ModelBinderContext bindingContext) { ValueProviderResult value= bindingContext.ValueProvider .GetValue(bindingContext.ModelName); if(value==null) return null; if(string.IsNullOrEmpty(value.AttemptedValue)) return null; int entityId; if(!int.TryParse(value.AttemptedValue,out entityId)) { return null; } Type repositoryType=typeof(IRepository<>) .MakeGenericType(bindingContext.ModelType); var repository=(IRepository)ServiceLocator .Resolve(repositoryType); Entity entity=repository.GetById(entityId); return entity; } }
public interface IRepository<TEntity> where TEntity:Entity { TEntity Get(int id); }
注册自定义模型绑定器提供器:
protected void Application_Start() { ModelBinderProviders.BinderProviders .Add(new EntityModelBinderProvider()); }
二、使用自定义值提供器:
通过建立额外的自定义值提供器我们可以进一步消除控制器范文动作中的查询代码:
// Before public ViewResult LogOnWidget(LogOnWidgetModel model) { bool inAuthenticated=Request.IsAuthenticated; model.IsAuthenticated=isAuthenticated; model.CurrentUser=Session[""]; return View(model); } // After public ViewResult LogOnWidget(LogOnWidgetModel model) { bool inAuthenticated=Request.IsAuthenticated; model.IsAuthenticated=isAuthenticated; return View(model); }
我感觉还是暂且略过吧,搞不懂。。。