views:

2961

answers:

6

Context: .Net 3.5, C#
I'd like to have caching mechanism in my Console application.
Instead of re-inventing the wheel, I'd like to use System.Web.Caching.Cache (and that's a final decision, I can't use other caching framework, don't ask why).
However, it looks like System.Web.Caching.Cache is supposed to run only in a valid HTTP context. My very simple snippet looks like this:

using System;
using System.Web.Caching;
using System.Web;

Cache c = new Cache();

try
{
    c.Insert("a", 123);
}
catch (Exception ex)
{
    Console.WriteLine("cannot insert to cache, exception:");
    Console.WriteLine(ex);
}

and the result is:

cannot insert to cache, exception:
System.NullReferenceException: Object reference not set to an instance of an object.
   at System.Web.Caching.Cache.Insert(String key, Object value)
   at MyClass.RunSnippet()

So obviously, I'm doing something wrong here. Any ideas?


Update: +1 to most answers, getting the cache via static methods is the correct usage, namely HttpRuntime.Cache and HttpContext.Current.Cache. Thank you all!

+3  A: 

Just use the Caching Application Block if you don't want to reinvent the wheel. If you still want to use the ASP.NET cache- see here. I'm pretty sure this only works with .NET 2.0 and above though. It simply wasn't possible to use the cache outside of ASP.NET in .NET 1.

MSDN has a nice big warning on the page for the cache documentation too:

The Cache class is not intended for use outside of ASP.NET applications. It was designed and tested for use in ASP.NET to provide caching for Web applications. In other types of applications, such as console applications or Windows Forms applications, ASP.NET caching might not work correctly.

For a very lightweight solution, where you don't have to worry about expiration etc, then a dictionary object could suffice.

RichardOD
"see here" link is broken
Ron Klein
@Ron- that's a Stackoverflow bug. Here's a TinyUrl for the same link- http://tinyurl.com/ms35eu
RichardOD
+9  A: 

The documentation for the Cache constructor says that it is for internal use only. To get your Cache object, call HttpRuntime.Cache rather than creating an instance via the constructor.

Amit G
+1  A: 

Try

public class AspnetDataCache : IDataCache
{
    private readonly Cache _cache;

    public AspnetDataCache(Cache cache)
    {
        _cache = cache;
    }

    public AspnetDataCache()
        : this(HttpRuntime.Cache)
    {

    }
    public void Put(string key, object obj, TimeSpan expireNext)
    {
        if (key == null || obj == null)
            return;
        _cache.Insert(key, obj, null, DateTime.Now.Add(expireNext), TimeSpan.Zero);
    }

    public object Get(string key)
    {
        return _cache.Get(key);
    }

Hans Malherbe
A: 

The System.Web.Caching.Cache class relies on having its member "_cacheInternal" set by the HttpRuntime object.

To use the System.Web.Caching classes you'd have to create an HttpRuntime object and setup the HttpRuntime.Cache property. You'd effectively have to emulate IIS.

You're better off using other caching frameworks like:

d4nt
"The only way to set that is via internal methods " - not true, _cacheInternal is set by the static property accessor HttpRuntime.Cache. I would however be interested in more info on why MSDN recommends the ASP.NET Cache should not be used in-non web apps. I have code that uses it (which dates from before the existence of this warning), and it *seems* to work OK.
Joe
Thanks @Joe - edited my answer
d4nt
A: 

I ended on this page wondering the same thing. Here's what I'm doing (which I don't like but seems to work just fine):

        HttpContext context = HttpContext.Current;
        if (context == null)
        {
            HttpRequest request = new HttpRequest(string.Empty, "http://tempuri.org", string.Empty);
            HttpResponse response = new HttpResponse(new StreamWriter(new MemoryStream()));
            context = new HttpContext(request, response);
            HttpContext.Current = context;
        }
        this.cache = context.Cache;
Jim Rogers
+1  A: 

While the OP specified v3.5, the question was asked before v4 was released. To help anyone who finds this question and can live with a v4 dependency, the framework team created a new general purpose cache for this type of scenario. It's in the System.Runtime.Caching namespace: http://msdn.microsoft.com/en-us/library/dd997357%28v=VS.100%29.aspx

The static reference to the default cache instance is: MemoryCache.Default

Joel Fillmore
Thanks for the tip!
Ron Klein