ASP.net: singleton class, instantiate just once per request? - asp.net

I have a class called UserContext that tracks the activities of a given user on my website. It should be a singleton class (just one instance per user). In a Windows Forms application, I'd could write something like this:
Class UserContext
Public Shared Current As New UserContext()
Private Sub New(appName As String)
[...]
End Class
But on an ASP.net app, this would get shared across all current users.
If this class were only being used within a Page entity I could just store the UserContext instance in a Page variable—it doesn't necessarily need to survive postbacks. But other entities (that don't know about Page) also call UserContext, and I'd like them all to be given the same instance.
What can I do to ensure that a class is only instantiated once per http request (or per user)? Could I use the cache for this?
Public Shared Function GetContext() As UserContext
If HttpContext.Current.Cache("CurrentUserContext") Is Nothing Then HttpContext.Current.Cache("CurrentUserContext") = New UserContext()
Return HttpContext.Current.Cache("CurrentUserContext")
End Function
Might session state be a better option?
Cache and session state both survive postbacks—is there another option that resets with each new request?
Thanks for your help!

HttpContext.Current.Cache will be shared among all users. HttpContext.Current.Session is per user but persists for subsequent requests.
You need HttpContext.Current.Items:
Public Shared Function GetContext() As UserContext
If HttpContext.Current.Items("CurrentUserContext") Is Nothing Then HttpContext.Current.Items("CurrentUserContext") = New UserContext()
Return HttpContext.Current.Items("CurrentUserContext")
End Function
This will ensure a safe per request and per user cache store.

You can use the HttpContext.Current.Items collection.

You will need a locking strategy to handle concurrent requests if you are storing the variable for longer than the life of the request. Always assign on your read, and employ double-checked locking to enforce singleton.
Private ReadOnly lockObj As New Object()
Private Const CurrentUserContextKey As String = "CurrentUserContext"
Public Function GetContext() As UserContext
Dim session = HttpContext.Current.Session
Dim userContext = TryCast(session(CurrentUserContextKey), UserContext)
If userContext Is Nothing Then
SyncLock lockObj
userContext = TryCast(session(CurrentUserContextKey), UserContext)
If userContext Is Nothing Then
userContext = New UserContext()
session(CurrentUserContextKey) = userContext
End If
End SyncLock
End If
Return userContext
End Function

Related

Shopping cart session specific to instance

Strange - Session - Inproc - mode use cookies name asp_net session id, timeout 20 , is shared across clients, not sure !!! session should be unique for each client, but its been shared across clients !!
In my asp.net application, the shopping cart session has been shared across the requests, not sure how happened,it should be different specific to the request , each request in IIS should have each session, but all the requests in IIS is been shared by this session`public class PODCart
{
#region Properties
public List<PODCartItem> Items { get; private set; }
#endregion
#region Singleton Implementation
public static readonly PODCart Instance;
static PODCart()
{
if (HttpContext.Current.Session["C"] == null)
{
Instance = new PODCart();
Instance.Items = new List<PODCartItem>();
HttpContext.Current.Session["C"] = Instance;
}
else
Instance = (PODCart)HttpContext.Current.Session["C"];
}
protected PODCart() { }
}`
Really need to know the fix as quick as possible, though the singleton implementation is done.
You have a singleton class defined and you are assigning it to every single session. Of course it's going to use the same one.
It really looks like PODCart shouldn't be a singleton.

Is ThreadLocal in ASP.NET equivalent to a per request variable?

I use a ThreadLocal variable in an ASP.NET HttpHandler. I assumed it will result in a new variable per request.
I have some strange behavior in my application. When a ThreadLocal variable is created and disposed in an ASP.NET page?
What happens if the same thread is used by ASP.NET later for another request? Does it result in a new ThreadLocal variable or the previously created value (which was used with another request) will be used?
If ThreadLocal variables are disposed when the thread is actually disposed, then my assumption fails with ASP.NET (since threads get back to pool and are not unique per request)
ASP.NET can and will reuse threads between requests- in fact, if memory serves it uses a thread from the normal .NET thread pool for each request. You are probably better off using session state instead.
Try with this:
public class WebRequestLocal<T>
{
private readonly Func<T> _getter;
private readonly object _id = new object();
public WebRequestLocal(Func<T> getter)
{
_getter = getter;
}
public T Value
{
get
{
HttpContext httpContext = HttpContext.Current;
if(httpContext == null)
throw new Exception("HttpContext unavailable.");
if (httpContext.Items.Contains(_id))
return (T)httpContext.Items[_id];
return (T)(httpContext.Items[_id] = _getter());
}
}
}

ASP.NET Web Service + Module + Public variable = thread safe?

