7

I have this in my Application_Start:

var crumbsCache = new MemoryCache("breadCrumbsNames");
var crumbsList = new List<CacheItem>
                    {
                        //list of new CacheItem();
                    };
foreach (var cacheItem in crumbsList)
{
    crumbsCache.Add(cacheItem, new CacheItemPolicy());
}

Now, in my controllers i am doing this:

var cache = new MemoryCache("breadCrumbsNames");
var cacheItem = cache.GetCacheItem("nameOfCacheItem");

But then cacheItem is always null, what am I doing wrong?

1

2 Answers 2

12

I think a better option for you would be to use Ninject or some other dependency injection framework to inject your MemoryCache into the controllers as needed.

You will begin by adding Ninject and Ninject.Mvc3 (and any other related bits) to your ASP.NET MVC project. If you are working in Visual Studio, you can use NuGet to do that. It is quite painless and well-automated.

The next step will be to wrap your MemoryCache into some kind of a interface, such as:

public interface IMemoryCacheService
{
    MemoryCache MemoryCache
    {
        get;
        set;
    }
}

And:

public class MemoryCacheService : IMemoryCacheService
{
    public MemoryCacheService()
    {
        MemoryCache = new MemoryCache();
    }

    public MemoryCache MemoryCache
    {
        get;
        set;
    }
}

Then you define a binding within Ninject so that Ninject knows that when you need something of type IMemoryCacheService, it should give you the instance of MemoryCacheService.

I will paste my own Ninject config class here. The one that will be created in your project will be very similar and will be in a folder called App_Start (which will be created automatically if you use NuGet). The class that Ninject creates by default is called NinjectWebCommon.

public static class NinjectConfig
{
    private static readonly Bootstrapper bootstrapper = new Bootstrapper();

    public static void Start()
    {
        DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
        DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));

        bootstrapper.Initialize(CreateKernel);
    }

    public static void Stop()
    {
        bootstrapper.ShutDown();
    }

    private static IKernel CreateKernel()
    {
        var kernel = new StandardKernel();

        kernel.Bind<Func<IKernel>>()
              .ToMethod(context => () => new Bootstrapper().Kernel);
        kernel.Bind<IHttpModule>()
              .To<HttpApplicationInitializationHttpModule>();
        kernel.RegisterServices();

        return kernel;
    }

    private static void RegisterServices(this IKernel kernel)
    {
        kernel.Bind<IMemoryCacheService>()
              .To<MemoryCacheService>()
              .InSingletonScope();
              // InSingletonScope() is important so Ninject knows
              // to create only one copy and then reuse it every time
              // it is asked for

        // ignore the stuff below... I have left it in here for illustration
        kernel.Bind<IDbTransactionFactory>()
              .To<DbTransactionFactory>()
              .InRequestScope();
        kernel.Bind<IDbModelContext>()
              .To<DbModelContext>()
              .InRequestScope();
        kernel.Bind<IDbModelChangeContext>()
              .To<DbModelChangeContext>()
              .InRequestScope();
        kernel.Bind<IUserContext>()
              .To<UserContext>()
              .InRequestScope();

        kernel.BindAttributeAndFilter<IgnoreNonAjaxRequestsFilter, IgnoreNonAjaxRequestsAttribute>();
        kernel.BindAttributeAndFilter<ProvideApplicationInfoFilter, ProvideApplicationInfoAttribute>();
        kernel.BindAttributeAndFilter<ProvideSessionInfoFilter, ProvideSessionInfoAttribute>();
        kernel.BindAttributeAndFilter<UseDialogLayoutFilter, UseDialogLayoutAttribute>();
        kernel.BindAttributeAndFilter<CheckResourceAccessFilter, CheckResourceAccessAttribute>();
        kernel.BindAttributeAndFilter<CheckResourceStateFilter, CheckResourceStateAttribute>();
    }

    private static void BindAttributeAndFilter<TFilter, TAttribute>(this IKernel kernel)
    {
        kernel.BindFilter<TFilter>(FilterScope.Action, null)
              .WhenControllerHas<TAttribute>();
        kernel.BindFilter<TFilter>(FilterScope.Action, null)
              .WhenActionMethodHas<TAttribute>();
    }
}

Finally, your controllers will change from:

public class HomeController : Controller
{
    public ActionResult Foo()
    {
        ...
    }

    ...
}

to:

public class HomeController : Controller
{
    private IMemoryCacheService memoryCacheService;

    public HomeController(IMemoryCacheService memoryCacheService)
    {
        this.memoryCacheService = memoryCacheService;
    }

    public ActionResult Foo()
    {
        // use this.memoryCacheService in your controller methods...
    }

    ...
}

Say, you made another service as well called IEmailService following the above-mentioned strategy, and you wanted IEmailService to be available in HomeController as well, then:

public class HomeController : Controller
{
    private IMemoryCacheService memoryCacheService;
    private IEmailService emailService;

    public HomeController(IMemoryCacheService memoryCacheService, IEmailService emailService)
    {
        this.memoryCacheService = memoryCacheService;
        this.emailService = emailService;
    }

    public ActionResult Foo()
    {
        // use this.memoryCacheService in your controller methods...
        // and also use this.emailService in your controller methods...
    }

    ...
}

Ninject will change the ASP.NET MVC controller factory to automatically provide the injected arguments to the controller constructors.

I think this sort of approach is better in the long run that keeping global variables, etc.

Sign up to request clarification or add additional context in comments.

3 Comments

I'm of the opinion this adds more overhead than value for most situations. [Edited to add: this may be appropriate for distributed caches.] Just use MemoryCache.Default as described by Ryan Byrne.
I wrote all of the above more to illustrate the right approach than to answer the specific question, if I am honest. The core problem was that the OP was trying to create an object in a controller (which would be per-request) whereas he needed a singleton. In general, we want to be injecting dependencies, rather than using static classes/properties.
Further, if you read the comment by the OP on Ryan Byrne's answer, it is quite clear that (probably unbeknownst to the OP) the OP is looking for a DI mechanism, rather than just a properly initialized global variable.
10

You are creating a new instance of MemoryCache in each controller. Since it is new there is nothing in it which is why you values are always null. You need to access the same instance that you created in Application_Start. Look into using MemoryCache.Default.

2 Comments

But what exactly is MemoryCache.Default? If i would set up two different instances of memcache, how would MemoryCache.Default know which one is default?
Set MemoryCache.Default equal to the instance you want to use.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.