MVC BaseController和BaseModel保证值适用于所有的意见 [英] MVC BaseController and BaseModel to ensure that values are available to all views

查看:222
本文介绍了MVC BaseController和BaseModel保证值适用于所有的意见的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是关于一个解决方案,通过@Andre Calil在SO下面提供的一个问题
<一href=\"http://stackoverflow.com/questions/16986251/razor-mvc-where-to-put-global-variables-thats-accessible-across-master-page-p\">Razor MVC,在那里把全局变量是整个母版页,partiview访问和查看?

我使用的是安德烈的方法,并有一个小问题:
我_layout是强类型的BaseModel和我的看法是强类型为AccountModel从BaseModel继承。

问题是:如果我回到没有模式,即一个视图返回查看()然后我得到一个异常。它造成的,因为在BaseController OnActionExecuted事件被检查,如果提供的模型为空,如下所示:

 保护覆盖无效OnActionExecuted(ActionExecutedContext filterContext)
{
    如果(filterContext.Result是ViewResultBase)//获取的ViewResult和PartialViewResult
    {
        对象视图模型=((ViewResultBase)filterContext.Result)。型号;        如果(视图模型= NULL&放大器;!&安培;视图模型是MyBaseModel)
        {
            MyBaseModel myBase =视图模型作为MyBaseModel;
            myBase.Firstname = CurrentUser.Firstname; //从基本控制器
        }
    }
    base.OnActionExecuted(filterContext); //这是很重要的!
}

该模型是空,因此这种情况下就不会总是工作。我的下一步是确保我总是通过一个模型分成即使它是一个空BaseModel对象的视图。这一问题是,我得到了以下异常:

 传递到字典的模型项的类型是MyNamespace.BaseModel',但本词典需要类型的模型项目MyNamespace.AccountModel。

两点,我需要澄清:


  1. 我认为这将工作,因为AccountModel是子类BaseModel的?

  2. 如果该模型是在上面的code空,有另一种方式,我可以注入一个模型到每个视图,以便我能避免重构所有我的code,包括返回查看(BaseModel。空)?


解决方案

您需要看定制剃刀意见本文由Phil Haacked描述:

的http:// haacked.com/archive/2011/02/21/changing-base-type-of-a-razor-view.aspx

所以基本上你BaseController你会设置将在基地控制器的初始化事件每次请求可读取(在我的情况下,它是用户的实例)公共变量:

 公共类BaseController:控制器
{
   公众用户APPUSER;   保护覆盖无效初始化(RequestContext的的RequestContext)
   {
       base.Initialize(RequestContext的);
       APPUSER = _userService.GetUser(ID);
       ViewBag.User = APPUSER;
   }
}

好,你现在可以通过从基控制器继承的任何控制器访问的变量。剩下要做的唯一一件事就是要弄清楚如何使用您的视图中这个变量。这就是我在上面链接的文章将帮助您。默认情况下,所有的意见都来自System.Web.Mvc.WebViewPage产生。但是,您可以通过以下操作使这个类的自定义实现:

 命名空间YourApplication.Namespace
{
   公共抽象类CustomWebViewPage:WebViewPage
   {
      私人用户_appUser;      公共用户APPUSER
      {
         得到
         {
            尝试
            {
                _appUser =(用户)ViewBag.User;
            }
            赶上(例外)
            {
                _appUser = NULL;
            }
            返回_appUser;
         }
      }
   }   公共抽象类CustomWebViewPage&LT;&的TModel GT; :WebViewPage&LT;&的TModel GT;那里的TModel:类
   {
      私人用户_appUser;      公共用户APPUSER
      {
          得到
          {
              尝试
              {
                 _appUser =(用户)ViewBag.User;
              }
              赶上(例外)
              {
                 _appUser = NULL;
              }
              返回_appUser;
          }
      }
   }
}

您刚才定义有用户属性,并试图获取一个自定义的剃刀视图类从ViewBag.User,我们建立在我们的基本控制器。剩下要做的唯一一件事就是告诉您的应用程序时,它试图生成视图使用这个类。您可以通过设置下面的行你的意见web.config文件中做到这一点:

 &LT;页面pageBaseType =YourApplication.Namespace.CustomWebViewPage&GT;

