wcf - How to add control the cache of a restful service operation by operation? -
i've written rest service using wcf. service contains several operations. based ([webget]
), others post based ([webinvoke]
).
the service working expected. however, based operations put in client cache, not desirable operations.
after bit search, i've found how prevent browser caching wcf json responses. working, found it's not reusable.
my platform not allows me update web.config. actually, service part of sharepoint project. , updating web.config file hard implement properly. forbid me use [webcache]
attribute.
so implemented custom messageinspector
fix proper headers:
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 brievty */ } public class cacheinspector : idispatchmessageinspector { /*... code omitted 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(); } } }
this code working expected, applies operations in service.
how can code attribute based class apply same logic, @ operation scope ?
i've tried find useful in ioperationbehavior
interface, did not find appropriate implementation.
full code (.net 4.5):
[attributeusage(attributetargets.class, inherited = false, allowmultiple = true)] public class cacheattribute : attribute, iservicebehavior { private readonly bool m_cacheenabled; public bool cacheenabled { { 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(); } } }
i think looking for.
[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 }
usage
[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(); }
Comments
Post a Comment