Access/use the same object during a request - asp.net - asp.net

i have a HttpModule that creates an CommunityPrincipal (implements IPrincipal interface) object on every request. I want to somehow store the object for every request soo i can get it whenever i need it without having to do a cast or create it again.
Basically i want to mimic the way the FormsAuthenticationModule works.
It assigns the HttpContext.User property an object which implements the IPrincipal interface, on every request.
I somehow want to be able to call etc. HttpContext.MySpecialUser (or MySpecialContext.MySpecialUser - could create static class) which will return my object (the specific type).
I could use a extension method but i dont know how to store the object so it can be accessed during the request.
How can this be achieved ?
Please notice i want to store it as the specific type (CommunityPrincipal - not just as an object).
It should of course only be available for the current request being processed and not shared with all other threads/requests.
Right now i assign my CommunityPrincipal object to the HttpContext.User in the HttpModule, but it requires me to do a cast everytime i need to use properties on the CommunityPrincipal object which isnt defined in the IPrincipal interface.

I'd recommend you stay away from coupling your data to the thread itself. You have no control over how asp.net uses threads now or in the future.
The data is very much tied to the request context so it should be defined, live, and die along with the context. That is just the right place to put it, and instantiating the object in an HttpModule is also appropriate.
The cast really shouldn't be much of a problem, but if you want to get away from that I'd highly recommend an extension method for HttpContext for this... this is exactly the kind of situation that extension methods are designed to handle.
Here is how I'd implement it:
Create a static class to put the extension method:
public static class ContextExtensions
{
public static CommunityPrinciple GetCommunityPrinciple(this HttpContext context)
{
if(HttpContext.Current.Items["CommunityPrinciple"] != null)
{
return HttpContext.Current.Items["CommunityPrinciple"] as CommunityPrinciple;
}
}
}
In your HttpModule just put the principal into the context items collection like:
HttpContext.Current.Items.Add("CommunityPrincipal", MyCommunityPrincipal);
This keeps the regular context's user property in the natural state so that 3rd party code, framework code, and anything else you write isn't at risk from you having tampered with the normal IPrincipal stroed there. The instance exists only during the user's request for which it is valid. And best of all, the method is available to code as if it were just any regular HttpContext member.... and no cast needed.

Assigning your custom principal to Context.User is correct. Hopefully you're doing it in Application_AuthenticateRequest.
Coming to your question, do you only access the user object from ASPX pages? If so you could implement a custom base page that contains the cast for you.
public class CommunityBasePage : Page
{
new CommunityPrincipal User
{
get { return base.User as CommunityPrincipal; }
}
}
Then make your pages inherit from CommunityBasePage and you'll be able to get to all your properties from this.User.

