【问题标题】:Including user model in every view在每个视图中包含用户模型
【发布时间】:2013-12-19 02:47:53
【问题描述】:

我正在创建一个带有表单身份验证的 ASP.NET MVC4 网站,但在以正确的方式在一个视图中包含多个模型时遇到了困难。

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

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

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

【问题讨论】:

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


【解决方案1】:

有两种方法可以访问它。

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

方法一: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 将可用于从该控制器派生的所有操作,无需额外工作。我建议将其设为属性,因为它可以让您更灵活地使用基类以及要将其应用于哪些控制器/动作。

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

您不太可能希望使用自己的 WebPageView 基类。如果您想添加成员以协助处理数据或查看任何内容,这非常适合。但它不是添加或以其他方式操作视图数据或模型的正确位置,尽管这是可能的。

创建视图基类

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

然后在视图、局部和布局中使用成员

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

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

【讨论】:

    【解决方案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    
      }
      

    【讨论】:

      【解决方案3】:

      假设“用户信息”是从 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>
      

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

      【讨论】:

        猜你喜欢
        • 2012-03-13
        • 2019-10-03
        • 2012-11-26
        • 1970-01-01
        • 2013-05-28
        • 2013-05-07
        • 2011-08-18
        • 2016-06-25
        • 1970-01-01
        相关资源
        最近更新 更多