2012-01-25 2 views
11

Мне нужно добавить функции кеширования и найти новый блестящий класс под названием MemoryCache. Тем не менее, я нахожу MemoryCache немного искалеченным, поскольку он (я нуждаюсь в функциональности регионов). Помимо прочего, мне нужно добавить что-то вроде ClearAll (region). Авторы приложили огромные усилия, чтобы поддерживать этот класс без поддержки регионов, код как:MemoryCache с поддержкой регионов?

if (regionName != null) 
{ 
throw new NotSupportedException(R.RegionName_not_supported); 
} 

летит почти в каждом виде. Я не вижу простого способа переопределить это поведение. Единственный способ добавить поддержку региона, о которой я могу думать, это добавить новый класс в качестве оболочки MemoryCache, а не как класс, который наследует MemoryCache. Затем в этом новом классе создайте словарь и позвольте каждому методу «буфер» регионировать. Звучит неприятно и неправильно, но в конце концов ...

Знаете ли вы, что лучше добавлять регионы в MemoryCache?

ответ

5

Вы можете создать более одного экземпляра MemoryCache, по одному для каждого раздела ваших данных.

http://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache.aspx:

вы можете создать несколько экземпляров класса MemoryCache для использования в одном приложении и в том же AppDomain, например

+0

, где лучшее место, чтобы создать экземпляр все эти новые экземпляры MemoryCache? Есть ли поставщик MemoryCache, где вы можете управлять всеми этими экземплярами? –

+0