现在对你的看法,你为你的用户属性帮助,您可以使用这样的:

  @AppUser

请不是申报需要进入的意见web.config中的页面文件并非主要的应用程序的web.config!

我觉得这是给你一个更好的解决方案,因为你没有提供示范基地通过视图模型所有视图。视图模型应保留它是用来干什么。

This is a question about a solution provided by @Andre Calil in the following SO Razor MVC, where to put global variables that's accessible across master page, partiview and view?

I'm using Andre's approach and have a slight problem: My _Layout is strongly typed as BaseModel and my view is strongly typed as AccountModel which inherits from BaseModel.

Problem is: if I return a view with no model i.e. return View() then I get an exception. It's caused because the BaseController OnActionExecuted event is checking if the model provided is null as in:

protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
    if (filterContext.Result is ViewResultBase)//Gets ViewResult and PartialViewResult
    {
        object viewModel = ((ViewResultBase)filterContext.Result).Model;

        if (viewModel != null && viewModel is MyBaseModel)
        {
            MyBaseModel myBase = viewModel as MyBaseModel;
            myBase.Firstname = CurrentUser.Firstname; //available from base controller
        }
    }
    base.OnActionExecuted(filterContext);//this is important!
}

The model is null so this scenario won't always work. My next step was to make sure I always pass a model into a view even if it's an empty BaseModel object. Problem with that is that I get the following exception:

The model item passed into the dictionary is of type 'MyNamespace.BaseModel', but this dictionary requires a model item of type 'MyNamespace.AccountModel'.

Two points that I need to clarify:

  1. I thought this would work because AccountModel is a sub class of BaseModel?
  2. If the model is null in the code above, is there another way that I can inject a model into each view so that I can avoid having to refactor all my code to include return View(BaseModel.Empty)?

解决方案

You need to look at custom razor views as described by Phil Haacked in this article:

http://haacked.com/archive/2011/02/21/changing-base-type-of-a-razor-view.aspx

So basically in your BaseController you would set up a public variable that will be fetched on every request in the base controller's Initialize event (in my case it is the instance of User):

public class BaseController : Controller
{
   public User AppUser;

   protected override void Initialize(RequestContext requestContext)
   {
       base.Initialize(requestContext);
       AppUser = _userService.GetUser(id);
       ViewBag.User = AppUser;
   }
}

So now you have a variable which can be accessed by any controller which inherits from the base controller. The only thing left to do is to figure out how to use this variable inside your view. This is where the article I linked above will help you. By default all your views are generated from System.Web.Mvc.WebViewPage. However you can make a custom implementation of this class by doing the following:

namespace YourApplication.Namespace
{
   public abstract class CustomWebViewPage : WebViewPage
   {
      private User _appUser;

      public User AppUser
      {
         get
         {
            try
            {
                _appUser = (User)ViewBag.User;
            }
            catch (Exception)
            {
                _appUser = null;
            }
            return _appUser;
         }
      }
   }

   public abstract class CustomWebViewPage<TModel> : WebViewPage<TModel> where TModel : class
   {
      private User _appUser;

      public User AppUser
      {
          get
          {
              try
              {
                 _appUser = (User)ViewBag.User;
              }
              catch (Exception)
              {
                 _appUser = null;
              }
              return _appUser;
          }
      }
   }
}

You have just defined a custom razor view class which has a property of user and tries to fetch that from the ViewBag.User that we setup in our base controller. The only thing left to do is to tell your app to use this class when it's trying to generate the view. You can do this by setting the following line in your VIEWS web.config file:

<pages pageBaseType="YourApplication.Namespace.CustomWebViewPage">

Now on your view you get a helper for your User property that you can use like this:

@AppUser

Please not that the pages declaration needs to go into the VIEWS web.config files not the main app web.config!

I think this is a much better solution for you since you don't have to provide the base model to all your view via the view model. View model should be reserved for what it is intended.

这篇关于MVC BaseController和BaseModel保证值适用于所有的意见的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