42 votes

Mise en cache dans WCF

Je suis en train de construire un service WCF, j'ai besoin de stocker des données de référence dans un cache que je consulterai à chaque fois que je recevrai une entrée de la méthode... Quelle est la bonne façon de faire cela ? (J'aimerais également définir une politique d'expiration pour le cache qui l'invalidera après un certain intervalle de temps).

30voto

Juozas Kontvainis Points 3294

Si vous utilisez .NET 4, la méthode recommandée est d'utiliser MemoryCache

28voto

Toute solution de mise en cache doit répondre à deux problèmes fondamentaux

1) Stockage des éléments du cache et récupération

2) Invalidation du cache

Comme la mise en cache Http est bien connue, je ne vais pas l'expliquer en détail. Vous pouvez utiliser l'attribut de compatibilité asp seul avec une certaine configuration web, où vous obtiendrez la mise en cache par le charme.

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

Et le web config est comme

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

Mais cela ne convient pas à la plupart des scénarios, surtout lorsque vous avez de gros objets complexes à mettre en cache. Par exemple, j'ai eu une situation où je voulais mettre en cache une image générée par le système (la sortie du contrat d'opération est une image générée par le système qui dépend de l'entrée). Dans un tel cas, vous devez implémenter votre propre cache. J'ai utilisé les blocs de cache de la bibliothèque d'entreprise de Microsoft qui ont répondu à tous mes besoins de stockage en cache. Cependant, vous devez encore faire la plomberie pour intégrer le bloc de mise en cache de la bibliothèque d'entreprise de Microsoft avec votre service WCF. Tout d'abord, vous devez intercepter le canal de communication WCF pour mettre en œuvre le cache. Une discussion détaillée sur la façon d'intercepter le canal de communication WCF peut être trouvée à l'adresse suivante http://msdn.microsoft.com/en-us/magazine/cc163302.aspx . C'est comment vous faites la plomberie pour le cache de WCF

Basic Plumbing Architecture

Étape 0 Disons que vous avez un contrat d'opération comme suit et que vous voulez mettre en cache l'élément renvoyé par cette méthode.

[OperationContract]
MyCompositeClass Rotate(int angle)

Étape 1 D'abord vous devez enregistrer votre cacheur personnalisé dans le pipeline WCF. Pour ce faire, je vais utiliser un attribut afin de pouvoir décorer joliment mon appel WCF selon les principes de la programmation orientée aspect.

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

Étape 2

Ensuite, vous devez implémenter le point où l'objet du cache sera récupéré.

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

Étape 3

Enfin, ajoutez votre attribut au-dessus de votre appel de service

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

La configuration du bloc de mise en cache des bibliothèques d'entreprise dépasse le cadre de cette réponse. Vous pouvez utiliser le lien suivant pour l'apprendre. L'avantage de la bibliothèque d'entreprise est que vous disposez de moyens prêts à l'emploi pour étendre votre politique de mise en cache. Elle dispose de moyens intégrés pour l'expiration et le stockage du cache. Vous pouvez également écrire vos propres politiques d'expiration du cache et de stockage. http://www.codeproject.com/KB/web-cache/CachingApplicationBlock.aspx

Une dernière chose, pour que la mise en cache de votre bibliothèque d'entreprise fonctionne, vous devez ajouter les détails de configuration suivants. Vous devez également ajouter les dlls pertinentes à la référence de votre projet.

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

1voto

Ronald Wildenberg Points 18258

Vous pourriez jeter un coup d'œil à Vélocité . Il s'agit du système distribué en mémoire de Microsoft. cadre de mise en cache . Mais c'est peut-être un peu trop bêta...

1voto

nologo Points 898

1voto

Paul Fryer Points 2008

Si vous envisagez de passer à plus d'un serveur dans un système sans état et à charge équilibrée, vous voudrez conception pour l'utilisation d'un cache distribué . Les principales choses à faire ici sont :

  1. Utilisez un cache local et un cache distribué. Ne mettez que les sessions ou les dans le cache distribué, les autres trucs dans le cache local.

  2. Définissez des délais d'attente appropriés pour les éléments. Cela variera en fonction du type d'information et de la proximité de la source.

  3. Supprimez des éléments du cache lorsque vous savez qu'ils seront incontinents (comme les mises à jour, suppressions, etc).

  4. Veillez à concevoir des clés de cache qui soient uniques. Construisez un modèle du type d'information que vous prévoyez de mettre en cache et utilisez-le comme modèle pour construire des clés.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X