缓存在WCF?缓存、WCF

2023-09-02 21:22:14 作者:╰把曾经 谱写成童話╮

我建立一个WCF服务。我需要存储的参考数据中,我将每一次我收到的方法输入时间查找缓存...什么是正确的方式来做到这一点?我也想定义一个特定的时间间隔后也将无效,缓存过期策略。

I am building a WCF service. I need to store reference data in the cache which I will look up every time I receive input from the method... What is the right way to do this? I would also like to define an expiration policy for the cache that will invalidate it after a certain time interval.

推荐答案

任何缓存解决方案应解决两个基本问题

Any caching solution should address two basic problems

的缓存项和检索的 1)存储

2)的缓存失效

由于HTTP缓存是一个众所周知的某个时刻,我不打算详细解释一下。您可以单独使用ASP的兼容性属性与一些网络配置,在那里你会得到缓存通过的魅力。

Since Http caching is a well known one I am not going to explain it in detail. You can use asp compatibility attribute alone with some web configuration, where you will get caching by charm.

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

和web配置就像

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

但是,这并不适合大多数情况下尤其是当您有大量复杂的对象缓存。比如我有一个情况下,我想缓存系统生成的图像(操作契约的输出是一个系统生成的图像依赖于输入)。 在这种情况下,你要实现你自己的缓存。我已经使用了解决我所有的缓存存储要求微软企业库缓存块。但是,你仍然需要做的管道与WCF服务集成微软的企业库缓存块。首先,你必须要拦截来实现高速缓存中的WCF通信信道。如何拦截WCF通信信道的详细讨论,可以在http://msdn.microsoft.com/en-us/magazine/cc163302.aspx. 这是你怎么做管道的WCF缓存

But this is not suitable for most scenarios especially when you have large complex object to cache. For example I had a situation where I wanted to cache a system generated image (the output of the operation contract is a system generated image that depends on the input). In such a case, you have to implement your own cache. I have used Microsoft enterprise library caching blocks that addressed all my caching storage requirements. However, you still need to do the plumbing to integrate Microsoft enterprise library caching block with your WCF service. First you have to intercept the WCF communication channel to implement the cache. A detail discussion of how to intercept the WCF communication channel can be found at http://msdn.microsoft.com/en-us/magazine/cc163302.aspx. This is how you do the plumbing for WCF caching

步骤0 比方说,你有一个经营合同如下,你要缓存的项目收益通过该方法。

Step 0 Let’s say you have an operation contract as follows and you want to cache the item return by that method.

[OperationContract]
MyCompositeClass Rotate(int angle)

第1步 首先,你必须注册您的自定义cacher的在WCF管道。要做到这一点,我想使用属性,以便按照方面定向编程原理,我可以很好地装点我的WCF调用。

Step 1 First you have to register your custom cacher in the WCF pipeline. To do that I am going to use an attribute so that I can nicely decorate my WCF call according to aspect orient programming principles.

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步

然后,你必须执行,其中的缓存对象将被检索的点。

Then you have to implement the point where cache object will be retrieved.

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步

最后补充一下上面的服务电话的属性。

Finally add your attribute above your service call

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

企业库缓存块的配置超出了这个答案的范围。您可以使用下面的链接来了解它。关于企业库的好处是,你得到现成的方法来扩展你的缓存策略。它内置的方式缓存过期和存储。你也可以写自己的缓存过期和存储策略。 http://www.$c$cproject.com/KB/web-cache/CachingApplicationBlock.aspx

The configuration of enterprise library caching block is beyond the scope of this answer. You can use following link to learn it. The good thing about enterprise library is that you get ready made ways to extend your caching policy. It has built in ways for cache expiry and storage. You also can write your own cache expiration and storage policies. http://www.codeproject.com/KB/web-cache/CachingApplicationBlock.aspx

最后一点,你让你的企业库缓存工作,你需要添加下面的配置详细信息。您还需要相关的DLL添加到您的项目引用。

One final thing, for you to get your enterprise library caching working you need to add following configuration details. You also need to add relevant dlls to your project reference.

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