在每个视图中包含用户模型

时间:2013-12-19 02:47:53

标签: c# asp.net asp.net-mvc asp.net-mvc-4

我正在使用Forms身份验证创建一个ASP.NET MVC4网站,并且在查看视图中包含多个模型的正确方法遇到了困难。

具体来说,有一个属于给定视图的模型,比如“CartModel”。但是,考虑到站点的当前UI,在部分视图中使用的模型包含在主布局视图中,其中包含有关当前登录用户的信息。

我目前解决此问题的方法是将LoginModel作为每个视图模型的一部分。但是,这似乎是重复的,并且无法正常工作。

解决此问题的最正确方法是什么?

3 个答案:

答案 0 :(得分:4)

有两种方法可以访问它。

  1. 使用过滤器(或覆盖控制器全部派生自的基础控制器中的OnActionExecuting方法),将ViewBag / ViewData所需的模型添加到其中。
  2. Use your own base WebViewPage公开模型,但您仍然需要填充它。因此,它可能需要访问您的API,并且正确完成,可能需要一些依赖注入。
  3. 方法1:OnActionExecuting

    从基本控制器覆盖

    public abstract MyBaseController : Controller
    {
            protected override void OnActionExecuting(ActionExecutingContext filterContext)
            {
                 if (User != null && User.Identity.IsAuthenticated) // check if user is logged in if you need to
                 {
                      ViewBag.LoginModel = /* add data here */;
                 }
            }
    }
    

    然后将它用作基类(或继承的某个地方):

    public MyController : MyBaseController
    {
       //etc.
    }
    

    或使用过滤器

    PopulateLoginModelAttribute : ActionFilterAttribute, IActionFilter
    {
        void IActionFilter.OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (filterContext.HttpContext.User != null && filterContext.HttpContext.User.Identity.IsAuthenticated)
            {
                 filterContext.Controller.ViewBag.LoginModel = /* add data here */;
            }
    
            this.OnActionExecuting(filterContext);
        }
    }
    

    然后装饰控制器类,操作方法或添加为全局过滤器。

    [PopulateLoginModel] // will be applied to all actions in this controller
    public class MyController : Controller // note you can use the normal base type, or whatever you need
    {
        public ActionResult MyView()
        {
            return View(new CartModel());
        }
    }
    

    然后使用您在引用的部分,布局等ViewBag中放置的模型,但继续使用Model作为操作的视图。

    通常在视图中访问ViewBag(也可以访问布局,我在LoginModel类型上编写了一个属性值来说明):

    <span>@ViewBag.LoginModel.Name</span> <!-- available because of the filter !-->
    Number of items in your cart: @Model.Items.Count <!-- the model provided by the action method !-->
    

    ViewBag.LoginModel将可用于从此控制器派生的所有操作,无需额外工作。我建议将它作为一个属性,因为它可以让您更灵活地使用基类以及要将其应用到哪些控制器/操作。

    方法2:提供自己的WebViewPage基类

    您不太可能想要使用自己的WebPageView基类。如果您想添加成员以帮助处理数据或视图的任何内容,那么它非常适合。但它不是添加或操纵viewdata或模型的正确位置,尽管它是可能的。

    创建视图基类

    public abstract class MyWebViewPage<T> : WebViewPage<T>
    {
        protected LoginModel GetLoginModel()
        {
            // you could resolve some dependency here if you need to
            return /* add data here */
        }
    }
    

    然后使用视图,部分和布局中的成员

    确保views文件夹中的web.config已正确更新。

    <span>@GetLoginModel().Name</span>
    

答案 1 :(得分:2)

您可以通过多种方法在视图中包含多个模型:

  1. 使用ViewBag

    动作:

    public ActionResult Index()
    {
        ViewBag.CartData = _repository.GetCartData();
        ViewBag.LoginData = _repository.GetLoginData();
    
        return View();
    }   
    

    查看:

    @foreach (var item in ViewBag.CartData)
    {         
        // Do something here with item in CartData model    
    }
    
    @foreach (var item in ViewBag.LoginData)
    {         
        // Do something here with item in LoginData model    
    }
    
  2. 使用ViewData

    动作:

    public ActionResult Index()
    {
        ViewData["CartData"] = _repository.GetCartData();
        ViewData["LoginData"] = _repository.GetLoginData();
    
        return View();
    }    
    

    查看:

    @foreach (var item in ViewData["CartData"] as List<Cart>)
    {         
        // Do something here with item in CartData model    
    }
    
    @foreach (var item in ViewData["LoginData"] as List<Login>)
    {         
        // Do something here with item in LoginData model    
    }
    

答案 2 :(得分:0)

假设从User.Identity读取“用户信息”,您实际上不需要创建模型实例以在当前视图中使用。

假设您正在尝试这样做:

@model MyMasterViewModel
<div>

    @* Displaying some property of the primary model *@
    @Model.SomeProperyOrAnother

    @* Displaying some property of the model that is a member of the primary model *@
    @Model.InnerModel.SomeOtherProperty

</div>

如果辅助模型与主模型无关,则可以调用@Html.Action()方法,如下所示:

@model MyMasterViewModel

<div>

    @* Displaying some property of the primary model *@
    @Model.SomeProperyOrAnother

    @Html.Action("LoginInfo")

</div>

调用的结果被注入当前视图。我为我的帐户菜单做了类似的事情,因为我只是从Identity对象中读取Request信息并使用它来获取我需要的任何其他信息。如果你想确保永远不会直接调用“助手”动作,你可以用[ChildActionOnly]

来装饰它。