Reputation: 5621
I'm using a lazy singleton following Jon Skeet's great pattern here.
The purpose of this object is to provide references to all of the other methods in the application.
For example, GetTheme(Context.Current.User.Id)
gets the theme for the current user, as do a plethora of other methods.
The issue I'm running into is how do I deal with changes in state when the object is already instantiated?
Namely, if a user comes to the website and isn't logged in, the Context
object is used during the creation of the new user.
However, after logging in, the User
object is null, because it was already instantiated.
I've tried to deal with this in the following way, making the public property reference a private method that checks for a null
reference, and tries to determine if it should indeed be null
.
Unfortunately, this turns into an infinite loop and crashes every time.
I have previously tried making the user object itself lazy, but for some strange reason it doesn't instantiate when called and remains null
.
What I'm looking for is, how do I make the User
property of my Lazy Singleton evaluate itself when called, and instantiate itself if it's null
, but capable of being populated?
The conditions being, the MVC Global User
object property User.Identity.Name
is not null, and is passed into the session at load to be pulled in the model, and that a user exists in the database using the username as a key.
public sealed class Context
{
public static Context Current { get { return lazy.Value; } }
private static readonly Lazy<Context> lazy =
new Lazy<Context>(() => new Context());
public UserMeta User { get { return _meta(); } }
private Context()
{
Deployment = GetCurrentDeploymentType();
Device = (Device)HttpContext.Current.Session["CurrentDevice"];
}
private UserMeta _meta()
{
//If the current object is null,
//but the user has been authenticated, populate the object
if (Current.User == null &&
!string.IsNullOrEmpty((string)HttpContext.Current.Session["UserEmail"]))
{
//check that the user is in the database first
var _userTry =
Sql.Read.UserByEmail((string)HttpContext.Current.Session["UserEmail"]);
if (_userTry == null)
{
return new UserMeta(
new UserMeta((string)HttpContext.Current.Session["UserEmail"]));
}
return null;
}
//If the Current Instance already has a populated User Object,
//just use that
else if (Current.User != null)
return Current.User;
else
return null;
}
}
Upvotes: 0
Views: 73
Reputation: 6054
If you use a private field, it will solve the problem
public sealed class Context
{
private UserMeta _user = null;
public static Context Current { get { return lazy.Value; } }
private static readonly Lazy<Context> lazy = new Lazy<Context>(() => new Context());
public UserMeta User
{
get
{
if (_user == null) _user =_meta();
return _user;
}
}
private Context()
{
private UserMeta _meta()
{
if (!string.IsNullOrEmpty((string)HttpContext.Current.Session["UserEmail"]))
{
//check that the user is in the database first
var _userTry =
Sql.Read.UserByEmail((string)HttpContext.Current.Session["UserEmail"]);
if (_userTry == null)
{
return new UserMeta(
new UserMeta((string)HttpContext.Current.Session["UserEmail"]));
}
return null;
}
}
Upvotes: 1