In my ASP.NET Web Service I've included a module in which their are Public declared variables. Will they be thread-safe? Will they get mixed up upon simultaneous calls?
Those variables are mostly DatsSet, DataTable and SQLDataAdapter..
Partial code of the module:
Imports System.Data.OleDb
Imports System.Diagnostics
Module modCommon
Public bDoLog As Boolean
Public sCurrentODBC As String
Public cn As SqlConnection
Public Query1ds As DataSet
Public Query1 As DataTable
Public Query1adapter As SqlDataAdapter
#scripni
Thanks, as I'm not familiary with your suggestions, I will move everything locally.
Additionally, will the following variables be thread-safe?:
[ToolboxItem(False)]_
Public Class Service1
Inherits System.Web.Services.WebService
Dim sName As String
Dim sCurrentPath As String
[WebMethod()]_
Public Function Capture(ByVal sPath As String) As String
sName = "Joe"
End Function
End Class
If you're using web services than yes, you will have concurency problems when multiple services will try to access the same resource, and SqlConnection is definetly a resource you don't want shared.
You should make sure that you don't have simultaneous calls to the properties (for ex. by wrapping the fields with getters / setters and implementing locks in those methods) or by moving the code to a class and instantiating that class whenever you need it.

asp.net custom role provider nhibernate error

HI,
I am implementing a custom role provider in my nhibernate application
I have a repository that I call whenever I want to access the nhibernate session.
So when my role provider initializes itself
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config) {
base.Initialize(name, config);
Repository = new Repository();
}
Then I override
public override string[] GetRolesForUser(string username) {
var users = Repository.QueryAll<Users>();
//I then filter and so on
}
But when this function is called I always get an error that the NHibernate session is closed.
I debugged the nhibernate source code and it turns out that the session here has a different guid that the session in my controllers(I am using ASP.NET MVC also).
And this particular session is closed by the time I get here.
I don't know who closes it. I know it is started when the application starts and only then.
Does anyone have any idea what I am doing wrong?
I want to still use Nhibernate in this provider but not get the error any more.
Thank you
I had what appears to be the exact same problem. Don't forget that Role and Membership providers are only instantiated once and exist for the lifetime of the application. If you're using a Session per Web request pattern, the ISession will be closed after the first request and then any reference to an ISession internal to the provider will likely be null for subsequent requests.
You can get around this by injecting a reference to the ISessionFactory and calling GetCurrentSession, instead of directly holding a reference to an ISession.
This is how I evetually fixed it.
in my repository class I had this:
public Repository()
{
this.Session = SessionManager.GetCurrentSession();
}
I deleted the constructor entirely
I put in this instead:
private ISession _session;
protected ISession Session
{
get
{
if (_session == null)
{
_session = SessionManager.GetCurrentSession();
}
return _session;
}
}

how to Initialize the object as a static only for one session

I am working with ASP.net 3.5 MVC application.
I have one assembly which has ClassA.
I have another assembly which creates the object of ClassA
Now the question is ,
how to Intialize the object as a static only for one session.
The object will be static across the session. New Instance of the object should be created only when new session starts. In addition, for the previous session the object should be available with the previous intsance.
How to do this ?
You can use HTTPModule (hit every time) which checks the Application Object with some key (unique for a session, probably you can use SessionId + something within the key). This we are doing to access previous session's object , in case we don't want this, then we can set with some key not unique to a particular session.
Now as the module is hit, and we find no object in Application Object for the particular session we will create the object and will set in this HTTPModule Class as static.
Then the following code might help in case we find no object in HTTPApplication object for the current session(in case we dont need previous session's object then we can use HTTPSession object also to check for ClassA object's availability, even a flag with in HTTPSession will suffice, no need to save any object in HTTPSession, module class will give that).
In HTTPModule class the following should be added:
Static variable which can be accessed from this HTTPModule class by any other class of your application.
/* HTTP Module Class */
public class SomeModuleClass
{
public static ClassA classA = null;
private void someFunctionOfModuleFiringEverytime()
{
/* if there is no instance of ClassA in HTTPApplication or HTTPSession object*/
SessionManager sessionManager = new SessionManager();
/* one object of SessionManager gives back one object of ClassA always*/
classA = sessionManager.getClassA();
}
}
/* an assembly which is making the Class A instance*/
public class SessionManager
{
private ClassA classInstance=null;
public ClassA getClassA()
{
if (classInstance == null)
classInstance = new ClassA();
return classInstance;
}
}
/* class from another assembly*/
public class ClassA
{
public ClassA()
{
}
}
Wrap the object into a Singleton class. Singleton class should cache the object into Session. Perform lazy-load to create the object only when accessed for the first time and then cache into session. This will also work even in case when the session expires.
http://en.wikipedia.org/wiki/Singleton_pattern
http://www.dofactory.com/patterns/PatternSingleton.aspx
You could use the Session_Start event in global.asax and put the instance of ClassA in the session. You could then just read it from the session and it will be the same instance for the same user as long as the session is alive.

Resources