我已经使用WCF编写了休息服务。该服务包含多个操作。有些是基于GET的([WebGet]
),有些是基于POST的([WebInvoke]
)。
该服务正在按预期工作。但是,基于GET的操作放在客户端缓存中,这对于所有操作都是不可取的。
经过一番搜索后,我找到了How to prevent the browser from caching WCF JSON responses。这是有效的,但我发现它不是非常可重复使用。
我的平台不允许我更新web.config。实际上,我的服务是SharePoint项目的一部分。并且更新web.config文件很难正确实现。这禁止我使用[WebCache]
属性。
所以我实现了一个自定义MessageInspector
来修复正确的标题:
public class CacheAttribute : Attribute, IServiceBehavior
{
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase host)
{
foreach (ChannelDispatcher cDispatcher in host.ChannelDispatchers)
{
foreach (EndpointDispatcher eDispatcher in cDispatcher.Endpoints)
{
eDispatcher.DispatchRuntime.MessageInspectors.Add(new CacheInspector(m_CacheEnabled, CacheDuration));
}
}
}
/*...
Other code omitted for brievty
*/
}
public class CacheInspector : IDispatchMessageInspector
{
/*...
Code omitted for brievety
*/
public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
var cache = HttpContext.Current.Response.Cache;
if (m_CacheEnabled)
{
cache.SetCacheability(HttpCacheability.Public);
cache.SetExpires(DateTime.UtcNow + CacheDuration.Value);
}
else
{
cache.SetExpires(DateTime.UtcNow.AddMinutes(-1));
cache.SetNoStore();
}
}
}
此代码按预期工作,但它适用于服务中的所有操作。
如何编写应用相同逻辑的基于属性的类,但是在操作范围?
我试图在IOperationBehavior
界面中找到有用的东西,但我找不到合适的实施方式。
完整代码(.net 4.5):
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
public class CacheAttribute : Attribute, IServiceBehavior
{
private readonly bool m_CacheEnabled;
public bool CacheEnabled { get { return m_CacheEnabled; } }
public TimeSpan? CacheDuration { get; set; }
public CacheAttribute(bool cacheEnabled)
{
this.m_CacheEnabled = cacheEnabled;
}
public CacheAttribute(TimeSpan cacheDuration) : this(true)
{
this.CacheDuration = cacheDuration;
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase host)
{
foreach (ChannelDispatcher cDispatcher in host.ChannelDispatchers)
{
foreach (EndpointDispatcher eDispatcher in cDispatcher.Endpoints)
{
eDispatcher.DispatchRuntime.MessageInspectors.Add(new CacheInspector(m_CacheEnabled, CacheDuration));
}
}
}
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
}
public class CacheInspector : IDispatchMessageInspector
{
private readonly bool m_CacheEnabled;
private readonly TimeSpan? CacheDuration;
public CacheInspector(bool m_CacheEnabled, TimeSpan? CacheDuration)
{
this.m_CacheEnabled = m_CacheEnabled;
this.CacheDuration = CacheDuration;
}
public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
{
return null;
}
public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
var cache = HttpContext.Current.Response.Cache;
if (m_CacheEnabled)
{
cache.SetCacheability(HttpCacheability.Public);
cache.SetExpires(DateTime.UtcNow + CacheDuration.Value);
}
else
{
cache.SetExpires(DateTime.UtcNow.AddMinutes(-1));
cache.SetNoStore();
}
}
}
答案 0 :(得分:5)
我认为这正是您所寻找的。 p>
[AttributeUsage(AttributeTargets.Method)]
public class CacheAttribute : Attribute, IOperationBehavior, IParameterInspector
{
public TimeSpan CacheLifetime { get; private set; }
public CacheAttribute(double lifetime)
{
this.CacheLifetime = TimeSpan.FromSeconds(lifetime);
}
#region IOperationBehavior Members
public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters) {}
public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation) {}
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
dispatchOperation.ParameterInspectors.Add(this);
}
public void Validate(OperationDescription operationDescription) {}
#endregion
#region IParameterInspector Members
public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
{
if (this.CacheLifetime == TimeSpan.Zero) {
WebOperationContext.Current.OutgoingResponse.Headers.Add("Cache-Control", "no-cache");
} else {
WebOperationContext.Current.OutgoingResponse.Headers.Add("Cache-Control", string.Format("max-age={0}",this.CacheLifetime.TotalSeconds));
}
}
public object BeforeCall(string operationName, object[] inputs)
{
return null;
}
#endregion
}
使用
[ServiceContract]
public interface ICacheTestService
{
[OperationContract]
[WebGet(UriTemplate = "CurrentTime")]
[Cache(0)]
string GetCurrentTime();
[OperationContract]
[WebGet(UriTemplate = "CurrentTimeCached")]
[Cache(30)]
string GetCurrentTimeCached();
[OperationContract]
[WebGet(UriTemplate = "CurrentTimeNoCC")]
string GetCurrentTimeNoCC();
}