48

I am busy converting a web application to MVC and have some information saved to Application variables used across multiple tenants/accounts to make things a bit more efficient.

I realise the point of MVC is to keep things as stateless as possible, Sesion State obviously makes sense to have and exists in MVC but we dont want to just convert Application to Session variables as we would rather have something more global and more secure. Do MVC applications have Application Variables? I have seen some examples where caching is used? Is this now standard and How robust/secure is this compared to Application/Session State?

Mark Redman
  • 24,079
  • 20
  • 92
  • 147

6 Answers6

104

Yes, you can access Application variables from .NET MVC. Here's how:

System.Web.HttpContext.Current.Application.Lock();
System.Web.HttpContext.Current.Application["Name"] = "Value";
System.Web.HttpContext.Current.Application.UnLock();
AdamantineWolverine
  • 2,131
  • 1
  • 17
  • 14
  • 4
    Why calling `Lock` and `Unlock`? Is it also necessary when reading a previously set value? – awe Oct 30 '13 at 11:47
  • 1
    @awe it's to help prevent against race conditions – Zach M. Mar 07 '14 at 20:33
  • @ZachM. What kind of race could happen here? Possibly create 2 Application variables with same name? Other than that, I don't see much else could get in a race condition, and this would be something I would expect the set operation to handle internally. – awe Mar 10 '14 at 10:32
  • I was simply stating the reason for lock and unlock, if you have an application with multiple users this could happen. Application wide variables are available out of session from my understanding. – Zach M. Mar 10 '14 at 12:53
  • 4
    One example is that you have multiple users accessing your site and you want to run some resource intensive code once every few minutes, but no more. The application variable is available across sessions, so you use the application variable to track the last time someone ran the resource intensive code. You lock the application variable, check the time it was last run, and if it is time to run the code again, you update the application variable to the current time, unlock the variable, and run the resource intensive code. – AdamantineWolverine Apr 22 '14 at 07:17
  • @Zach M - Session is specific for every user, you can't access other user session variable – Lyubomir Velchev Jun 04 '15 at 16:10
7

Session state or the Cache are better choices. They are mockable in MVC and are designed to store session and application-scoped data.

Static classes seems like a popular choice here. However static classes create dependencies between your types and make versioning/testing harder. Its also a bit of an odd pattern to use in a framework that is designed to break apart these kinds of dependencies. For instance, the standard ASP.NET framework is riddled with statics and sealed types. These are all replaced with mock-able instances.

"Secure" is a bit unclear in this context. Exactly what do you mean by "secure?"

  • 2
    Of course for optimal decoupling, testing etcetera one should store them in an ordinary class and put a instance that class in a the IoC-container. – Svante Svenson Feb 15 '10 at 16:17
  • 1
    @svinto that all depends on the rest of the design. IOC isn't configuration. You can configure for IOC but that's more about what type to use in this situation, not what color to use on the header background, for instance. –  Feb 15 '10 at 17:56
  • Voted up! Static classes have a lot of the same problems as global variables and big S Singletons. They are tightly coupled, difficult to test and can have concurrency issues. If you do use static classes you should make all properties readonly!! Better to store your variables in a data file (XML, JSON, YAML) or a database and then pull them into cache. This also has the benefit of letting you change your configuration without recompiling. IoC could be useful if you think you might change the data source and want to be able to switch between different classes to load the data into cache. – Chris Kentfield May 25 '12 at 02:19
  • Session State is per request. Application state, as the OP wants, is the same across all requests. Cache is closer, but is more appropriate for caching values which require heavy workload to create, but may change, and could be updated after a given timeout. HttpContext.Current.Application is the right answer here. – Josh Noe Jul 17 '13 at 14:56
4

I implemented something like below as an Extension for Global state variable. I put things like Site title,Service Endpoints, authorized roles

