我一直在寻找一种处理Asp.net MVC网站模型的好方法,当所有页面具有共同属性时。这些属性将显示在布局(母版页)中。我使用一个“BaseModel”类来保存这些属性,并且我的布局使用此BaseModel作为其模型。
每个其他模型都继承自该BaseModel,并且每个模型都有相对于其表示的视图的特定属性。正如您可能已经猜到的那样,我的模型实际上是视图模型,即使这在这里并不太相关。
我尝试了不同的方法来初始化BaseModel值:
1. 在每个视图中手动设置 2. 拥有一个基本控制器,它具有一个Initialize虚拟方法来执行它(因此特定控制器可以实现特定的公共行为) 3. 有一个基本控制器,覆盖OnActionExecuting以调用Initialize方法 4. 使用帮助程序类在控制器之外进行操作 5. 使用模型工厂
但是,这些方法都没有真正吸引我:
每个其他模型都继承自该BaseModel,并且每个模型都有相对于其表示的视图的特定属性。正如您可能已经猜到的那样,我的模型实际上是视图模型,即使这在这里并不太相关。
我尝试了不同的方法来初始化BaseModel值:
1. 在每个视图中手动设置 2. 拥有一个基本控制器,它具有一个Initialize虚拟方法来执行它(因此特定控制器可以实现特定的公共行为) 3. 有一个基本控制器,覆盖OnActionExecuting以调用Initialize方法 4. 使用帮助程序类在控制器之外进行操作 5. 使用模型工厂
但是,这些方法都没有真正吸引我:
- 对我来说似乎显而易见,但DRY就足以证明这一点了(实际上我从未尝试过那个解决方案,我只是为了能够在最后一点上循环而将其放置在那里)。
- 我不喜欢那个方法,因为它意味着每当添加一个新的控制器时,你需要知道它必须从BaseController继承并且你需要调用Initialize方法,更不用说如果你的控制器已经覆盖了基本控制器,仍然需要调用基本控制器以保持值。
- 见下一点
- 第3点和第4点是同一主题的变体,但这并不能真正解决第二种解决方案的问题。
- 到目前为止,这是我的最爱,但现在我必须传递更多的变量来设置这些值。我喜欢它的依赖反转。但是,如果我想要提供来自会话的值,例如,我需要显式地传递它们,那么我又回到了起点,因为我必须手动提供它们(无论是引用还是通过任何类型的接口)。
当然,(几乎)所有这些解决方案都可以工作,但我正在寻找更好的方法来解决这个问题。
在输入这个问题的同时,我发现可能有一条新的路线——构建者模式,但是实现也可能很快变成一个负担,因为我们可能会有几十个视图和控制器。
我很乐意接受任何严肃的推荐/提示/建议/模式/建议!
更新
感谢@EBarr,我想出了另一个解决方案,使用ActionFilterAttribute(不是生产代码,在5分钟内完成):
public class ModelAttribute : ActionFilterAttribute
{
public Type ModelType { get; private set; }
public ModelAttribute(string typeName) : this(Type.GetType(typeName)) { }
public ModelAttribute(Type modelType)
{
if(modelType == null) { throw new ArgumentNullException("modelType"); }
ModelType = modelType;
if (!typeof(BaseModel).IsAssignableFrom(ModelType))
{
throw new ArgumentException("model type should inherit BaseModel");
}
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var model = ModelFactory.GetModel(ModelType);
var foo = filterContext.RequestContext.HttpContext.Session["foo"] as Foo;
model.Foo = foo;
model.Bar = somevalue;
filterContext.Controller.TempData["model"] = model;
}
}
调用它非常简单:
[Model(typeof(HomeModel))]
public ActionResult Index()
{
var homeModel = TempData["model"] as HomeModel;
// Add View Specific stuff
return View(homeModel);
}
它让我拥有了最好的每个世界。唯一的缺点是找到一个适当的方法来将模型传回操作。
这里使用TempData对象完成,但我也考虑更新在ActionParameters中找到的模型。
我仍然接受任何关于此的严肃建议/提示/建议/模式或之前提到的问题。
OnActionExecuting
和OnActionExecuted
中可以使我的代码位于单个基本控制器中。在任何较大的 MVC 项目中,您都将拥有一个基本控制器,因此我并不介意。它还允许我根据模型类型运行逻辑,而不是将逻辑与执行的操作绑定在一起。 - EBarr