0

I setup a Configuration model that stores a set of (essentially) Key => Value pairs that can be edited by the end user.

To make things easier I setup a static AppSettings class to make calling these easier throughout the app. (config values are never created or destroyed by the end user, only modified).

So what we have is (note - some of this has been removed for brevity):

Initializer

var configurations = new List<Configuration>
{
    new Configuration{ Key="CurrentGameID", Value="1" },
    new Configuration{ Key="AllowedStudentSpaces", Value="2" },
    new Configuration{ Key="WelcomeMessage", Value="Howdy, users" },
};
configurations.ForEach(c => context.Configurations.Add(c));
context.SaveChanges();

Helper

public static class AppSettings
{
    private static MyContext db = new MyContext();

    public static int CurrentGameID
    {
        get
        {
            var configuration = db.Configurations.FirstOrDefault(c => c.ID == (int)ConfigIDs.CurrentGame);
            return Convert.ToInt32(configuration.Value);
        }
    }

    public static int AllowedStudentSpaces
    {
        get
        {
            var configuration = db.Configurations.FirstOrDefault(c => c.ID == (int)ConfigIDs.AllowedStudentSpaces);
            return Convert.ToInt32(configuration.Value);
        }
    }

    public static string WelcomeMessage
    {
        get
        {
            var configuration = db.Configurations.FirstOrDefault(c => c.ID == (int)ConfigIDs.WelcomeMessage);
            return configuration.Value;
        }
    }
}

enum ConfigIDs
{
    CurrentGame = 1,
    AllowedStudentSpaces = 2,
    WelcomeMessage = 3
};

This should allow me to call whatever I need by doing something like:

<h1>@AppSettings.WelcomeMessage</p>

or

if(numSpaces < AppSettings.AllowedStudentSpaces)
{
 // Do work
}

That works great, but it appears that my app likes to cache the values returned by those calls when they are called using the AppSettings class. The updated values don't appear until I have cleared my session (by using a different browser or something). What causes that? Is there a way to circumvent it? Is there a better approach than what I am doing?

drewwyatt
  • 5,989
  • 15
  • 60
  • 106
  • 6
    What you are seeing is the behavior of the DBContext which you are holding a static reference to. You really want to create/destroy the context instance once PER REQUEST in MVC. The following suggests a way to do this without using Dependency Injection: http://stackoverflow.com/questions/6334592/one-dbcontext-per-request-in-asp-net-mvc-without-ioc-container – David Tansey Aug 13 '14 at 14:48

2 Answers2

2

Use System.Web.Mvc.OutputCacheAttribute you can create a custom attribute like this:

public class NoCacheAttribute : OutputCacheAttribute
{
    public NoCacheAttribute()
    {
        Location = OutputCacheLocation.None;
        NoStore = true;
        Duration = 0;
        VaryByParam = "None";
    }
}

And apply it on your Controller which should not use cache.

Major
  • 5,948
  • 2
  • 45
  • 60
1

You should set up a way to use a new DbContext with each page load. Right now the Configuration entities get attached once to the static DbContext's local and are not being reloaded from the database.

David Sherret
  • 101,669
  • 28
  • 188
  • 178
  • Calling dispose on DbContext isn't necessary. [This is a nice article about the subject](http://blog.jongallant.com/2012/10/do-i-have-to-call-dispose-on-dbcontext.html#.U-uIg5MvQZw) – rareyesdev Aug 13 '14 at 15:51
  • @agarwaen interesting. I just always assumed because it's IDisposable. – David Sherret Aug 13 '14 at 16:20
  • 2
    @agarwaen Be very very careful here, as this is a slipper slope. As the article even mentions, a derived DbContext may have it's own reasons to be disposed, so it's always good practice to dispose. You never know when someone might say, has this this class is disposable I'll put some managed things that also need to be disposed in this context, then when it isn't things go wrong (terribly wrong). – Erik Philips Aug 13 '14 at 16:26
  • @agarwaen: Apparently, calling Dispose on a DbContext isn't necessary _in the current release_. Since they implement IDisposable, they have the right to change the circumstances under which the Dispose call is truly necessary. They have the right to do that without consulting everyone who read that blog post. – John Saunders Aug 13 '14 at 16:29
  • @ErikPhilips I completely agree with you. I think that the reason why DbContext implements IDisposable is because EF is a very flexible API and you may try to override some default behaviors, if you do that then you may need to dispose the context manually. But John Saunders has a good point in his comment. Thanks for sharing it – rareyesdev Aug 13 '14 at 16:37