Since you already storing the object in the HttpContext.User property all you really need to acheive you goal is a Static method that acheives your goal:-
public static class MySpecialContext
{
public static CommunityPrinciple Community
{
get
{
return (CommunityPrinciple)HttpContext.Current.User;
}
}
}
Now you can get the CommunityPrinciple as:-
var x = MySpecialContext.Community;
However it seems a lot of effort to got to avoid:-
var x = (CommunityPrinciple)Context.User;
An alternative would be an Extension method on HttpContext:-
public static class HttpContextExtensions
{
public static CommunityPrinciple GetCommunity(this HttpContext o)
{
return (CommunityPrinciple)o.User;
}
}
The use it:-
var x = Context.GetCommunity();
That's quite tidy but will require you to remember to include the namespace where the extensions class is defined in the using list in each file the needs it.
Edit:
Lets assume for the moment that you have some really good reason why even a cast performed inside called code as above is still unacceptable (BTW, I'd be really interested to understand what circumstance leads you to this conclusion).
Yet another alternative is a ThreadStatic field:-
public class MyModule : IHttpModule
{
[ThreadStatic]
private static CommunityPrinciple _threadCommunity;
public static CommunityPrinciple Community
{
get
{
return _threadCommunity;
}
}
// Place here your original module code but instead of (or as well as) assigning
// the Context.User store in _threadCommunity.
// Also at the appropriate point in the request lifecyle null the _threadCommunity
}
A field decorated with [ThreadStatic] will have one instance of storage per thread. Hence multiple threads can modify and read _threadCommunity but each will operate on their specific instance of the field.

Related

Making my identity 2.0 custom extension method thread safe

So I created a class to hold user settings and i'm saving it as a JSON string so that I can modify it whenever I please without doing migrations every time I add one setting.
Anyways everything is working wonderful, well until, exception, I look further into it, and I've found things about it being thread safe but I don't really understand what they mean, how is my simple function that accesses entity identity dbcontext, not thread safe?
public static AppUserSettings GetUserSettings(this IIdentity identity)
{
var user = IdentityDbContext.Users.Find(identity.GetUserId());
return user.SettingsClass != null ? JsonConvert.DeserializeObject<AppUserSettings>(user.SettingsClass) : new AppUserSettings();
}
and the sister function:
public static void SetUserSettings(this IIdentity identity, AppUserSettings toSaveUserSettings)
{
var user = IdentityDbContext.Users.Find(identity.GetUserId());
user.SettingsClass = JsonConvert.SerializeObject(toSaveUserSettings);
DatabaseUtil.SaveChanges(IdentityDbContext);
}
Any help is appreciated, if need be I can attach other classes and/or snippets, but I feel like it is largely a Identity/Entity issue.

Action requires multiple controllers to execute

I have a UserController that has a Destroy function. It is a rather complex function because it demands to destroy all user's data. I have another action, from the Admin panel that deletes all data from a specific set of users.
Since I don't want to replicate the code from the UserController, I would like to call the Destroy function from UserController for each User to destroy its data.
How should I proceed?
Thanks in advance.
Why not move this functionality to a common class method which can be accessed from both the controllers as needed ?
public class UserManager
{
public void Destroy(List<int> userIdsToDestroy)
{
foreach(var userId in userIdsToDestroy)
{
//Execute code to destroy
}
}
}
and from your action methods, you can call it like
var mgr = new UserManager();
var badUsers = new List<int> { 1,2,3};
mgr.Destroy(badUsers);
Update the badUsers variable value as needed based on from where you are calling it.
Shared functionality like this would ideally be in a business layer, and both controllers would call that code. If it's a little app, you could just create a separate folder structure for shared code. Larger projects would have a business layer dll.
Why not make the Destroy() method as a Non-Action method then like
[Non-Action]
public void Destroy(User user)
{
// code goes here
}
You can as well make this Destroy() function as part of your business layer logic instead of handling this in controller. In that case, you call it from anywhere.
If you want it to be #controller, you can as well consider usig [ChildActionOnly] action filter attribute.

Using Sessions in my Project

I am new to .NET programming and I am trying to implement sessions in my already screwed sample. So here are the details of my sample i had done till now.
I have types of solutions in my project. A Class library, web application and console application.
I created a static class which has a bunch of get/properties and using these properties as global variables to use in my Class library. These get/set properties have a mixed set of data structures like list and dictionaries.
My Web app has only one page with a bunch of list boxes and button. I am using all the get set properties from my class library in to my Web application for some data storing and retrieving purposes. Now when the web page is opened in two different browsers then the data is over written from one user to the other as I am using all static variables and storing data in those static variables.
My best solution to this is using sessions but I am a little confused of using them in my project. Can any one please help me in this regard.
Here is a small sample of my explanation:
a XMLData Class in Class Library has a bunch of these get/set properties.
public Dictionary<string, List<string>> Content
{
get { return _testContent; }
set { _testContent = value;}
}
Now how do I use HttpContext Sessions to use in my Class Library to move these static properties to sessions so that every user who uses my site have their set of data. FYI. The web project is basically used for call in methods to the class library and do a little selection on the list box of the UI which are kind of inputs to my test.
Thanks In Advance.
The simple way is that you can access the current context in a class in your class library using
HttpContext.Current
this has Session available on it.
There are more complex ways that your application could be architected, but we'll start with the simplest :)
To elaborate, your class library may declare an interface for a component that is able to access session
public interface ISessionStore
{
object Get(string key);
void Save(string key, object value);
}
now, define a concrete implementation of ISessionStore
public class HttpContextSessionStore : ISessionStore
{
public object Get(string key)
{
var context = HttpContext.Current;
if (context == null)
throw new InvalidOperationException("this class is intended to work only within web applications");
return context.Session(key);
}
public void Save(string key, object value)
{
var context = HttpContext.Current;
if (context == null)
throw new InvalidOperationException("this class is intended to work only within web applications");
// note that this will overwrite anything already set
// against this key in session
context.Session[key] = value;
}
}
Now you can program against the interface ISessionStore and use the HttpContextSessionStore in your application.
I'd recommend looking at the MVP pattern if you're working with web forms or alternatively, take a look at the MVC framework.
In addition to Russ Cam's comments above, you should also check that HttpContext.Current != null in methods in your class library. It's guaranteed to bite you in the ass if you start writing unit tests, or for any code which isn't being executed within ASP.Net

Intercept Unity 2.0 HandlerAttribute without an interface

I'm a first-time user of the AOP features of Unity 2.0 and would like some advice. My goal is to be able to log method calls in an ASPX page, like so:
public partial class Page2 : Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
[Log]
private void Testing()
{
}
}
Here is the code for the LogAttribute:
public class LogAttribute : HandlerAttribute
{
public override ICallHandler CreateHandler(IUnityContainer container)
{
return new LogHandler(Order);
}
}
Now the LogHandler:
public class LogHandler : ICallHandler
{
public LogHandler(int order)
{
Order = order;
}
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
string className = input.MethodBase.DeclaringType.Name;
string methodName = input.MethodBase.Name;
string preMethodMessage = string.Format("{0}.{1}", className, methodName);
System.Diagnostics.Debug.WriteLine(preMethodMessage);
return getNext()(input, getNext);
}
public int Order { get; set; }
}
The problem I have is how to use the [Log] attribute. I've seen plenty of example of how to configure the interception settings, for example:
container.AddNewExtension<Interception>();
container.Configure<Interception>().SetDefaultInterceptorFor<ILogger>(new InterfaceInterceptor());
But this implies that I have an interface to intercept, which I don't. I have the ASPX page which uses the [Log] attribute.
so how can I configure Unity to make use of the [Log] attribute? I've done this before using PostSharp and would like to be able to use Unity to do the same.
Cheers.
Jas.
You're unfortunately not going to get this to work in an ASP.NET page with Unity interception.
Unity interception uses a runtime interception model. Depending on the interceptor you choose, you'll either get a subclass with virtual method overrides to call the call handlers (VirtualMethodInterceptor) or a separate proxy object (Interface or TransparentProxyInterceptor) which execute the call handlers and then forward to the real object.
Here's the issue - ASP.NET controls creation and calls to your page, and there's no easy way to hook into them. Without controlling the creation of the page object, you can't use the VirtualMethodInterceptor, because that requires that you instantiate a subclass. And you can't use the proxy version either, because you need ASP.NET to make calls through the proxy.
PostSharp gets around this because it's actually rewriting your IL at compile time.
Assuming you could hook into the creation of the page object, you'd have to use the VirtualMethodInterceptor here. It's a private method, so you want logging on "self" calls (calls from one method of the object into another method on the same object). The proxy-based interceptors can't see those, since the proxy is a separate instance.
I expect there is a hook somewhere to customize how ASP.NET creates object - BuildManager maybe? But I don't know enough about the details, and I expect it'll require some pretty serious hacking to get work.
So, how do you get around this? My recommendation (actually, I'd recommend this anyway) is to use the Model-View-Presenter pattern for your ASP.NET pages. Make the page object itself dumb. All it does is forward calls to a separate object, the Presenter. The Presenter is where your real logic is, and is independent of the details of ASP.NET. You get a huge gain in testability, and you can intercept calls on the presenter without all the difficulty that ASP.NET gives you.

strongly typed sessions in asp.net

Pardon me if this question has already been asked. HttpContext.Current.Session["key"] returns an object and we would have to cast it to that particular Type before we could use it. I was looking at various implementations of typed sessions
http://www.codeproject.com/KB/aspnet/typedsessionstate.aspx
http://weblogs.asp.net/cstewart/archive/2008/01/09/strongly-typed-session-in-asp-net.aspx
http://geekswithblogs.net/dlussier/archive/2007/12/24/117961.aspx
and I felt that we needed to add some more code (correct me if I was wrong) to the SessionManager if we wanted to add a new Type of object into session, either as a method or as a separate wrapper. I thought we could use generics
public static class SessionManager<T> where T:class
{
public void SetSession(string key,object objToStore)
{
HttpContext.Current.Session[key] = objToStore;
}
public T GetSession(string key)
{
return HttpContext.Current.Session[key] as T;
}
}
Is there any inherent advantage in
using
SessionManager<ClassType>.GetSession("sessionString")
than using
HttpContext.Current.Session["sessionString"] as ClassType
I was also thinking it would be nice
to have something like
SessionManager["sessionString"] = objToStoreInSession,
but found that a static class cannot have an indexer. Is there any other way to achieve this ?
My thought was create a SessionObject which would store the Type and the object, then add this object to Session (using a SessionManager), with the key. When retrieving, cast all objects to SessionObject ,get the type (say t) and the Object (say obj) and cast obj as t and return it.
public class SessionObject { public Type type {get;set;} public Object obj{get;set;} }
this would not work as well (as the return signature would be the same, but the return types will be different).
Is there any other elegant way of saving/retrieving objects in session in a more type safe way
For a very clean, maintainable, and slick way of dealing with Session, look at this post. You'll be surprised how simple it can be.
A downside of the technique is that consuming code needs to be aware of what keys to use for storage and retrieval. This can be error prone, as the key needs to be exactly correct, or else you risk storing in the wrong place, or getting a null value back.
I actually use the strong-typed variation, since I know what I need to have in the session, and can thus set up the wrapping class to suit. I've rather have the extra code in the session class, and not have to worry about the key strings anywhere else.
You can simply use a singleton pattern for your session object. That way you can model your entire session from a single composite structure object. This post refers to what I'm talking about and discusses the Session object as a weakly typed object: http://allthingscs.blogspot.com/2011/03/documenting-software-architectural.html
Actually, if you were looking to type objects, place the type at the method level like:
public T GetValue<T>(string sessionKey)
{
}
Class level is more if you have the same object in session, but session can expand to multiple types. I don't know that I would worry about controlling the session; I would just let it do what it's done for a while, and simply provide a means to extract and save information in a more strongly-typed fashion (at least to the consumer).
Yes, indexes wouldn't work; you could create it as an instance instead, and make it static by:
public class SessionManager
{
private static SessionManager _instance = null;
public static SessionManager Create()
{
if (_instance != null)
return _instance;
//Should use a lock when creating the instance
//create object for _instance
return _instance;
}
public object this[string key] { get { .. } }
}
And so this is the static factory implementation, but it also maintains a single point of contact via a static reference to the session manager class internally. Each method in sessionmanager could wrap the existing ASP.NET session, or use your own internal storage.
I posted a solution on the StackOverflow question is it a good idea to create an enum for the key names of session values?
I think it is really slick and contains very little code to make it happen. It needs .NET 4.5 to be the slickest, but is still possible with older versions.
It allows:
int myInt = SessionVars.MyInt;
SessionVars.MyInt = 3;
to work exactly like:
int myInt = (int)Session["MyInt"];
Session["MyInt"] = 3;

Resources