2014-06-26 30 views
1

我寫了一個使用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(); 
     } 

    } 
} 

回答

4

我想這是你所期待的。

[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(); 
} 
+0

謝謝:)它按預期工作。 –