3

All of the below relates to a ASP.NET c# app. I have a Singleton Settings MemoryCache that reads values from database on first access and caches these, then invalidates them using SQL Service Broker message and re-reads as required.

For the purposes of standard controllers, i create my Db Context in a request scope. However, this obviously means that i can't use the same context in the Settings Cache class, since that is a singleton and we have a scope collision.

At the moment, i ended up with two db contexts - the Controllers get it via IoC container, whereas a Singleton just creates it's own.

However, i am not satisfied with this approach (mostly due to the way i feel about two contexts, the cache doesn't set anything on the db hence concurrency is not an issue as much).

What is a better way to do it?

2
  • Why does the cache know about the database? Could you just cache the results of the DB call? Possibly doing so would allow you to use DI to create the class that sets up the cache with data.
    – psr
    Commented Jan 29, 2014 at 1:26
  • @psr the cache knows about the db cause i use SqlDependancy variant that allows the cache to be invalidated automatically when data in the db changes (using SQL Broker)
    – zaitsman
    Commented Jan 30, 2014 at 8:17

2 Answers 2

3

You could split your cache implementation into 2 parts, a Cache and a CacheStorage.

The CacheStorage is only responsible for storing the cached data, and has a Singleton lifetime. Because it may be accessed by multiple threads concurrently, it should be thread-safe.

The Cache is the dynamic part of the caching mechanism, it has a PerRequest lifecycle and depends on both the CacheStorage and the DbContext. It is responsible for reading the settings from the DbContext on first access and updating the CacheStorage's data with it.

This way, the CacheStorage can be kept on for the duration of the application, and the Cache gets instantiated only when there's a valid DbContext available.

0

The DbContext is not thread safe so you should not use a singleton DbContext in an ASP.NET web app. A thread per request is created and you'll start getting exceptions as soon as multiple users begin using your application.

It sounds like you're wrapping the cache in another class that has its own DbContext. Why not just have that class take a DbContext in its constructor? Also, is there a reason you aren't using HttpContext.Current.Cache (Cache class)? That is the preferred way to Cache in ASP.NET (If you aren't using a 3rd party cache) and it will have the lifetime of the app domain. I'm fairly sure this solves all of your singleton and 2 DbContext issues.

According to Microsoft

The MemoryCache class is similar to the ASP.NET Cache class. The MemoryCache class has many properties and methods for accessing the cache that will be familiar to you if you have used the ASP.NET Cache class. The main differences between the Cache and MemoryCache classes are that the MemoryCache class has been changed to make it usable by .NET Framework applications that are not ASP.NET applications. For example, the MemoryCache class has no dependencies on the System.Web assembly. Another difference is that you can create multiple instances of the MemoryCache class for use in the same application and in the same AppDomain instance.

source

4
  • the first part of your message has puzzled me. Separating the DbContext and Cache problem - Should i or should i not create DbContext per request?
    – zaitsman
    Commented Dec 30, 2013 at 0:16
  • 1
    You should create a new DbContext per request. IIS/ASP.NET uses new threads to serve requests and the DbContext isn't thread safe. Even if you aren't explicitly creating new threads, your singleton DbContext will have multiple threads operating on it. If multiple users are using your website at the same time, you will run into issues. A static DbContext variable won't work. See these links : stackoverflow.com/questions/6126616/is-dbcontext-thread-safe stackoverflow.com/questions/1416351/…
    – brian
    Commented Dec 30, 2013 at 0:21
  • i guess you misunderstood the question. The singleton in the picture is the SettingsCache class; the class creates and disposes of manually retained context when the data is read; the data is then stored in cache; there is no updates from this singleton class. The trigger for this, however, is the SqlDependency, created by the getter of the property. The dependency connection is maintained by .net and is not explicit. The dbcontexts that operate with the actual data via controller actions are managed in the HttpRequest scope, just as you suggested.
    – zaitsman
    Commented Dec 30, 2013 at 1:04
  • @zaitsman: If the question has to be explained it's better to edit the question, so others don't have to search the comments. It's common in SO to have to edit the question before it's clear enough.
    – david.pfx
    Commented Mar 30, 2014 at 3:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.