Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Razor MVC, where to put global variables that's accessible across master page, partiview and view?

Hello Razor MVC Gurus:

Newbie question.

Background. I have a custom IIdentity that is set in an HttpModule before it gets to controller & views. To use it, i have to do

   MyIdentity myIdentity = (MyIdentity)((GenericPrincipal)context.User).Identity;
   MyComplexUser user = myIdentity.User;
   //user.name //user.location //user.username  //etc

The problem is, I use the object in different places such as

  • master layout
  • Some sub level nested layouts
  • Some partialviews
  • Some views

It really depends on what properties of "MyComplexUser" object the views need.

Currently, in the views, I have to do this really complicated casting to get to a property. For instance, if I want the "Name" of the user, I need to do

@(((MyComplexUser)(((MyIdentity)((GenericPrincipal)context.User).Identity).User)).Name)

I suppose I could put it in the controllers and then populate the ViewBag with a ViewBag.MyUser property, but then

  1. I don't like to use ViewBag. I prefer strongly typed objects
  2. If I use a strongly typed object ("MyUser") for views, then I have to popular all those models with a "MyUser" property. Feels a bit dirty? As I like to keep my models clean and be specific to the views they are involved with. Besides, it gets unnecessarily repetitive.
  3. In places like master_layout.cshtml or partialviews, how do you access "MyUser" if I put them in a controller?
  4. Use RenderAction and build partialviews for each User property is an overkill?

Thanks. Again, I'm a newbie at MVC 4, any suggestion is greatly appreciate it.

like image 368
Liming Avatar asked Jun 07 '13 14:06

Liming


People also ask

How do I create a global variable in Razor view?

To declare a variable in the View using Razor syntax, we need to first create a code block by using @{ and } and then we can use the same syntax we use in the C#. In the above code, notice that we have created the Code block and then start writing C# syntax to declare and assign the variables.

Can you mix MVC and Razor pages?

You can add support for Pages to any ASP.NET Core MVC app by simply adding a Pages folder and adding Razor Pages files to this folder. Razor Pages use the folder structure as a convention for routing requests.

What is the equivalent of ASP NET Master pages in Razor view?

Layout is similar to the master page in ASP.NET Web Form. Similar to master page, the Layouts may contain CSS, jQuery files and multiple views. Layout can keep the user interface elements and theme consistency throughout the application. Layouts are the special view type in ASP.NET MVC.


1 Answers

I'll explain a similar solution that works pretty well for me. With small changes, I believe that it will work for you (and others, hopefully) as well.

Basically, we'll be using inheritance.

Controllers

Let's create a custom base controller, such as

public class BaseController : Controller

and let's change our controllers to inherit from it, as

public class HomeController : BaseController

Models (ViewModels, I say)

You probably have lots of classes inside your Models folder, right? They act as DTOs from the controller to the views, right²? If you answered yes for both, then keep reading.

Let's create a base model class, such as public class BaseVM, and let's change our models to inherit from it, like public class HomeIndex : BaseVM

Important: your layout file (_Layout or whatsoever) must be strongly typed to BaseVM or a child of it.

The hook

Now that everything's beautifuly typed, let's use the request pipeline in our favor. At BaseController, you'll add a method that looks like this:

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 BaseVM)
        {
            BaseVM baseVM = viewModel as BaseVM;

            baseVM.MyIdentity = (MyIdentity)((GenericPrincipal)context.User).Identity;
            //and so on...
        }
    }

    base.OnActionExecuted(filterContext);//this is important!
}

OnActionExecuted is called after the execution of the action but before the view rendering. That's exactly what we want.

I hope you got it already. =)

like image 74
Andre Calil Avatar answered Sep 28 '22 07:09

Andre Calil