2009-05-28 13 views
41

Sto costruendo un servizio WCF. Ho bisogno di memorizzare i dati di riferimento nella cache che cercherò ogni volta che riceverò input dal metodo ... Qual è il modo giusto per farlo? Vorrei anche definire una politica di scadenza per la cache che la invaliderà dopo un certo intervallo di tempo.Caching nella WCF?

+3

http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/8ee823e4-b592-475b-b916-883aeb9fed5b –

risposta

1

Si potrebbe dare un'occhiata a Velocity. Questa è la memoria in-memory distribuita da Microsoft caching framework. Ma questo potrebbe essere un po 'troppo beta ...

0

Puoi usare System.Web.Cache (anche se non sei in un contesto web), ed è quello che farei. È fondamentalmente una grande tabella di hash della memoria con alcune sottigliezze per i contenuti in scadenza.

+2

prendere questa o lasciare ...ma questo è direttamente da msdn: la classe Cache non è pensata per l'uso al di fuori delle applicazioni ASP.NET. È stato progettato e testato per l'utilizzo in ASP.NET per fornire il caching per le applicazioni Web. In altri tipi di applicazioni, ad esempio applicazioni console o applicazioni Windows Form, la memorizzazione nella cache di ASP.NET potrebbe non funzionare correttamente. –

0

Ci sono molti modi per farlo. È abbastanza semplice ospitare l'oggetto System.Web.Cache e utilizzarlo per memorizzare i dati di riferimento. C'è un buon esempio di questo qui: http://kjellsj.blogspot.com/2007/11/wcf-caching-claims-using.html

+2

Come ha osservato Simon, MS dice: "La classe Cache non è destinato ad essere utilizzato al di fuori di applicazioni ASP.NET. E 'stato progettato e testato per l'utilizzo in ASP.NET per fornire la memorizzazione nella cache per le applicazioni Web. In altri tipi di applicazioni, come ad esempio console applicazioni o applicazioni Windows Form, la memorizzazione nella cache di ASP.NET potrebbe non funzionare correttamente. " –

0

Invece di scadenza dei dati della cache di tanto in tanto, si può effettivamente solo fare in modo di invalidare la cache ogni volta che i dati sottostanti si sta caching modifiche.

Vedere questo esempio da informazioni 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) 
{ 
... 
} 
29

Se si utilizza .NET 4, il metodo consigliato è quello di utilizzare MemoryCache

+6

Dai un'occhiata a questo articolo per avere un esempio su come usarlo: http://pieterderycke.wordpress.com/2012/04/09/caching-in-wcf-services-part-1/ – MuSTaNG

+0

Magnifica soluzione, no xml, nessuna configurazione web. – Akli

+2

Assicurati di smaltire la memoria cache o avrai una buona perdita di memoria. Lo so ... questo mi è costato giorni della mia vita. –

27

Qualsiasi soluzione di caching dovrebbe affrontare due problemi fondamentali

1) Archiviazione degli elementi della cache e recupero

2) Cache invalidation

Poiché il caching Http è noto, non lo spiegherò in dettaglio. È possibile utilizzare l'attributo di compatibilità asp da solo con alcune configurazioni Web, dove si otterrà il caching in base al fascino.

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

E la configurazione web è come

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

Ma questo non è adatto per la maggior parte degli scenari soprattutto quando si hanno grandi oggetto complesso di cache. Ad esempio, ho avuto una situazione in cui volevo memorizzare nella cache un'immagine generata dal sistema (l'output del contratto operativo è un'immagine generata dal sistema che dipende dall'input). In tal caso, è necessario implementare la propria cache. Ho utilizzato i blocchi di memorizzazione nella cache della libreria aziendale Microsoft che hanno risolto tutti i requisiti di archiviazione nella cache. Tuttavia, è ancora necessario eseguire l'impianto idraulico per integrare il blocco di memorizzazione nella cache della libreria aziendale Microsoft con il servizio WCF. Per prima cosa devi intercettare il canale di comunicazione WCF per implementare la cache. Una discussione dettagliata su come intercettare il canale di comunicazione WCF può essere trovata a http://msdn.microsoft.com/en-us/magazine/cc163302.aspx. Questo è come si fa l'impianto idraulico per WCF caching

Basic Plumbing Architecture

Fase 0 Diciamo che hai un contratto di operazione come segue e si desidera memorizzare nella cache il ritorno dell'articolo da quel metodo.

[OperationContract] 
MyCompositeClass Rotate(int angle) 

Fase 1 In primo luogo è necessario registrare il cacher personalizzato in cantiere WCF. Per farlo userò un attributo in modo che possa decorare in modo piacevole la mia chiamata alla WCF secondo i principi di programmazione dell'aspetto.

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

Fase 2

poi si deve implementare il punto in cui verrà recuperato oggetto cache.

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

Fase 3

Infine aggiungere l'attributo sopra il servizio di chiamata

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

La configurazione del blocco di cache biblioteca impresa è oltre la portata di questa risposta. Puoi utilizzare il seguente link per apprenderlo. La cosa buona della libreria aziendale è che ti sei preparato per estendere la tua politica di caching. Ha integrato modalità per la scadenza e l'archiviazione della cache. È inoltre possibile scrivere la propria scadenza di cache e le politiche di archiviazione. http://www.codeproject.com/KB/web-cache/CachingApplicationBlock.aspx

Un'ultima cosa, per far funzionare la memorizzazione nella cache della tua biblioteca aziendale, è necessario aggiungere i seguenti dettagli di configurazione. È inoltre necessario aggiungere DLL rilevanti al riferimento del progetto.

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

Spero che tu non abbia intenzione di copiare e incollare questa risposta per ogni vecchia domanda di cache che trovi sul sito. Considera invece di contrassegnare alcune delle domande come duplicati. –

+0

beh, non sapevo che esistesse un'opzione del genere. come farlo? –

+0

C'è un link flag sotto ogni domanda. –

1

Se avete intenzione di essere fuori scala a più di un server in un carico bilanciato, sistema di apolide, si vorrà design for use of a distributed cache. Le cose principali da fare qui sono:

  1. Utilizzare sia una cache locale che distribuita. Solo mettere sessioni o short ha vissuto roba nella cache distribuita, altra roba cache localmente.

  2. Imposta i timeout appropriati per gli articoli. Questo può variare a seconda del tipo di informazione e quanto vicino alla fonte deve essere.

  3. Rimuovere elementi dalla cache quando si sa che sarà incontinente (come gli aggiornamenti , eliminazioni, ecc.).

  4. Fare attenzione a progettare chiavi cache univoche. Creare un modello del tipo di informazioni che si prevede di memorizzare nella cache e utilizzarlo come modello per le chiavi di costruzione .