2013-02-15 20 views
5

mam to w moim Application_Start:ASP.NET MVC i MemoryCache - jak z tego korzystać?

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

Teraz, w moim kontrolerów Robię to:

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

Ale wtedy cacheItem zawsze jest null, co robię źle?

+0

Sprawdź to http://www.deanhume.com/home/blogpost/object-caching----net -4/37 – Mate

Odpowiedz

8

Tworzysz nowe wystąpienie MemoryCache w każdym kontrolerze. Ponieważ jest nowy, nie ma w nim nic, dlatego wartości są zawsze zerowe. Musisz uzyskać dostęp do tego samego wystąpienia, które utworzyłeś w Application_Start. Sprawdź w użyciu MemoryCache.Default.

+0

Ale czym właściwie jest "MemoryCache.Default"? Gdybym ustawił dwa różne wystąpienia memcache, w jaki sposób "MemoryCache.Default" wiedziałby, który z nich jest domyślny? – ojek

+0

Ustaw MemoryCache.Wartość domyślna równa instancji, której chcesz użyć. –

10

Myślę, że lepszym rozwiązaniem byłoby użycie Ninject lub innej struktury wtrysku zależności, aby wprowadzić w razie potrzeby swój MemoryCache do kontrolerów.

Zaczniesz od dodania Ninject i Ninject.Mvc3 (i innych powiązanych bitów) do projektu ASP.NET MVC. Jeśli pracujesz w Visual Studio, możesz użyć NuGet, aby to zrobić. Jest dość bezbolesny i dobrze zautomatyzowany.

Następnym krokiem będzie owinąć MemoryCache do pewnego rodzaju interfejsu, takich jak:

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

oraz:

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

    public MemoryCache MemoryCache 
    { 
     get; 
     set; 
    } 
} 

Następnie należy zdefiniować wiązania wewnątrz Ninject tak że Ninject wie że gdy potrzebujesz czegoś typu IMemoryCacheService, powinieneś podać instancję MemoryCacheService.

Wkleję tutaj własną klasę konfiguracyjną Ninject. Ten, który zostanie utworzony w twoim projekcie, będzie bardzo podobny i znajdzie się w folderze o nazwie App_Start (który zostanie utworzony automatycznie, jeśli użyjesz NuGet). Klasa domyślnie tworzona przez program Ninject nosi nazwę 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>(); 
    } 
} 

Wreszcie kontrolery zmieni się z:

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

    ... 
} 

do:

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, dokonane innej usługi, jak również o nazwie IEmailService po wyżej wymienionej strategii, a ty chciał IEmailService być również dostępny w HomeController, a następnie:

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 zmieni fabrykę kontrolera ASP.NET MVC, aby automatycznie podawać wstrzyknięte argumenty do konstruktorów kontrolera.

Myślę, że ten rodzaj podejścia jest lepsze na dłuższą metę, że utrzymanie zmiennych globalnych itp

+3

Jestem zdania, że ​​w większości sytuacji zwiększa to obciążenie ogólne. [Edytowane w celu dodania: może to być odpowiednie dla rozproszonych pamięci podręcznych.] Po prostu użyj MemoryCache.Default zgodnie z opisem Ryana Byrne'a. –

+0

Napisałem wszystkie powyższe, aby zilustrować właściwe podejście, niż odpowiedzieć na konkretne pytanie, jeśli jestem szczery. Podstawowym problemem było to, że OP próbował stworzyć obiekt w kontrolerze (który byłby na żądanie), podczas gdy potrzebował singletonu. Ogólnie rzecz biorąc, chcemy używać zależności wstrzykiwania, zamiast używać statycznych klas/właściwości. –

+1

Co więcej, jeśli przeczytałeś komentarz OP o odpowiedzi Ryana Byrne'a, jest całkiem jasne, że (prawdopodobnie bez wiedzy o PO) PO szuka mechanizmu DI, a nie tylko poprawnie zainicjowanej zmiennej globalnej. –