¿Almacenamiento en caché en WCF?

Estoy construyendo un servicio WCF. Necesito almacenar datos de referencia en el caché que buscaré cada vez que reciba información del método … ¿Cuál es la forma correcta de hacerlo? También me gustaría definir una política de caducidad para el caché que lo invalidará después de un cierto intervalo de tiempo.

Si está utilizando .NET 4, la forma recomendada es usar MemoryCache

Cualquier solución de almacenamiento en caché debe abordar dos problemas básicos

1) Almacenamiento de elementos de caché y recuperación

2) invalidación de caché

Como Http Caching es muy conocido, no voy a explicarlo en detalle. Puede usar el atributo de compatibilidad asp solo con alguna configuración web, donde obtendrá el almacenamiento en caché por encanto.

[AspNetCacheProfile("MyProfile")] public Customer GetName(string id) { // ... } 

Y la configuración web es como

             

Pero esto no es adecuado para la mayoría de los escenarios, especialmente cuando tiene un gran objeto complejo para caché. Por ejemplo, tuve una situación en la que quería almacenar en caché una imagen generada por el sistema (el resultado del contrato de operación es una imagen generada por el sistema que depende de la entrada). En tal caso, debe implementar su propio caché. He utilizado los bloques de caché de la biblioteca empresarial de Microsoft que abordan todos mis requisitos de almacenamiento en caché. Sin embargo, aún necesita hacer la instalación de tuberías para integrar el bloque de caché de la biblioteca empresarial de Microsoft con su servicio WCF. Primero, debe interceptar el canal de comunicación WCF para implementar el caché. Puede encontrar una discusión detallada sobre cómo interceptar el canal de comunicación WCF en http://msdn.microsoft.com/en-us/magazine/cc163302.aspx . Así es como se hace la plomería para el almacenamiento en caché de WCF

Arquitectura básica de fontanería

Paso 0 Supongamos que tiene un contrato de operación de la siguiente manera y desea almacenar en caché el artículo devuelto por ese método.

 [OperationContract] MyCompositeClass Rotate(int angle) 

Paso 1 Primero debe registrar su caché personalizado en la tubería de WCF. Para hacer eso, voy a usar un atributo para poder decorar mi llamada WCF de acuerdo con los principios de progtwigción de orientación de aspecto.

 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; } ///  /// Decorate the method call with the cacher ///  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; } } 

Paso 2

Luego debe implementar el punto donde se recuperará el objeto de caché.

 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; } } } 

Paso 3

Finalmente agregue su atributo arriba de su llamada de servicio

 [OperationContract] [MyCacheRegister(typeof(RotateCacher)] MyCompositeClass Rotate(int angle) 

La configuración del bloque de almacenamiento en caché de la biblioteca empresarial está fuera del scope de esta respuesta. Puede usar el siguiente enlace para aprenderlo. Lo bueno de la biblioteca empresarial es que te preparas para ampliar tu política de almacenamiento en caché. Ha construido formas de caducidad y almacenamiento de caché. También puede escribir sus propias políticas de caducidad y almacenamiento de caché. http://www.codeproject.com/KB/web-cache/CachingApplicationBlock.aspx

Una última cosa, para que funcione el almacenamiento en caché de su biblioteca empresarial, debe agregar los siguientes detalles de configuración. También necesita agregar dlls relevantes a su referencia de proyecto.

  

Podrías echarle un vistazo a Velocity . Este es el marco de caché en memoria distribuido de Microsoft. Pero esto puede ser un poco demasiado beta …

Si va a expandirse a más de un servidor en un sistema sin estado de equilibrio de carga, querrá diseñar para usar un caché distribuido . Las principales cosas que hacer aquí son:

  1. Use tanto un caché local como distribuido. Solo coloca cosas de sesión o de corta vida en la caché distribuida, otras cosas caché localmente.

  2. Establezca tiempos de espera adecuados para los artículos. Esto variará según el tipo de información y cuán cerca de la fuente debe estar.

  3. Elimine cosas de la memoria caché cuando sepa que serán incontinentes (como actualizaciones, eliminaciones, etc.).

  4. Tenga cuidado de diseñar claves de caché que sean únicas. Cree un modelo del tipo de información que planea almacenar en caché y utilícela como plantilla para construir claves.

Puedes usar System.Web.Cache (incluso si no estás en un contexto web), y eso es lo que haría. Básicamente es una gran tabla hash de memoria con algunas sutilezas para los contenidos que expiran.

Hay muchas formas en que puedes hacer esto. Una bastante fácil es alojar el objeto System.Web.Cache usted mismo y usarlo para almacenar los datos de referencia. Hay un buen ejemplo de eso aquí: http://kjellsj.blogspot.com/2007/11/wcf-caching-claims-using.html

El WCF REST Starter Kit tiene el almacenamiento en caché, aquí hay un artículo sobre su uso … con código de ejemplo.

http://weblogs.asp.net/gsusx/archive/2008/10/29/adding-caching-to-wcf-restful-services-using-the-rest-starter-kit.aspx

En lugar de caducar los datos de caché de vez en cuando, puede asegurarse de invalidar el caché cada vez que cambian los datos subyacentes que almacena en caché.

Vea este ejemplo de la información Q http://www.infoq.com/news/2011/04/Atribute-Caching

 [Cache.Cacheable("UserTransactionCache")] public DataTable GetAllTransactionsForUser(int userId) { return new DataProvider().GetAllTransactionsForUser(userId); } [Cache.TriggerInvalidation("UserTransactionCache")] public void DeleteAllTransactionsForUser(int userId) { ... }