I'm building a Javascript application and eash user has an individual UserSession. The application makes a bunch of Ajax calls. Each Ajax call needs access to a single UserSession object for the user.
Each Ajax call needs a UserSession object.
Data in the UserSession object is unique to each user.
Originally, during each Ajax call I would create a new UserSession object and it's data members were stored in the ASP.NET Session. However, I found that the UserSession object was being instantiated a lot. To minimize the construction of the UserSession object, I wrapped it in a Singleton pattern and sychronized access to it.
I believe that the synchronization is happening application wide, however I only need it to happen per user. I saw a post here that says the ASP.NET cache is synchronized, however the time between creating the object and inserting it into the cache another Thread could start construction it's another object and insert it into the cache.
Here is the way I'm currently synchronizing access to the object. Is there a better way than using "lock"... should be be locking on the HttpContext.Session object?
private static object SessionLock = new object();
public static WebSession GetSession
{
get
{
lock (SessionLock)
{
try
{
var context = HttpContext.Current;
WebSession result = null;
if (context.Session["MySession"] == null)
{
result = new WebSession(context);
context.Session["MySession"] = result;
}
else
{
result = (WebSession)context.Session["MySession"];
}
return result;
}
catch (Exception ex)
{
ex.Handle();
return null;
}
}
}
}
You don't need to lock Session state access.
The physical values of a session state are locked for the time needed to complete a request. The lock is managed internally by the HTTP module and used to synchronize access to the session state.
http://msdn.microsoft.com/en-us/library/aa479041.aspx
In general, you don't need this kind of code for asp.net session access, since access to each session is limited to a single user. The only reason I can think of for locking access to your session object is if you expect to have multiple simultaneous ajax requests, and even so, I think asp.net would synchronize the access for you.
If you do decide to lock, you only really need to do it if your session object is null:
if (context.Session["MySession"] == null) {
lock(SessionLock) {
if (context.Session["MySession"] == null) {
context.Session["MySession"] = new WebSession(context); // try-catch block removed for clarity (and my laziness)
}
}
}
return (WebSession)context.Session["MySession"];
Related
I have build WebApi service(MvcApplication) that recive UserName ,and Email.
i have url to this service:
Ex: www.domain.com/Controller/SendUser
And i have some affiliates that use this URL to my service in they website/landing page,and they send me data with Username,and Email of potential client.
Some affiliates have build they submit form wrong,and allow to users press SEND button many times before they see response on the screen or redirect to next page.And here where the problem appears.
I getting 5-10 request to my service with duplicate data,and start to run all my validation function and methods insert to database.
IMPORTANT:
I don't wont solution on database level,i want to stop the request in the beginning,don't even start all validation services.
I need to receive request,temporary save UserName+Email,and if i receiving in the same second or in next 10 seconds the same UserName+Email just to avoid it.
I tries to add static dictionary to Global.asax and save EncodedLead(from User+Email),I lock the my dictionary GlobalMemoryLeads before i check if ContainsKey(X),and than i add a key,but some how i still get error that key is all ready exist even when dictionary is lock.
It seems that threads go throw lock and try to add the same key even when
GlobalMemoryLeads.ContainsKey(EncodedLead) return false,sow another thread can add key to dictionary that is locked by another thread??What i am missing here?
How to avoid duplicate requests?
UPDATED
My code:
[AcceptVerbs(WebRequestMethods.Http.Get, WebRequestMethods.Http.Post)]
[AllowCrossSiteJson]
public ActionResult SendUser(string UserName, string Email, )
{
string response = "";
bool duplicate=false;
try
{
string Lead = UserName + email;
int EncodedLead = Lead.GetHashCode();
//here i lock my GlobalMemoryLeads dictionary
lock (MvcApplication.GlobalMemoryLeads)
{
//here i check if that key is all ready ContainsKey
if (!MvcApplication.GlobalMemoryLeads.ContainsKey(EncodedLead))
{
try
{
MvcApplication.GlobalMemoryLeads.Add(EncodedLead, false);
}
catch (Exception ex)
{
//here i get error that key is all ready exist
//how it possible if i have
//1: Globalizes lock
//2 i check ContainsKey before
return Json(new { respondNotSuccess = "Duplicate Lead" });
}
}
}
}
catch (Exception ex)
{
response = "Exception " + ex.Message;
}
return Json(new { respondSuccess = response });
}
In general, avoid locking on a public type, or instances beyond your code's control.
The common constructs lock (this), lock (typeof (MyType)), and lock ("myLock") violate this guideline:
lock (this) is a problem if the instance can be accessed publicly.
lock (typeof (MyType)) is a problem if MyType is publicly accessible.
lock ("myLock") is a problem because any other code in the process using the same string, will share the same lock.
Best practice is to define a private object to lock on, or a private static object variable to protect data common to all instances
try to do something like that:
private Object thisLock = new Object();
lock (thisLock)
{
if (!MvcApplication.GlobalMemoryLeads.ContainsKey(EncodedLead))
{
try
{
MvcApplication.GlobalMemoryLeads.Add(EncodedLead, false);
...
I'm using a Webservice coded in C# using .Net Framework 3.5.
The WebMethods of this Webservice besides their main workload also connect to Salesforce to retrieve and write data, so I'm using a static variable for keeping the Salesforce api login object alive between requests, this way I only log in once (on Salesforce) and then reuse this variable for subsequent calls, avoiding the need to login on each request.
This static object is evaluated on the main ctor of the Webservice, to check if some properties inside the login object are valid (for example, the validity of the session), if not, the login method is called again.
This works with no problems at all on my development environment (Windows 7 and VS2012 IIS7.5? Dev server) and in a test server (Win Server 2003, IIS6), but it doesn't work at all on the production box which is also a Windows Server 2003 with IIS6, because the static variable value is null on each request, logging in Salesforce on every request, giving long response times for each call and also hitting some limits on Salesforce, locking the account and blocking any following logins.
Sadly both machines (test and production) don't have the same configuration and the production box is currently unreachable for me, so the recycling time of the App Pool and other specifics are unknown to me at the moment.
I think this is a configuration issue, but anyway here is my code, firstly i started only by having a static variable inside the Webservice main class and then (current version) creating a whole static class with static variables.
All of the following code is under the same namespace
Static class (Salesforce login logic):
public static class Srv
{
public static SFHelpers helper = new SFHelpers(); // own class, Holds Salesforce logic and data related to this requirement
public static SforceService SFserv = new SforceService(); // Salesforce class that handles login (and other Salesforce data manipulation methods)
public static DateTime NextLoginSF = DateTime.MinValue; // Determines when does the Salesforce session expires
public static void LoginSalesforce()
{ // Simplified salesforce login steps, removed try-catch and other conditions to facilitate comprehension
SFserv.Url = helper.URLSalesforce;
LoginResult loginResult = SFserv.login(SFuser, SFpass);
NextLoginSF = DateTime.Now.AddSeconds(loginResult.userInfo.sessionSecondsValid);
SFserv.Url = loginResult.serverUrl;
SFserv.SessionHeaderValue = new SessionHeader { sessionId = loginResult.sessionId };
}
}
Main ctor and sample Webmethod:
[WebService(Namespace = "http://helloSO.com/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class WsSFTest : System.Web.Services.WebService
{
public WsSFTest()
{
try
{
if (Srv.SFserv.SessionHeaderValue == null || DateTime.Now >= Srv.NextLoginSF) // any of this will trigger a login to renew Salesforce session
{
Srv.LoginSalesforce();
}
}
catch (SoapException se)
{
if (se.Code.Name == ExceptionCode.INVALID_SESSION_ID.ToString())
{ // Login again because Salesforce invalidated my session somehow
Srv.LoginSalesforce();
}
else
{
// Irrelevant
}
}
catch (Exception e)
{
// Irrelevant
}
}
[WebMethod]
public SampleResult SampleMethod(int param)
{
try
{
//irrelevant code gathers values here
var something = Srv.helper.Method(param, anotherParam);
return something;
}
catch (Exception e)
{
// Irrelevant
}
}
}
Serializing the login object to a local file or persistance database are my last options since quick response times are a must.
I think what's left for me to try are Session variables but given this behavior odds that something similar could happen seem high.
Any clues? Thanks in advance
At the end I realized some evaluation value in this line (Specifically Srv.NextLoginSF)
if (Srv.SFserv.SessionHeaderValue == null || DateTime.Now >= Srv.NextLoginSF) // any of this will trigger a login to renew Salesforce session
Was returning with a different value than expected, and that the static variable wasn't losing its value
I'm new in C# and trying to understand how to work with Lazy.
I need to handle concurrent request by waiting the result of an already running operation. Requests for data may come in simultaneously with same/different credentials.
For each unique set of credentials there can be at most one GetDataInternal call in progress, with the result from that one call returned to all queued waiters when it is ready
private readonly ConcurrentDictionary<Credential, Lazy<Data>> Cache
= new ConcurrentDictionary<Credential, Lazy<Data>>();
public Data GetData(Credential credential)
{
// This instance will be thrown away if a cached
// value with our "credential" key already exists.
Lazy<Data> newLazy = new Lazy<Data>(
() => GetDataInternal(credential),
LazyThreadSafetyMode.ExecutionAndPublication
);
Lazy<Data> lazy = Cache.GetOrAdd(credential, newLazy);
bool added = ReferenceEquals(newLazy, lazy); // If true, we won the race.
Data data;
try
{
// Wait for the GetDataInternal call to complete.
data = lazy.Value;
}
finally
{
// Only the thread which created the cache value
// is allowed to remove it, to prevent races.
if (added) {
Cache.TryRemove(credential, out lazy);
}
}
return data;
}
Is that right way to use Lazy or my code is not safe?
Update:
Is it good idea to start using MemoryCache instead of ConcurrentDictionary? If yes, how to create a key value, because it's a string inside MemoryCache.Default.AddOrGetExisting()
This is correct. This is a standard pattern (except for the removal) and it's a really good cache because it prevents cache stampeding.
I'm not sure you want to remove from the cache when the computation is done because the computation will be redone over and over that way. If you don't need the removal you can simplify the code by basically deleting the second half.
Note, that Lazy has a problem in the case of an exception: The exception is stored and the factory will never be re-executed. The problem persists forever (until a human restarts the app). In my mind this makes Lazy completely unsuitable for production use in most cases.
This means that a transient error such as a network issue can render the app unavailable permanently.
This answer is directed to the updated part of the original question. See #usr answer regarding thread-safety with Lazy<T> and the potential pitfalls.
I would like to know how to avoid using ConcurrentDictionary<TKey, TValue> and start
using MemoryCache? How to implement
MemoryCache.Default.AddOrGetExisting()?
If you're looking for a cache which has a mechanism for auto expiry, then MemoryCache is a good choice if you don't want to implement the mechanics yourself.
In order to utilize MemoryCache which forces a string representation for a key, you'll need to create a unique string representation of a credential, perhaps a given user id or a unique username?
If you can, you can create an override of ToString which represents your unique identifier or simply use the said property, and utilize MemoryCache like this:
public class Credential
{
public Credential(int userId)
{
UserId = userId;
}
public int UserId { get; private set; }
}
And now your method will look like this:
private const EvictionIntervalMinutes = 10;
public Data GetData(Credential credential)
{
Lazy<Data> newLazy = new Lazy<Data>(
() => GetDataInternal(credential), LazyThreadSafetyMode.ExecutionAndPublication);
CacheItemPolicy evictionPolicy = new CacheItemPolicy
{
AbsoluteExpiration = DateTimeOffset.UtcNow.AddMinutes(EvictionIntervalMinutes)
};
var result = MemoryCache.Default.AddOrGetExisting(
new CacheItem(credential.UserId.ToString(), newLazy), evictionPolicy);
return result != null ? ((Lazy<Data>)result.Value).Value : newLazy.Value;
}
MemoryCache provides you with a thread-safe implementation, this means that two threads accessing AddOrGetExisting will only cause a single cache item to be added or retrieved. Further, Lazy<T> with ExecutionAndPublication guarantess only a single unique invocation of the factory method.
I am trying to write a custom mechanism for compressing and caching web scripts. I am using a Mutex to provide managed access for the cache creation methods.
public class HttpApplicationCacheManager
{
public object Get(
Cache cache, // Reference to the HttpContext.Cache
string key, // Id of the cached object
int retrievalWaitTime,
Func<object> getData, // Method that builds the string to be cached
Func<CacheDependency> getDependency) // CacheDependency object for the
// string[] of file paths to be cached
{
Mutex mutex = null;
bool iOwnMutex = false;
object data = cache[key];
// Start check to see if available on cache
if (data == null)
{
try
{
// Lock base on resource key
// (note that not all chars are valid for name)
mutex = new Mutex(false, key);
// Wait until it is safe to enter (someone else might already be
// doing this), but also add 30 seconds max.
iOwnMutex = mutex.WaitOne(retrievalWaitTime * 1000);
// Now let's see if some one else has added it...
data = cache[key];
// They did, so send it...
if (data != null)
{
return data;
}
// Still not there, so now is the time to look for it!
data = getData();
var dependency = getDependency();
cache.Insert(key, data, dependency);
}
catch
{
throw;
}
finally
{
// Release the Mutex.
if ((mutex != null) && (iOwnMutex))
{
mutex.ReleaseMutex();
}
}
}
return data;
}
}
The
Whilst this works, I occasionally see the following error:
System.UnauthorizedAccessException
Access to the path 'SquashCss-theme.midnight.dialog' is denied.
I have found some posts suggesting that this might be due to a race condition. Unfortunately, my Mutex knowledge is very limited and I am struggling to see where the problem might be.
Any help would be much appreciated.
Why not just use any of the built-in .NET caches? I don't see anything in your code that could not be handled by the .NET cache implementations. Another option maybe the readerwriterlockslim class, since you really only need to lock on writes.
Following is my ASP.Net Web API controller code. Here as you can see there's a private class object, BL, that is used and both the Get methods implemented. For the first method FetchAllDashboardByUserId(int userId), I pass the user id so that the BL object can be initiated. Within the same browser session, if the second get method is called, then I do not want to pass the userid, since BL should be by default initiated, but currently that's not the case. BL is null for the second method, so I have to add userid to the call to the method - GetCardDataUI(int userId, int dashBoardID, int cardID). My question is how to avoid it. Is my thinking incorrect that:
A single open browser where I make the Consecutive call to the following URLs are a single session:
webapi/ViewR?userId=1
webapi/ViewR?userId=1&dashBoardID=1&cardID=3
I don't want to pass the userId in the second URL. Please note that if I declare class object as static then it works as expected, but that's not what I want, it has to be tied to a user:
public class ViewRController : ApiController
{
// BL object for a user
private static BL accessBL = null;
// HTTP GET for Webapi/ViewR (Webapi - name of API, ViewR - Controller with implementation)
[AcceptVerbs("Get")]
public List<DashboardUI> FetchAllDashboardByUserId(int userId)
{
if (accessBL == null)
accessBL = new BL(userId);
// Use BL object for entity processing
}
[AcceptVerbs("Get")]
public CardDataGetUI GetCardDataUI(int userId, int dashBoardID, int cardID)
{
if (accessBL == null)
accessBL = new BL(userId);
// Use BL object for entity processing
}
}
How I want the second method implementation to be:
[AcceptVerbs("Get")]
public CardDataGetUI GetCardDataUI(int dashBoardID, int cardID)
{
// Use BL class object created in last call for entity processing
// Should not pass userid again
}
You can easily store data in Session:
... first request:
Session["userID"] = userID;
... next request:
int userID = (int)Session["userID"]; // should check for null first, but you get the idea...
But keep the following points in mind:
Session variables are stored as objects, so you'll need to cast and/or type-check
Session variables can be null
Session expires after a configurable (in web.config) about of time
Default session state is in-memory, meaning if the app pool is restarted session state is gone - you can store session in files or databases to keep longer
Session doesn't scale out unless you use persistent storage (file, database)
Objects stored in persistent storage must be serializable