C# 在 WCF 中缓存?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/922116/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Caching in WCF?
提问by Developer
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.
我正在构建 WCF 服务。我需要将参考数据存储在缓存中,每次我从方法接收到输入时我都会查找它......这样做的正确方法是什么?我还想为缓存定义一个过期策略,在特定时间间隔后使其失效。
回答by Ronald Wildenberg
You could take a look at Velocity. This is Microsoft's distributed in-memory caching framework. But this may be a little bit too beta...
回答by MrKurt
You can use System.Web.Cache (even if you're not in a web context), and that's what I'd do. It's basically a big, in memory hash table with some niceties for expiring contents.
您可以使用 System.Web.Cache(即使您不在网络环境中),这就是我要做的。它基本上是一个很大的内存哈希表,其中包含一些用于过期内容的细节。
回答by tomasr
There are many ways you can do this. One fairly easy is to host the System.Web.Cache object yourself and use that to store the reference data. There's a good example of that here: http://kjellsj.blogspot.com/2007/11/wcf-caching-claims-using.html
有很多方法可以做到这一点。一种相当简单的方法是自己托管 System.Web.Cache 对象并使用它来存储引用数据。这里有一个很好的例子:http: //kjellsj.blogspot.com/2007/11/wcf-caching-claims-using.html
回答by Zachary
The WCF REST Starter Kit has caching, here is an article about using it... with sample code.
WCF REST Starter Kit 有缓存,这里有一篇关于使用它的文章......带有示例代码。
回答by nologo
回答by Adam Bell
Rather than expiring the cache data every so often, you can actually just make sure to invalidate the cache whenever the underlying data you are caching changes.
与其经常使缓存数据过期,您实际上可以确保在您缓存的基础数据发生变化时使缓存失效。
See this example from info Q http://www.infoq.com/news/2011/04/Attribute-Caching
请参阅 info 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)
{
...
}
回答by Juozas Kontvainis
If you are using .NET 4, the recommended way is to use MemoryCache
如果您使用 .NET 4,推荐的方法是使用MemoryCache
回答by Sriwantha Attanayake
Any caching solution should address two basic problems
任何缓存解决方案都应该解决两个基本问题
1) Storage of cache items and retrieval
1) 缓存项的存储和检索
2) Cache invalidation
2)缓存失效
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.
由于 Http 缓存是一种众所周知的缓存,因此我不打算详细解释它。您可以在某些 Web 配置中单独使用 asp 兼容性属性,您将在其中获得缓存。
[AspNetCacheProfile("MyProfile")]
public Customer GetName(string id)
{
// ...
}
And the web config is like
而网络配置就像
<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>
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
但这并不适合大多数场景,尤其是当您有大型复杂对象要缓存时。例如我有一个情况,我想缓存一个系统生成的图像(操作合约的输出是一个依赖于输入的系统生成的图像)。在这种情况下,您必须实现自己的缓存。我使用了 Microsoft 企业库缓存块来满足我的所有缓存存储要求。但是,您仍然需要进行管道连接以将 Microsoft 企业库缓存块与您的 WCF 服务集成。首先,您必须拦截 WCF 通信通道以实现缓存。有关如何拦截 WCF 通信通道的详细讨论,请访问http://msdn.microsoft.com/en-us/magazine/cc163302.aspx. 这就是你如何为 WCF 缓存做管道
Step 0Let's say you have an operation contract as follows and you want to cache the item return by that method.
步骤 0假设您有一个如下的操作合同,并且您想缓存该方法返回的项目。
[OperationContract]
MyCompositeClass Rotate(int angle)
Step 1First 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.
步骤 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;
}
}
Step 2
第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; }
}
}
Step 3
第 3 步
Finally add your attribute above your service call
最后在您的服务调用上方添加您的属性
[OperationContract]
[MyCacheRegister(typeof(RotateCacher)]
MyCompositeClass Rotate(int angle)
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
企业库缓存块的配置超出了这个答案的范围。您可以使用以下链接进行学习。企业库的好处在于您可以使用现成的方法来扩展缓存策略。它内置了缓存过期和存储的方法。您还可以编写自己的缓存过期和存储策略。 http://www.codeproject.com/KB/web-cache/CachingApplicationBlock.aspx
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.
最后一件事,为了让您的企业库缓存工作,您需要添加以下配置详细信息。您还需要将相关的 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>
回答by Paul Fryer
If you're going to be scaling out to more than one server in a load balanced, stateless system, you'll want to design for use of a distributed cache. The main things to do here are:
如果您要在负载平衡的无状态系统中扩展到多台服务器,您将需要设计使用分布式缓存。这里要做的主要事情是:
Use both a local and distributed cache. Only put session or short lived stuff in the distributed cache, other stuff cache locally.
Set appropriate timeouts for items. This will vary depending on the type of information and how close to the source it needs to be.
Remove stuff from cache when you know it will be incontinent (like updates, deletes, etc).
Take care to design cache keys that are unique. Build a model of the type of information you plan to cache and use that as a template for building keys.
使用本地和分布式缓存。只将会话或短暂的东西放在分布式缓存中,其他东西在本地缓存。
为项目设置适当的超时。这将根据信息的类型以及它需要与来源的接近程度而有所不同。
当您知道它会失禁时从缓存中删除内容(例如更新、删除等)。
注意设计唯一的缓存键。构建您计划缓存的信息类型的模型,并将其用作构建密钥的模板。