I am storing some information in static dictionary which is defined in class inside WCF service component like below :
public class UserAuthenticator : IUserAuthentication
{
public static ConcurrentDictionary<UserInfo, ConcurrentDictionary<string, BookingDetails>>BookingDetailsDictionary = new ConcurrentDictionary<UserInfo, ConcurrentDictionary<string, BookingDetails>>(new UserEqualityComparer());
public static ConcurrentDictionary<string, Connector> connectorDictionary = new ConcurrentDictionary<string, Connector>();
public BookingDetails Authenticate(UserInfo userInfo, ServiceDetails serviceDetail, XmlElement requestData)
{
var bookDetails = new BookingDetails();
try
{
ConcurrentDictionary<string, BookingDetails> dicObject = null;
if (bookingDictionary.TryGetValue(userInfo, out dicObject))
{...}
else
{
// call Database and get value from database and fill db value in to static ConcurrentDictionary
}
}
}
}
Here I check static ConcurrentDictionary key if value in the not in dictionary then call database and fill value in the dictionary.
Expected output is first time invoke wcf service then call database and fill value in the ConcurrentDictionary and then after all the WCF service call read data from ConcurrentDictionary
Now, problems is sometimes I see that the static ConcurrentDictionary count are zeroed. And the strange part is the application pool is still active. no application pool is recycle still randomly it call database and sometime it take data from ConcurrentDictionary
This is really strange for me. I assume that static variable will hold its value until the application ends. But even the application pool did not recycle or IIS is not restarted, the static variable is zeroed.
What do you suggest? Is using ConcurrentDictionary variables a better choice?
Note : I have used castle windsor dependency injection in my wcf application and UserAuthenticator class is register with LifestyleTransient() like below
Component.For<IUserAuthentication, UserAuthenticator>().LifestyleTransient()
Please advice me the best solution
Thanks in advance
Finally I got solution of above problem
As I have used static ConcurrentDictionary in WCF project and also implemented web garden and static variables per process so its not working in another process some time with web gardern
Solution is as off now stopped wen garden and its working fine and in future will implement distributed cache like (Radis, NCache, etc) with web garden
Thanks to #mjwills and # Shantanu for valuable comments
Related
I am creating an ASP.NET MVC web application. It has service classes to execute business logic and it access data through Entity Framework.
I want to change some business logic based on application variable. These variables are global variables and load from app config and don't change after the initial loading.
public class BroadcastService : IBroadcastService
{
private static readonly ILog Logger = LogProvider.GetCurrentLogger();
private readonly IUnitOfWork _worker;
private readonly IGlobalService _globalService;
public BroadcastService(IUnitOfWork worker, IGlobalService globalService)
{
_worker = worker;
_globalService = globalService;
}
public IEnumerable<ListItemModel> GetBroadcastGroups()
{
if(Global.EnableMultiTenant)
{
//load data for all tenants
}
else
{
//load data for current tenant only
}
return broadcastGroups ?? new List<ListItemModel>();
}
...
}
public static class Global
{
public static bool EnableMultiTenant{get;set;}
}
For example, EnableMultiTenant will hold application is running in multi-tenant mode or not.
My concerns are:
Is it ok to use a static global variable class to holds those values?
This application is hosting on Azure app service with load balancing. Is there any effect when running multi-instance and when app pool restarts?
To answer your question as to whether it is 'okay' to do this, I think that comes down to you.
I think the biggest thing to know is when that data is going to get refreshed. From experience I believe that static information gets stored in the application pool, so if it is restarted then the information will be refreshed.
Lifetime of ASP.NET Static Variable
Consider how many times you need that information, if you only need it once at startup, is it worth having it as a static. If you are getting that information a lot (and say for example it is stored in a database) then it may be sensible to store that in a cache somewhere such as a static member.
I think my only recommendation with static member variables is asp is keep them simple, booleans seem fine to me. Remember that users do share the same application meaning that static variables are global for all users. If you want a user specific variable then you want to use sessions cache.
Always remember the two hardest thing in programming
Naming things
Cache invalidation
Off by one errors
https://martinfowler.com/bliki/TwoHardThings.html
Even though this is a joke, it holds a lot of truth
Hope this helps
This is thread safe if you initialize these values once and then only read from them. It is also safe in the presence of multiple worker processes and restarts because the multiple processes don't share variables.
As an alternative consider creating an instance of a class holding your settings:
class MySettings {
bool IsEnabled;
}
Then you can use dependency injection to inject a singleton value of this class to your code. This makes it easier to tests and makes the code more uniform.
How would I go about setting and accessing application-wide variables in ASP.NET Core 2.0?
Details:
I have a variable, let's call it CompanyName, which resides in the database and is used on literally every page. I don't want to hit the database every time I need to display the CompanyName. 100 years ago, I would have set Application["CompanyName']=CompanyName but I understand that this is not the way to do things in .NET Core. What would be the alternative?
A lot has progressed in the last 100 years. Some time ago, I believe in ASP.NET 1.0, the Application object in ASP classic was superseded with caching (although the Application object was left in for backward compatibility with ASP classic).
AspNetCore has replaced the caching mechanism of ASP.NET and made it DI-friendly, but it is still very similar to how the state of things was in ASP.NET. The main difference is that you now need to inject it instead of using the static HttpContext.Current.Cache property.
Register the cache at startup...
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMemoryCache();
services.AddMvc();
}
public void Configure(IApplicationBuilder app)
{
app.UseMvcWithDefaultRoute();
}
}
And you can inject it like...
public class HomeController : Controller
{
private IMemoryCache _cache;
public HomeController(IMemoryCache memoryCache)
{
_cache = memoryCache;
}
public IActionResult Index()
{
string companyName = _cache[CacheKeys.CompanyName] as string;
return View();
}
Then to make it work application wide, you can use a filter or middleware combined with some sort of cache refresh pattern:
Attempt to get the value from the cache
If the attempt fails
Lookup the data from the database
Repopulate the cache
Return the value
public string GetCompanyName()
{
string result;
// Look for cache key.
if (!_cache.TryGetValue(CacheKeys.CompanyName, out result))
{
// Key not in cache, so get data.
result = // Lookup data from db
// Set cache options.
var cacheEntryOptions = new MemoryCacheEntryOptions()
// Keep in cache for this time, reset time if accessed.
.SetSlidingExpiration(TimeSpan.FromMinutes(60));
// Save data in cache.
_cache.Set(CacheKeys.CompanyName, result, cacheEntryOptions);
}
return result;
}
Of course, you could clean that up and make a service with strongly typed properties as a wrapper around your cache that is injected into controllers, but that is the general idea.
Note also there is a distributed cache in case you want to share data between web servers.
You could alternatively use a static method or a statically registered class instance, but do note if hosting on IIS that the static will go out of scope every time the application pool recycles. So, to make that work, you would need to ensure your data is re-populated using a similar refresh pattern.
The primary difference is that with caching there are timeout settings which can be used to optimize how long the data should be stored in the cache (either a hard time limit or a sliding expiration).
You could create a Singleton-class called ApplicationWideSettings. Give that class public Properties. Initialize all the values you need one time and then use them by accesing the only instance of your class via:
ApplicationWideSettings.Instance.PropertyName;
Just make sure the namespace of the ApplicationWideSettings-class is referenced when you want to access it.
I prefer this over global/static settings because you have one class to save all your globally available data.
If you are unsure what a Singleton is I can just suggest you look into this article from Jon Skeet:
C# In Depth: Implementing the Singleton Pattern in C#
I have created a Singleton-patterned class which contains some instance variables (Dictionaries) which are very expensive to fill.
This class is used in an .NET MVC 4 project. And they key is that the data provided by the dictionaries in this Singleton class is nice to have, but is not required for the web app to run.
In other words, when we process a web request, the request would be enhanced with the information from the dictionaries if they are available, but if it's not available, it's fine.
So what I would like to do is find the best way to load the data into these Dictionaries within the Singleton, without blocking the web activity as they are filled with data.
I would normally find a way to do this with multithreading, but in the past I read about and ran into problems using multithreaded techniques within ASP.NET. Have things changed in .NET 4 / MVC 4? How should I approach this?
UPDATE
Based on feedback below and more research, what I am doing now is below, and it seems to work fine. Does anyone see any potential problems? In my testing, no matter how many times I call LazySingleton.Instance, the constructor only gets called once, and returns instantly. I am able to access LazySingleton.EXPENSIVE_CACHE immediately, although it may not contain the values I am looking for (which I test for in my app using .Contains() call). So it seems like it's working...
If I'm only ever editing the EXPENSIVE_CACHE Dictionary from a single thread (the LazySingleton constructor), do I need to worry about thread safety when reading from it in my web app?
public class LazySingleton
{
public ConcurrentDictionary<string, string> EXPENSIVE_CACHE = new ConcurrentDictionary<string, string>(1, 80000); // writing to cache in only one thread
private static readonly Lazy<LazySingleton> instance = new Lazy<LazySingleton>(() => new LazySingleton());
private LazySingleton()
{
Task.Factory.StartNew(() => expensiveLoad());
}
public static LazySingleton Instance
{
get
{
return instance.Value;
}
}
private void expensiveLoad()
{
// load data into EXPENSIVE_CACHE
}
}
You may fill your cash repository on any of
Application_Start
Session_Start
your web application events.
Something like this
<%# Application Language="C#" %>
<script runat="server">
void Application_Start(object sender, EventArgs e)
{
SingletonCache.LoadStaticCache();
}
</script>
May this be useful
Background:
I asked this question about creating a cached provider structure for my WCF service. I've implemented that design now, but what I've noticed in testing, is that the providers aren't actually being cached. How do I know this? I added the following debug-level logging to my service:
private static readonly IDictionary<string, XmlLoaderProviderBase> _providerDictionary =
new Dictionary<string, XmlLoaderProviderBase>();
public void Load(LoadRequest loadRequest)
{
XmlLoaderProviderBase xmlLoader;
if (_providerDictionary.ContainsKey(loadRequest.TransferTypeCode))
{
// Use cached provider...
xmlLoader = _providerDictionary[loadRequest.TransferTypeCode];
Logger.Log.DebugFormat("Found cached provider: {0} for transfer type: {1}",
xmlLoader.GetType(), loadRequest.TransferTypeCode);
}
else
{
// Instantiate provider for the first time; add provider to cache...
xmlLoader = XmlLoaderProviderFactory.CreateProvider(loadRequest.TransferTypeCode);
_providerDictionary.Add(loadRequest.TransferTypeCode, xmlLoader);
Logger.Log.DebugFormat("Instantiating provider: {0} for transfer type: {1}",
xmlLoader.GetType(), loadRequest.TransferTypeCode);
}
xmlLoader.Load(loadRequest);
}
And what I notice, is that no matter how many times I call the service, a provider is always instantiated (it never finds the cached version). Thankfully log4net is pretty helpful, and it shows that each call to the service runs in it's own unique process (i.e. it has a unique process ID). So as is, the providers will never be cached. How can I get this to actually cache providers, and read that dictionary across processes? Is this even possible?
I also read similar questions to this here on SO, and I notice the InstanceContextMode setting. I don't think I want this, because I think that will hurt performance (am I wrong? way off?) In a nut shell, my desire is to share the _providerDictionary across all processes/service instances... please help!
I'm going to steal #slfan's comment:
Use
[ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Multiple, InstanceContextMode=InstanceContextMode.Single)]
Default InstanceContextMode is PerSession.
I would look into creating a custom caching framework using System.Runtime.Caching.ObjectCache / MemoryCache. To my knowledge this should be accessible across processes. It is also threadsafe.
See the following links:
http://technovivek.blogspot.com/2013/08/c-in-memory-cache-using-net-40-object.html
http://www.codeproject.com/Articles/290935/Using-MemoryCache-in-Net
I want to create a singleton that remains alive for the life of the app pool using HttpContent.Current.Cache.
Where would I create the class and how should it be implemented? I understand how to implement a singleton but am not too familiar with threading and httpcontent.current.cache.
Thanks!
It doesn't matter where to put the singleton code.
As soon as you access the instance and the type is initialized, it will remain in memory for the entire life of your ApplicationDomain. So use it as a normal class and the rest is done on first use.
Perhaps you are over-complicating the issue? i'm not sure why you need to use the cache. Could you not just add a file to the App_Code folder to house your class e.g "mSingleton.cs"
public sealed class mSingleton
{
static readonly mSingleton _instance = new mSingleton();
public int MyVal { get; set; }
public static mSingleton Instance
{
get { return _instance; }
}
private mSingleton()
{
// Initialize members, etc. here.
}
}
Then it is global to all your code and pages, maintains state until the app pool recycles or there is a app rebuild (i don't know if this causes the app to recycle as well - if it does then it suits your criteria anyway), doesn't need to be added to any cache, application or session variables.. no messy handling
You can do this on page_load in any aspx.cs file and refresh it to see the count go up each time to prove state is maintained:
mSingleton getMyObj = mSingleton.Instance;
getMyObj.MyVal++;
I'd not use the cache for this. I'd recommend a static class or singleton with static getInstance().