在WCF中缓存?

我正在构建WCF服务。 我需要将参考数据存储在缓存中,每次从该方法接收输入时我都会对其进行查找...正确的方法是什么? 我还想为缓存定义一个过期策略,该策略将在一定时间间隔后使其失效。

Developer asked 2020-08-12T07:55:52Z
9个解决方案
30 votes

如果使用的是.NET 4,建议的方法是使用MemoryCache

Juozas Kontvainis answered 2020-08-12T07:55:59Z
28 votes

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

1)缓存项的存储和检索

2)缓存失效

由于Http缓存是众所周知的缓存,因此我将不对其进行详细说明。 您可以在某些Web配置中单独使用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/zh-cn/magazine/cc163302.aspx]中找到。这就是您进行WCF缓存的方法

Basic Plumbing Architecture

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

第三步

最后,将属性添加到服务调用上方

[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>
Sriwantha Attanayake answered 2020-08-12T07:57:22Z
1 votes

您可以看一下Velocity。 这是Microsoft的分布式内存中缓存框架。 但这可能有点beta ...

Ronald Wildenberg answered 2020-08-12T07:57:43Z
1 votes

这是一篇好文章:[http://cascadeofinsights.com/post/1410736927/introducing-attribute-based-caching]

nologo answered 2020-08-12T07:58:03Z
1 votes

如果要在负载平衡的无状态系统中扩展到多个服务器,则需要设计使用分布式缓存。 这里要做的主要事情是:

  1. 同时使用本地和分布式缓存。 只放会话或短居住在分布式缓存中的东西,其他东西在本地缓存。

  2. 为项目设置适当的超时。 这将取决于信息的类型以及与来源之间的距离。

  3. 当您知道快要失禁时(例如更新,删除等)。

  4. 注意设计唯一的缓存键。 建立模型您计划缓存的信息类型,并将其用作以下内容的模板:建筑钥匙。

Paul Fryer answered 2020-08-12T07:58:41Z
0 votes

您可以使用System.Web.Cache(即使您不在网络环境中),这就是我要做的。 它基本上是一个很大的内存哈希表,其中包含一些用于使内容过期的细节。

MrKurt answered 2020-08-12T07:59:01Z
0 votes

您可以通过多种方式执行此操作。 一种相当容易的方法是自己托管System.Web.Cache对象,并使用该对象存储参考数据。 这里有一个很好的例子:[http://kjellsj.blogspot.com/2007/11/wcf-caching-claims-using.html]

tomasr answered 2020-08-12T07:59:24Z
0 votes

WCF REST入门工具包具有缓存功能,这是一篇有关将其与示例代码一起使用的文章。

[HTTP://weblogs.asp.net/甘肃省西/archive/2008/10/29/adding-caching-to-WCF-restful-services-using-他和-rest-starter-kit.aspx]

Zachary answered 2020-08-12T07:59:49Z
0 votes

您实际上不必确保每当要缓存的基础数据发生更改时就使缓存无效,而不是使缓存数据如此频繁地到期。

从信息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)
{
 ...
}
Adam Bell answered 2020-08-12T08:00:13Z
translate from https://stackoverflow.com:/questions/922116/caching-in-wcf