Including user model in every view

徘徊边缘 提交于 2021-01-27 11:46:01

问题


I'm creating an ASP.NET MVC4 web site with Forms authentication and am encountering difficulties in the correct way to include multiple models within a view.

Specifically, there is a model that belongs to a given view, say "CartModel". However, given the current UI of the site, there is a model used within a partial view that is included in the master layout view with information about the currently logged in user.

My current approach for solving this issue is to include the LoginModel as a part of every view model. However, this seems repetitive and doesn't work correctly.

What is the most correct way to resolve an issue such as this?


回答1:


There are two ways to make it accessible.

  1. Use a filter (or override the OnActionExecuting method in a base controller your controllers all derive from) that add a models you need to ViewBag/ViewData.
  2. Use your own base WebViewPage to expose the models, but you'll still need to populate it. Thus, it may need to access your APIs, and done correctly, would probably require some dependency injection.

Method 1: OnActionExecuting

Override from base controller

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 */;
             }
        }
}

Then use it as the base class (or somewhere further up the inheritance):

public MyController : MyBaseController
{
   //etc.
}

Or use a filter

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);
    }
}

Then decorate a controller class, action method, or add as a global filter.

[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());
    }
}

Then use the model you placed in the ViewBag in referenced partials, layouts, etc., but keep using Model for the action's view.

Access the ViewBag normally in your view (also accessible to layouts, and I made up a property value on LoginModel type to illustrate):

<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 will be available for all actions that derive from this controller without extra work. I'd recommend making it an attribute as it will give you more flexibility with base classes and to which controllers/actions you want to apply it to.

Method 2: Providing your own WebViewPage base class

It is less likely you'll want to use your own WebPageView base class. If you want to add members to assist in working through data or whatever for a view, it's great for that. But it's not the right place to add to or otherwise manipulate viewdata or the model, although it's possible.

Create the view base class

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

Then use the members in your views, partials, and layouts

Make sure your web.config in the views folder is updated correctly.

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



回答2:


You can include multiple models in your view by several methods:

  1. Using ViewBag

    Action:

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

    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. Using ViewData

    Action:

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

    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:


Assuming that the "user info" is read from, say, User.Identity, you don't actually need to create a model instance for use within the current view.

Let's say you're trying to do this:

@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>

If the secondary model has nothing to do with the primary model, you can just call the @Html.Action() method, like so:

@model MyMasterViewModel

<div>

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

    @Html.Action("LoginInfo")

</div>

The result of the call is injected into the current view. I do something like this for my account menus, since I'm just reading the Identity info from the Request object and using that to get whatever else I need. If you want to make sure the "helper" action is never called direct, you can decorate it with [ChildActionOnly]



来源:https://stackoverflow.com/questions/20672575/including-user-model-in-every-view

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!