0

I have a simple question, but its is very important to my project: What is the best way to create a global variable?

In my project, when the user will be authenticated, I build all web menus according with his profile, like claims or roles (I create my own claims), and I start to build the menu, with the specifics pages wich the user have permission to access.

In my filter method, I always check in the database if the user has the permission to access the menu.

What I wanna know is if have a possibility to put this list of menus in a global variable, like a Session ("/) or Application, because I dont wanna have to go to the database to check those permissions, and in this case is better if I could get this list in the server memory or something like that...

Regards.

Johnathon Sullinger
  • 7,097
  • 5
  • 37
  • 102
Antônio Filho
  • 221
  • 1
  • 10
  • 13
    The best way to create a global variable is not to create one. – Yuval Itzchakov Jul 01 '15 at 19:26
  • 2
    Global variables should be avoided. You could use service class that has a method you invoke to get this info. That service method would hit the database or do what ever setup it needs to, and cache the results in a private static collection. You should really avoid a public static property that is truly global. It will bite you in the butt later on. – Johnathon Sullinger Jul 01 '15 at 19:29
  • 1
    You should be checking the role of the user. If the user meets a specific role, then show the menus? Why do you not want this approach? – Kala J Jul 01 '15 at 19:29
  • possible duplicate of [Global variables in c#.net](http://stackoverflow.com/questions/2445436/global-variables-in-c-net) – Johnathon Sullinger Jul 01 '15 at 19:30
  • In that project, all the menus are configurable by a View with a table in the dabatase. How can I cache the results in a 'private static collection'? Because I wanna get my list of menus and put it in a 'global variable' to can take it everytime I want! In each page which user clicks, I must check if the user has the access and it is better if I could just read this 'global variable' in my filter method instead of to get that by the database. – Antônio Filho Jul 01 '15 at 19:36
  • 1
    Isn't this what caches are for? – StarPilot Jul 01 '15 at 20:27

1 Answers1

0

The best way to handle your situation is with a child action. You simply create an action in some controller in your project. Since this deals with user-level access, I'll use AccountController.

[AllowAnonymous]
[ChildActionOnly]
public ActionResult UserMenu()
{
    if (User.Identity.IsAuthenticated())
    {
        // logic to select your menu from database
        return View(menu);
    }

    // optionally you can return a different menu for anonymous users here
    return Content("");
}

Then, you create the UserMenu.cshtml view in your Views\Account directory. In this view, you'll simply use the model instance you passed in (menu above) to render just portion of your site navigation the menu object applies to.

Finally, in your layout, wherever you want this menu to appear, call:

@Html.Action("UserMenu", "Account");

If you want to only have this run once (really better put as "occasionally"), then you can utilize caching. Just add the following additional attribute to your child action:

[OutputCache(Duration = 3600, VaryByCustom = "User")]

There's no built in way to vary the cache by a particular user, so you have to create a custom vary. It's relatively easy though. Just add something like the following to Global.asax:

public override string GetVaryByCustomString(HttpContext context, string arg) 
{ 
    if(arg.ToLower() == "user") 
    { 
        if (context.User.Identity.IsAuthenticated())
        {
            return context.User.Identity.Name;
        }

        return null;
    } 

    return base.GetVaryByCustomString(context, arg); 
}

Then, MVC will cache the output of the UserMenu action for each unique user for 1 hour (3600 seconds), meaning any other requests by the same user will not invoke the action or send any queries to your database until the cache has expired.

Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
  • Perfect! This is exactly what I want! I have 2 simple questions: 1) This 'OutputCache' is a 'nice thing' to the application or is a 'bad thing', if you know what I mean... 2) In the 'GetVaryByCustomString' method, what's the difference between 'return null' and 'return context.User.Identity.Name'? Because the both make no difference to execute the 'ChildAction'... – Antônio Filho Jul 02 '15 at 13:32