每个请求的MVC检索模型
可以说我正在开发一个供多个部门使用的帮助台应用程序。应用程序中的每个URL都将包含一个指示特定部门的密钥。该键将始终是系统中每个操作的第一个参数。例如
http://helpdesk/HR/Members http://helpdesk/HR/Members/PeterParker http://helpdesk/HR/Categories http://helpdesk/Finance/Members http://helpdesk/Finance/Members/BruceWayne http://helpdesk/Finance/Categories
问题在于,在对每个请求的每个操作中,我都必须采用此参数,然后基于该键从存储库中检索帮助台部门模型。从该模型中,我可以检索成员,类别等的列表,这对于每个服务台部门都是不同的。这显然违反了DRY。
我的问题是,我该如何创建一个基础控制器,以便为我执行此操作,以便URL中指定的特定帮助台部门可用于所有派生的控制器,而我只能关注操作?
解决方案
回答
免责声明:我当前正在运行MVC Preview 5,因此其中一些可能是新的。
最佳实践方式:只需实现一个静态实用程序类,该类提供一个执行模型查找的方法,并将动作中的RouteData作为参数。然后,从需要模型的所有操作中调用此方法。
仅当每个控制器中的每个动作都需要模型且我们确实不想在该动作中进行额外的方法调用时,才采用这种灵活的方式:在Controller-implementing-base-class中,重写ExecuteCore()使用RouteData填充模型,然后调用base.ExecuteCore()。
回答
我们可以通过常规Cinheritance创建基本控制器类:
public abstract class BaseController : Controller { } public class DerivedController : BaseController { }
我们只能将此基类用于需要部门的控制器。我们无需执行任何特殊操作即可实例化派生的控制器。
从技术上讲,这可以正常工作。但是,从设计角度来看存在一定风险。如我们所说,如果所有控制器都需要一个部门,那就很好。如果仅其中一些需要部门,可能还可以。但是,如果某些控制器需要一个部门,而其他控制器则需要其他一些继承的行为,并且两个子集都相交,那么我们可能会遇到多重继承问题。这表明继承不是解决我们陈述的问题的最佳设计。
回答
在我的一个项目中,我有一个类似的场景,我倾向于使用ModelBinder而不是使用单独的继承层次结构。我们可以创建ModelBinder属性,以从RouteData中获取实体/实体:
public class HelpdeskDepartmentBinder : CustomModelBinderAttribute, IModelBinder { public override IModelBinder GetBinder() { return this; } public object GetValue(ControllerContext controllerContext, string modelName, Type modelType, ModelStateDictionary modelState) { //... extract appropriate value from RouteData and fetch corresponding entity from database. } }
...然后我们可以使用它使HelpdeskDepartment可用于所有操作:
public class MyController : Controller { public ActionResult Index([HelpdeskDepartmentBinder] HelpdeskDepartment department) { return View(); } }