public static class ApplicationStateExtension
 {
    public static T GetSetApplicationState<T>(this HttpApplicationState appState, string objectName, object objectValue = null, int syncCheckMinutes = 0)
    {
        T retVal = default(T);
        appState.Lock();
        if (appState[objectName + "LastSync"] == null || DateTime.Now.Subtract(((DateTime)appState[objectName + "LastSync"])).TotalMinutes >= syncCheckMinutes)
        {
            appState[objectName + "LastSync"] = DateTime.Now;

            if (objectValue != null)
                appState[objectName] = objectValue;
        }
        if (appState[objectName] != null)
            retVal = (T)appState[objectName];
        appState.UnLock();
        return retVal;
    }
    public static object GetSetApplicationState(this HttpApplicationState appState, string objectName, object objectValue = null, int syncCheckMinutes = 0)
    {
        object retVal = null;
        appState.Lock();
        if (appState[objectName + "LastSync"] == null || DateTime.Now.Subtract(((DateTime)appState[objectName + "LastSync"])).TotalMinutes >= syncCheckMinutes)
        {
            appState[objectName + "LastSync"] = DateTime.Now;

            if (objectValue != null)
                appState[objectName] = objectValue;
        }
        if (appState[objectName] != null)
            retVal = appState[objectName];
        appState.UnLock();
        return retVal;
    }
    public static void SetApplicationState(this HttpApplicationState appState, string objectName, object objectValue, int syncCheckMinutes = 0)
    {
        appState.Lock();
        if (appState[objectName + "LastSync"] == null || DateTime.Now.Subtract(((DateTime)appState[objectName + "LastSync"])).TotalMinutes >= syncCheckMinutes)
        {
            appState[objectName + "LastSync"] = DateTime.Now;
            appState[objectName] = objectValue;
        }
        appState.UnLock();
    }
    public static object GetApplicationState(this HttpApplicationState appState, string objectName)
    {
        object retVal = null;
        appState.Lock();
        if (appState[objectName] != null)
            retVal = appState[objectName];
        appState.UnLock();
        return retVal;
    }
    public static T GetApplicationState<T>(this HttpApplicationState appState, string objectName)
    {
        T retVal = default(T);
        appState.Lock();
        if (appState[objectName] != null)
            retVal = (T)appState[objectName];
        appState.UnLock();
        return retVal;
    }
}

So I can set them from Global.asax.cs something like this

Application.SetApplicationState("UISiteTitle",paramHelper.GetUIConfigXML<XMLParams.UISiteOptions>("UISiteOptions")
                .SiteOptionCollection.Where(v => v.name.Equals("title", StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault().value););

or

var uiPermissions = Application.GetSetApplicationState<XMLParams.UIPermissions>("UIPermissions", paramHelper.GetUIConfigXML<XMLParams.UIPermissions>("UIPermissions"), 30);
dynamiclynk
  • 2,275
  • 27
  • 31
3

You can declare Application variables in Application_Start like this:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    RouteConfig.RegisterRoutes(RouteTable.Routes);

    var e = "Hello";
    Application["value"] = e;
}

To access this on controller write:

string appVar = HttpContext.Application["value"] as string;
Mark Bell
  • 28,985
  • 26
  • 118
  • 145
Rohul Amin
  • 261
  • 3
  • 5
2

Make a static class?

Svante Svenson
  • 12,315
  • 4
  • 41
  • 45
  • 1
    I find static classes work great under the MVC context, it also helps you get away from the app/session state idea. – Jeremy B. Feb 15 '10 at 14:31
  • @jeremy except the session state is specifically updated for use in MVC. I'd definitely support "getting away from" it in order to reduce the amount of state stored on the server, but it definitely still has a place in the framework. –  Feb 15 '10 at 14:45
  • 1
    application scope and static class are very different things. Though they can be interchanged in some situations. – kervin Sep 17 '10 at 17:21
  • 4
    Implementing application variables as static classes makes them difficult to mock in unit tests – Josh Noe Jul 16 '13 at 21:58
  • 2
    what if i want to store an initialized object? – Yasser Sinjab Sep 16 '14 at 12:48
  • Static classes can work, but be careful about thread safety for any static variables that might be modified by multiple requests. – DCShannon Mar 01 '15 at 00:54
  • how can you be sure that iis or whatever host you are running in doesn't flip threads on you? in which case your static things will be reset. – pmcilreavy Nov 19 '15 at 01:42
  • Static classes are a very bad idea if you want to run multiple servers or processes. – Doobi Dec 02 '15 at 22:57
0

Do they have Application Variables? Yes, MVC is a framework that sits on top of the normal asp.net framework.

I would however create a static class that uses a cache store as it's backing.

Brian
  • 4,974
  • 2
  • 28
  • 30