问题
I have a WCF service that caches certain data and uses it to respond to web requests. To deal with this requirement, I made the service a Singleton (using InstanceContextMode.Single
and ConcurrencyMode.Multiple
(yes, it's threadsafe)).
I've tried to set the timeout of the service to its maximum using the following binding:
<binding name="WebHttpBinding" receiveTimeout="24.20:31:23.6470000">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="None" />
</security>
</binding>
My problem is that the service instance dies at unpredictable intervals, meaning the first web request to hit will cause the cache to get rebuilt (a very slow process).
Ideally, the cache would rebuild at a set time each day without having to get hit by a web request. I could set the app pool to recycle at a set time, but this still wouldn't resolve the issue of the service not getting instantiated until the first web request. I'd rather not have to make a little scheduled script that sends a request to the service, as that is kind of hacky.
Is there a better strategy for performing caching in a WCF service? What have others done here? Is there a best practice?
回答1:
There is an MSDN article on Caching Support for WCF Web HTTP Services, an excerpt is quoted below:
The .NET Framework version 4 enables you to use the declarative caching mechanism already available in ASP.NET in your WCF Web HTTP services. This allows you to cache responses from your WCF Web HTTP service operations. When a user sends an HTTP GET to your service that is configured for caching, ASP.NET sends back the cached response and the service method is not called. When the cache expires, the next time a user sends an HTTP GET, your service method is called and the response is once again cached..........
You might also want to look at:
- memcached
- Windows AppFabric
- NCache
- Caching Solutions
- WCF Caching Solution - Need Advice
- Also look at this on Velocity from Microsoft
回答2:
I have implemented caching at a higher layer inside the webservice.
This way you can decide when to invalidate the cache, and when to deserialize from disk.
To make sure the cache is built before the first webrequest, add some code to global.asax
to generate the cache upon load of the web server.
This is much simpler than doing it the "right way"
[OperationContract]
public void GetLargeComplexData();
public GetLargeComplexData()
{
// deserialize last cached data from db or file
...
// Verify the deserialized cache is not invalid
...
// if cache is invalid rebuild
...
//return cached data
...
}
回答3:
The receiveTimeout
isn't going to affect what you're trying to do. You should use AppFabric to keep your service always running. That way, whenever you recycle, AppFabric will automatically warm up your service. Just make sure that your cache gets built when your service is instantiated, not when it's first accessed.
回答4:
You can use IIS7 application warmup module
http://blogs.iis.net/thomad/archive/2009/10/14/now-available-the-iis-7-5-application-warm-up-module.aspx
回答5:
An option you can use is to move the cache out of the WCF service and into a dedicated cache service such as Memcached or use Microsoft AppFabric Caching
This allows you to separate the storage of cached data from the WCF service so you have more freedom in your architecture of how the data is managed and accessed.
来源:https://stackoverflow.com/questions/19036151/implementing-a-cache-in-a-wcf-service