Ответ 1
Если вы используете .NET 4, рекомендуется использовать MemoryCache
Я создаю службу WCF. Мне нужно хранить справочные данные в кеше, которые я буду искать каждый раз, когда получаю вход от метода... Каков правильный способ сделать это? Я также хотел бы определить политику истечения срока действия кэша, которая будет лишать ее права после определенного интервала времени.
Если вы используете .NET 4, рекомендуется использовать MemoryCache
Любое решение кэширования должно касаться двух основных проблем
1) Хранение элементов кэша и поиска
2) Недействительность кэша
Так как кэширование Http является хорошо известным, я не буду подробно объяснять его. Вы можете использовать только атрибут совместимости asp с некоторой веб-конфигурацией, где вы получите кеширование по очарованию.
[AspNetCacheProfile("MyProfile")]
public Customer GetName(string id)
{
// ...
}
И веб-конфиг похож на
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>
<system.web>
<caching>
<outputCacheSettings>
<outputCacheProfiles>
<add name=" MyProfile" duration="600" varyByParam="none" sqlDependency="MyTestDatabase:MyTable"/>
</outputCacheProfiles>
</outputCacheSettings>
</caching>
</system.web>
Но это не подходит для большинства сценариев, особенно когда у вас есть большой сложный объект для кеширования. Например, у меня была ситуация, когда я хотел кэшировать сгенерированное системой изображение (вывод рабочего контракта - это сгенерированное системой изображение, зависящее от ввода). В таком случае вы должны реализовать свой собственный кеш. Я использовал блоки кэширования корпоративной библиотеки Microsoft, которые учитывали все требования к кэшированию хранилища. Тем не менее, вам все равно нужно сделать сантехнику, чтобы интегрировать блок кэширования корпоративной библиотеки Microsoft с помощью службы WCF. Сначала вам нужно перехватить канал связи WCF для реализации кеша. Подробное обсуждение того, как перехватить канал связи WCF, можно найти на http://msdn.microsoft.com/en-us/magazine/cc163302.aspx. Так вы делаете сантехнику для кэширования WCF
Шаг 0 Допустим, у вас есть контракт на операцию следующим образом, и вы хотите кэшировать возвращаемый элемент этим методом.
[OperationContract]
MyCompositeClass Rotate(int angle)
Шаг 1 Сначала вам нужно зарегистрировать свой собственный кэшер в конвейере WCF. Для этого я собираюсь использовать атрибут, чтобы я мог красиво украсить мой вызов WCF в соответствии с принципами ориентации на аспект.
using System;
using System.ServiceModel.Description;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using System.Reflection;
[AttributeUsage(AttributeTargets.Method)]
public class MyCacheRegister : Attribute, IOperationBehavior
{
ConstructorInfo _chacherImplementation;
public ImageCache(Type provider)
{
if (provider == null)
{
throw new ArgumentNullException("Provider can't be null");
}
else if (provider.IsAssignableFrom(typeof(IOperationInvoker)))
{
throw new ArgumentException("The type " + provider.AssemblyQualifiedName + " does not implements the interface " + typeof(IOperationInvoker).AssemblyQualifiedName);
}
else
{
try
{
Type[] constructorSignatureTypes = new Type[1];
constructorSignatureTypes[0] = typeof(IOperationInvoker);
_chacherImplementation = provider.GetConstructor(constructorSignatureTypes);
}
catch
{
throw new ArgumentException("There is no constructor in " + provider.AssemblyQualifiedName + " that accept " + typeof(IOperationInvoker).AssemblyQualifiedName + " as a parameter");
}
}
}
public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
{
return;
}
public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
{
return;
}
/// <summary>
/// Decorate the method call with the cacher
/// </summary>
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
//decorator pattern, decorate with a cacher
object[] constructorParam = new object[1];
constructorParam[0] = dispatchOperation.Invoker;
dispatchOperation.Invoker = (IOperationInvoker)_chacherImplementation.Invoke(constructorParam);
}
public void Validate(OperationDescription operationDescription)
{
return;
}
}
Шаг 2
Затем вам нужно реализовать точку, в которой будет извлекаться объект кэша.
using System;
using System.ServiceModel.Dispatcher;
using Microsoft.Practices.EnterpriseLibrary.Caching;
using Microsoft.Practices.EnterpriseLibrary.Common;
using System.IO;
class RotateCacher : IOperationInvoker
{
private IOperationInvoker _innerOperationInvoker;
public RotateImageCacher(IOperationInvoker innerInvoker)
{
_innerOperationInvoker = innerInvoker;
}
public object[] AllocateInputs()
{
Object[] result = _innerOperationInvoker.AllocateInputs();
return result;
}
public object Invoke(object instance, object[] inputs, out object[] outputs)
{
object result=null;
///TODO: You will have more object in the input if you have more ///parameters in your method
string angle = inputs[1].ToString();
///TODO: create a unique key from the inputs
string key = angle;
string provider = System.Configuration.ConfigurationManager.AppSettings["CacheProviderName"];
///Important Provider will be DiskCache or MemoryCache for the moment
provider ="DiskCache";
///TODO: call enterprise library cache manager, You can have your own
/// custom cache like Hashtable
ICacheManager manager = CacheFactory.GetCacheManager(provider);
if (manager.Contains(key))
{
result =(MyCompositeClass) manager[key];
}
else
{
result =(MyCompositeClass) _innerOperationInvoker.Invoke(instance, inputs, out outputs);
manager.Add(key, result);
}
return result;
}
public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
{
IAsyncResult result = _innerOperationInvoker.InvokeBegin(instance, inputs, callback, state);
return result;
}
public object InvokeEnd(object instance, out object[] outputs, IAsyncResult asyncResult)
{
object result = _innerOperationInvoker.InvokeEnd(instance, out outputs, asyncResult);
return result;
}
public bool IsSynchronous
{
get { return _innerOperationInvoker.IsSynchronous; }
}
}
Шаг 3
Наконец, добавьте свой атрибут над своим служебным вызовом
[OperationContract]
[MyCacheRegister(typeof(RotateCacher)]
MyCompositeClass Rotate(int angle)
Конфигурация блока кэширования корпоративной библиотеки выходит за рамки этого ответа. Вы можете использовать следующую ссылку, чтобы узнать ее. Хорошая вещь в корпоративной библиотеке заключается в том, что вы получаете готовые способы расширения вашей политики кэширования. Он имеет встроенные возможности для истечения срока хранения и хранения кеша. Вы также можете написать свои собственные политики истечения срока хранения и хранения. http://www.codeproject.com/KB/web-cache/CachingApplicationBlock.aspx
Наконец, для того, чтобы вы могли работать с кэшированием своей корпоративной библиотеки, вам нужно добавить следующие данные конфигурации. Вам также необходимо добавить соответствующие DLL-ссылки в ссылку на проект.
<configSections>
<section name="cachingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Caching.Configuration.CacheManagerSettings, Microsoft.Practices.EnterpriseLibrary.Caching, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
</configSections>
<cachingConfiguration defaultCacheManager="Cache Manager">
<cacheManagers>
<add name="MemoryCache" type="Microsoft.Practices.EnterpriseLibrary.Caching.CacheManager, Microsoft.Practices.EnterpriseLibrary.Caching, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
expirationPollFrequencyInSeconds="60" maximumElementsInCacheBeforeScavenging="1000"
numberToRemoveWhenScavenging="10" backingStoreName="NullBackingStore" />
<add name="DiskCache" type="Microsoft.Practices.EnterpriseLibrary.Caching.CacheManager, Microsoft.Practices.EnterpriseLibrary.Caching, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
expirationPollFrequencyInSeconds="60" maximumElementsInCacheBeforeScavenging="1000"
numberToRemoveWhenScavenging="10" backingStoreName="IsolatedStorageCacheStore" />
</cacheManagers>
<backingStores>
<add type="Microsoft.Practices.EnterpriseLibrary.Caching.BackingStoreImplementations.NullBackingStore, Microsoft.Practices.EnterpriseLibrary.Caching, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
name="NullBackingStore" />
<add name="IsolatedStorageCacheStore" type="Microsoft.Practices.EnterpriseLibrary.Caching.BackingStoreImplementations.IsolatedStorageBackingStore, Microsoft.Practices.EnterpriseLibrary.Caching, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
encryptionProviderName="" partitionName="MyCachePartition" />
</backingStores>
</cachingConfiguration>
Вы можете взглянуть на Velocity. Это распределенная в Microsoft
это хорошая статья: http://cascadeofinsights.com/post/1410736927/introducing-attribute-based-caching
Если вы собираетесь масштабировать до более чем одного сервера в балансированной нагрузке системе без гражданства, вы захотите дизайн для использования распределенный кеш. Главное здесь:
Используйте как локальный, так и распределенный кеш. Только поставить сеанс или короткий в распределенном кеше, в другом кеше вещей.
Установите соответствующие тайм-ауты для элементов. Это зависит от тип информации и то, насколько близко к ее источнику.
Удалите вещи из кеша, когда вы знаете, что это будет недержанием (например, обновления, удаления и т.д.).
Позаботьтесь о создании уникальных кеш-ключей. Построить модель тип информации, которую вы планируете кэшировать, и использовать ее в качестве шаблона для ключи здания.
Вы можете использовать System.Web.Cache(даже если вы не в веб-контексте), и что я буду делать. Это в основном большая, в хэш-таблице памяти с некоторыми тонкостями для истечения срока содержания.
Есть много способов сделать это. Один довольно простой способ разместить объект System.Web.Cache самостоятельно и использовать его для хранения справочных данных. Вот хороший пример этого: http://kjellsj.blogspot.com/2007/11/wcf-caching-claims-using.html
В стартовом наборе WCF REST есть кеширование, вот статья об использовании его... с образцом кода.
Вместо того, чтобы выгружать данные кэша так часто, вы можете просто удостовериться в том, что вы будете недействительным кэшировать всякий раз, когда изменяются базовые данные, которые вы кэшируете.
См. этот пример из информации Q http://www.infoq.com/news/2011/04/Attribute-Caching
[Cache.Cacheable("UserTransactionCache")]
public DataTable GetAllTransactionsForUser(int userId)
{
return new DataProvider().GetAllTransactionsForUser(userId);
}
[Cache.TriggerInvalidation("UserTransactionCache")]
public void DeleteAllTransactionsForUser(int userId)
{
...
}