MemoryCache and multiple per call WCF services
1.the services are all hosted in the same app in IIS
the answer is yes if you are using MemoryCache.Default
as your default cache object
From MSDN
This property always returns a reference to the default cache instance. For typical application scenarios, only one instance of MemoryCache is required.
you could use it like the following
ObjectCache cache = MemoryCache.Default;
Is it possible to configure it in the following way
<system.runtime.caching>
<memoryCache>
<namedCaches>
<add name="Default" physicalMemoryLimitPercentage="20"/>
</namedCaches>
</memoryCache>
</system.runtime.caching>
from your others services instance you can access your memory cache like the following
List<string> cacheKeys = MemoryCache.Default.Select(kvp => kvp.Key).ToList();
foreach (string cacheKey in cacheKeys)
MemoryCache.Default.Remove(cacheKey);
2.the services are hosted in different IIS applications on the same server
this will be a bit tricky but it will remains a valid option you can create a dedicated webservice for caching that can be used by others webservices using the netnamedPipeBinding
given that are on the same server
How to add caching to my MVC Application and WCF Service
To cache data from WCF service, you should have a Cache layer first. Sample code:
using System.Runtime.Caching;
public class CacheManager
{
private static MemoryCache _cache = MemoryCache.Default;
public static void AddToCache<T>(string key, T value)
{
_cache[key] = value;
}
public static T GetFromCache<T>(string key)
{
return (T)_cache[key];
}
public static void RemoveFromCache(string key)
{
_cache.Remove(key);
}
}
Then use it in your data layer, eg:
public List<Top_100_Result> GetTopProductsByTypeName()
{
var products = CacheManager.GetFromCache<List<Top_100_Result>>("TOP_100_RESULT");
//Add to cache if not existed
if (products == null)
{
using (EmbraceEntities ctx = new EmbraceEntities())
{
var productObjects = ctx.Top_100(null);
products = new List<Top_100_Result>(productObjects.Distinct());
CacheManager.AddToCache<List<Top_100_Result>>("TOP_100_RESULT", products);
}
}
return products;
}
You should also clear cache to refresh the data as soon as the cache data becomes invalid.
CacheManager.RemoveFromCache("TOP_100_RESULT");
WCF channel Factory caching
This is a complex topic with a lot of details to go over, but here it goes.
First, as a general rule you should be caching a ChannelFactory
and not an individual Channel
. A ChannelFactory
is expensive to construct as well as thread-safe so it is a great candidate for caching. A Channel
is cheap to construct and it is generally recommended to only create channels on an as-needed basis and to close them as early as possible. Additionally, when you cache a Channel
then you have to worry about it timing out which will cause it to fault which invalidates the entire benefit of caching it in the first place.
The article you linked to by Michele Leroux Bustamante is one of the best resources out there. As she states, there are differences to consider between Windows clients and server-side clients. Mostly only Windows clients benefit from caching as typically the credentials differ from thread to thread on server-side clients. For your typical Windows clients, there are two main options: Caching the references yourself or leveraging the MRU cache.
Leveraging the MRU cache: Essentially this means that you are letting Microsoft take the wheel. The ClientBase
class will use an MRU cache for the internal ChannelFactory
instance. The caching behavior is controlled via a CacheSetting
property and by default caching will be disabled if any of the "security-sensitive" properties are accessed. ClientBase
properties which will invalidate and remove a ChannelFactory
from the MRU cache when accessed include the Endpoint
, ClientCredentials
or the ChannelFactory
itself. There is a way to override this behavior by setting the CacheSettings
property to CacheSettings.AlwaysOn
. Additionally, if the Binding
is run-time defined then the ChannelFactory
is no longer a candidate for the MRU cache. See more details here.
Caching the references yourself: This means that you are going to keep a collection of ChannelFactory
references yourself. The snippet you provide in your question uses this approach. The best approach I have ever seen and admittedly use a modified version of at work is by Darin Dimitrov via this related SO question. For those of us who like to have more fine-grained control over the caching mechanism then this is the approach to use. This is typically used when credentials must be set at run-time like is often required by internet services.
Quite similarly, client proxies can be cached to improve performance - Wenlong Dong has an article about this topic.
(Update) Server-side clients as noted before are quite limited in their options when it comes to ChannelFactory
caching. For this brief discussion, we will assume that our deployment scenario looks like this:
Client -> Service A -> Service B
The most likely method to use in order to leverage ChannelFactory
caching in this scenario is to cache the references yourself for the session between the Client and Service A. This way Service A does not have to construct a different ChannelFactory
instance every time Service A needs to call into Service B. However, if the properties of the ChannelFactory
need change for each call, then this is no longer going to be appropriate.
Of course this also holds if Service A is a Singleton and each call to the downstream service (Service B) does not require new credentials, but Singleton services have their own set of performance problems.
Caching WCF Service based on output
if (_inquiryview.ValidTest == "1")
{
HttpContext context = HttpContext.Current;
HttpCachePolicy cachePolicy = HttpContext.Current.Response.Cache;
cachePolicy.SetCacheability(HttpCacheability.ServerAndPrivate);
cachePolicy.SetExpires(DateTime.Now.AddDays(15));
cachePolicy.VaryByHeaders["Accept"] = true;
cachePolicy.VaryByHeaders["Accept-Charset"] = true;
cachePolicy.VaryByHeaders["Accept-Encoding"] = true;
cachePolicy.VaryByParams["*"] = true;
cachePolicy.SetValidUntilExpires(true);
}
Related Topics
Memcached with Windows and .Net
How to I Apply Filter While Paginating in ASP.NET MVC and Entity Framework
How to Translate Cultureinfo Language Names
Why Folderbrowserdialog Dialog Does Not Scroll to Selected Folder
Rotate - Transposing a List<List<String>> Using Linq C#
Why Is Infinity Printed as "8" in the Windows 10 Console
What's the Difference Between Using the Serializable Attribute & Implementing Iserializable
How to Register a .Net Com Dll with Regsvr32
How to Get the Correct Ip from Http_X_Forwarded_For If It Contains Multiple Ip Addresses
Print List of Objects to Console
How to Define Implicit Conversions of Enums in C#
ASP.NET Core Content-Disposition Attachment/Inline
What to Use: Var or Object Name Type
How to Fill Forms and Submit with Webclient in C#
Static Property Using Inotifypropertychanged. C#
Dataannotations: Recursively Validating an Entire Object Graph