我试图找出在ASP.NET MVC中创建导航菜单的最佳方法,该菜单可以根据构建它的控制器操作进行更改(根据用户权限等也会有所不同)。导航菜单显示在母版页中,我们的所有视图都是强类型的。
我想在基本控制器中使用OnActionExecuting来填充标准菜单,然后在每个控制器操作中相应地修改它。这似乎不是一个选项,因为在调用我的动作之前视图模型不可用。
我能想到的另一件事是在基础ViewModel构造函数中预先填充菜单对象。然后我可以根据需要添加/删除我的控制器操作。这似乎并不完全合适,因为我将实例化链接回ViewModel构造函数中的控制器动作(因为每个Menu项都可以有一个控制器/动作/ id)。
有关最佳方法的任何建议吗?特别是对于根据上下文发生显着变化的导航菜单(或可能是树视图)。
答案 0 :(得分:1)
我使用MasterModel来做这种事情。
鉴于.aspx及其.master是可分离的(例如,在渲染aspx时你可以换掉master;而且aspx不会从master继承继承,只有使用主人)在我看来,视图模型也应该是分开的。 (即PageModel不应继承自MasterModel。)
aspx可能只关心接收一个IEnumerable< Foo>,为什么它的视图模型需要继承一些常见的类?
所以而不是:
public class MasterModel
{
public string Title { get; set; }
public MenuModel Menu { get; set; }
}
public class PageViewModel
: MasterModel
{
public IEnumerable<Foo> TheOnlyThingInTheWorldMyPageReallyCaresAbout { get; set; }
}
public ActionResult TheAction()
{
var items = GetItems();
var model = new PageViewModel {
TheOnlyThingInTheWorldMyPageReallyCaresAbout = items
};
return view("Viewname", model);
}
我用:
public class BaseController
: Controller
{
protected MasterModel MasterModel
{
get { return ViewData["MasterModel"] as MasterModel; }
set { ViewData["MasterModel"] = value; }
}
}
public class MasterModel
{
public MasterModel()
{
// Sensible defaults
}
public string Title { get; set; }
public MenuModel Menu { get; set; }
}
public ActionResult TheAction()
{
var items = GetItems();
// Prepare the MasterModel as part of the controller's "select and prepare the view" responsibility.
// Common cases can be factored into ActionFilter attributes or to a base Controller class.
MasterModel = new MasterModel();
return view("Viewname", items);
}
然后,您可以将其添加到母版页:
<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>
<script runat="server">
public MasterModel Model { get { return ViewData["MasterModel"] as MasterModel; } }
</script>
现在,您无需对页面视图模型执行任何特殊操作。他们只关心他们应该关心的事情。
我想在基本控制器中使用OnActionExecuting来填充标准菜单,然后在每个控制器操作中相应地修改它。这似乎不是一个选项,因为在调用我的动作之前视图模型不可用。
我能想到的另一件事是在基础ViewModel构造函数中预先填充菜单对象。然后我可以根据需要添加/删除我的控制器操作。这似乎并不完全合适,因为我将实例化链接回ViewModel构造函数中的控制器动作(因为每个Menu项都可以有一个控制器/动作/ id)。
现在很容易做到这些,与您的页面浏览模型无关:
MasterModel = this.DefaultMasterModel();
// -- or --
MasterModel = this.DefaultMasterModel();
this.AlterMenu(MasterModel.Menu);
// -- or --
MasterModel = new MasterModel();
MasterModel.Menu = this.SpecialReplacementMenu();
// -- or --
MasterModel = new NestedMasterModel();
// -- or --
public class FlyingPigAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
var viewResult = filterContext.Result as ViewResult;
if (viewResult!=null)
{
var masterModel = viewResult.ViewData["MasterModel"] as MasterModel;
MakePigsFly(masterModel);
}
}
}
虽然没有提供一个特定的解决方案,但是这会为您提供选项,以便您可以重构代码以使它更好闻?
答案 1 :(得分:0)