@HenleyChiu Я не думаю, что в базовых библиотеках есть что-то. Просто используйте стандартные средства для совместного использования, например, например. статический, глобально видимый [ConcurrentDictionary ] (http://msdn.microsoft.com/en-us/library/dd287191.aspx) –

+2

Использование нескольких экземпляров «MemoryCache» может снизить эффективность кеширования в некоторых обстоятельства. См. Http://stackoverflow.com/questions/8463962/using-multiple-instances-of-memorycache – Nathan

9

Я знаю, что это долгое время, так как вы спрашивали об этом вопрос, поэтому на самом деле это не ответ на вас, а скорее дополнение для будущих читателей.

Я также был удивлен, обнаружив, что стандартная реализация MemoryCache НЕ поддерживает регионы. Это было бы так легко обеспечить сразу. Поэтому я решил обернуть MemoryCache в моем собственном простом классе, чтобы обеспечить функциональность, которая мне часто нужна.

Я прилагаю свой код, чтобы сохранить время для других, имеющих такую ​​же потребность!

/// <summary> 
/// ================================================================================================================= 
/// This is a static encapsulation of the Framework provided MemoryCache to make it easier to use. 
/// - Keys can be of any type, not just strings. 
/// - A typed Get method is provided for the common case where type of retrieved item actually is known. 
/// - Exists method is provided. 
/// - Except for the Set method with custom policy, some specific Set methods are also provided for convenience. 
/// - One SetAbsolute method with remove callback is provided as an example. 
/// The Set method can also be used for custom remove/update monitoring. 
/// - Domain (or "region") functionality missing in default MemoryCache is provided. 
/// This is very useful when adding items with identical keys but belonging to different domains. 
/// Example: "Customer" with Id=1, and "Product" with Id=1 
/// ================================================================================================================= 
/// </summary> 
public static class MyCache 
{ 
    private const string KeySeparator = "_"; 
    private const string DefaultDomain = "DefaultDomain"; 


    private static MemoryCache Cache 
    { 
     get { return MemoryCache.Default; } 
    } 

    // ----------------------------------------------------------------------------------------------------------------------------- 
    // The default instance of the MemoryCache is used. 
    // Memory usage can be configured in standard config file. 
    // ----------------------------------------------------------------------------------------------------------------------------- 
    // cacheMemoryLimitMegabytes: The amount of maximum memory size to be used. Specified in megabytes. 
    //        The default is zero, which indicates that the MemoryCache instance manages its own memory 
    //        based on the amount of memory that is installed on the computer. 
    // physicalMemoryPercentage: The percentage of physical memory that the cache can use. It is specified as an integer value from 1 to 100. 
    //        The default is zero, which indicates that the MemoryCache instance manages its own memory 
    //        based on the amount of memory that is installed on the computer. 
    // pollingInterval:    The time interval after which the cache implementation compares the current memory load with the 
    //        absolute and percentage-based memory limits that are set for the cache instance. 
    //        The default is two minutes. 
    // ----------------------------------------------------------------------------------------------------------------------------- 
    // <configuration> 
    // <system.runtime.caching> 
    //  <memoryCache> 
    //  <namedCaches> 
    //   <add name="default" cacheMemoryLimitMegabytes="0" physicalMemoryPercentage="0" pollingInterval="00:02:00" /> 
    //  </namedCaches> 
    //  </memoryCache> 
    // </system.runtime.caching> 
    // </configuration> 
    // ----------------------------------------------------------------------------------------------------------------------------- 



    /// <summary> 
    /// Store an object and let it stay in cache until manually removed. 
    /// </summary> 
    public static void SetPermanent(string key, object data, string domain = null) 
    { 
     CacheItemPolicy policy = new CacheItemPolicy { }; 
     Set(key, data, policy, domain); 
    } 

    /// <summary> 
    /// Store an object and let it stay in cache x minutes from write. 
    /// </summary> 
    public static void SetAbsolute(string key, object data, double minutes, string domain = null) 
    { 
     CacheItemPolicy policy = new CacheItemPolicy { AbsoluteExpiration = DateTime.Now + TimeSpan.FromMinutes(minutes) }; 
     Set(key, data, policy, domain); 
    } 

    /// <summary> 
    /// Store an object and let it stay in cache x minutes from write. 
    /// callback is a method to be triggered when item is removed 
    /// </summary> 
    public static void SetAbsolute(string key, object data, double minutes, CacheEntryRemovedCallback callback, string domain = null) 
    { 
     CacheItemPolicy policy = new CacheItemPolicy { AbsoluteExpiration = DateTime.Now + TimeSpan.FromMinutes(minutes), RemovedCallback = callback }; 
     Set(key, data, policy, domain); 
    } 

    /// <summary> 
    /// Store an object and let it stay in cache x minutes from last write or read. 
    /// </summary> 
    public static void SetSliding(object key, object data, double minutes, string domain = null) 
    { 
     CacheItemPolicy policy = new CacheItemPolicy { SlidingExpiration = TimeSpan.FromMinutes(minutes) }; 
     Set(key, data, policy, domain); 
    } 

    /// <summary> 
    /// Store an item and let it stay in cache according to specified policy. 
    /// </summary> 
    /// <param name="key">Key within specified domain</param> 
    /// <param name="data">Object to store</param> 
    /// <param name="policy">CacheItemPolicy</param> 
    /// <param name="domain">NULL will fallback to default domain</param> 
    public static void Set(object key, object data, CacheItemPolicy policy, string domain = null) 
    { 
     Cache.Add(CombinedKey(key, domain), data, policy); 
    } 




    /// <summary> 
    /// Get typed item from cache. 
    /// </summary> 
    /// <param name="key">Key within specified domain</param> 
    /// <param name="domain">NULL will fallback to default domain</param> 
    public static T Get<T>(object key, string domain = null) 
    { 
     return (T)Get(key, domain); 
    } 

    /// <summary> 
    /// Get item from cache. 
    /// </summary> 
    /// <param name="key">Key within specified domain</param> 
    /// <param name="domain">NULL will fallback to default domain</param> 
    public static object Get(object key, string domain = null) 
    { 
     return Cache.Get(CombinedKey(key, domain)); 
    } 

    /// <summary> 
    /// Check if item exists in cache. 
    /// </summary> 
    /// <param name="key">Key within specified domain</param> 
    /// <param name="domain">NULL will fallback to default domain</param> 
    public static bool Exists(object key, string domain = null) 
    { 
     return Cache[CombinedKey(key, domain)] != null; 
    } 

    /// <summary> 
    /// Remove item from cache. 
    /// </summary> 
    /// <param name="key">Key within specified domain</param> 
    /// <param name="domain">NULL will fallback to default domain</param> 
    public static void Remove(object key, string domain = null) 
    { 
     Cache.Remove(CombinedKey(key, domain)); 
    } 



    #region Support Methods 

    /// <summary> 
    /// Parse domain from combinedKey. 
    /// This method is exposed publicly because it can be useful in callback methods. 
    /// The key property of the callback argument will in our case be the combinedKey. 
    /// To be interpreted, it needs to be split into domain and key with these parse methods. 
    /// </summary> 
    public static string ParseDomain(string combinedKey) 
    { 
     return combinedKey.Substring(0, combinedKey.IndexOf(KeySeparator)); 
    } 

    /// <summary> 
    /// Parse key from combinedKey. 
    /// This method is exposed publicly because it can be useful in callback methods. 
    /// The key property of the callback argument will in our case be the combinedKey. 
    /// To be interpreted, it needs to be split into domain and key with these parse methods. 
    /// </summary> 
    public static string ParseKey(string combinedKey) 
    { 
     return combinedKey.Substring(combinedKey.IndexOf(KeySeparator) + KeySeparator.Length); 
    } 

    /// <summary> 
    /// Create a combined key from given values. 
    /// The combined key is used when storing and retrieving from the inner MemoryCache instance. 
    /// Example: Product_76 
    /// </summary> 
    /// <param name="key">Key within specified domain</param> 
    /// <param name="domain">NULL will fallback to default domain</param> 
    private static string CombinedKey(object key, string domain) 
    { 
     return string.Format("{0}{1}{2}", string.IsNullOrEmpty(domain) ? DefaultDomain : domain, KeySeparator, key); 
    } 

    #endregion 

} 
+1

Перечисление через MemoryCache неэффективно, так как оно блокирует весь кеш за время. Также ваш Clear() является линейным поиском, поэтому становится хуже с количеством элементов кеша линейно. Это лучшее решение: http://stackoverflow.com/a/22388943/220230 – Piedone

+0

Спасибо, что заметили это. В данном простом примере я теперь удалил метод Clear, чтобы избежать других заблуждений. Для тех, кому действительно нужен способ удаления вручную по регионам, я ссылаюсь на данную ссылку. –

0

Другой подход заключается в реализации оболочки вокруг MemoryCache, которая реализует регионы, составляя ключ и имя региона, например.

public interface ICache 
{ 
... 
    object Get(string key, string regionName = null); 
... 
} 

public class MyCache : ICache 
{ 
    private readonly MemoryCache cache 

    public MyCache(MemoryCache cache) 
    { 
     this.cache = cache. 
    } 
... 
    public object Get(string key, string regionName = null) 
    { 
     var regionKey = RegionKey(key, regionName); 

     return cache.Get(regionKey); 
    } 

    private string RegionKey(string key, string regionName) 
    { 
     // NB Implements region as a suffix, for prefix, swap order in the format 
     return string.IsNullOrEmpty(regionName) ? key : string.Format("{0}{1}{2}", key, "::", regionName); 
    } 
... 
} 

Это не идеальный вариант, но он подходит для большинства случаев использования.

Я реализовал это, и он доступен в виде пакета NuGet: Meerkat.Caching

Смежные вопросы