Abstracting HttpContext Request and Session - thread safety - asp.net

I have the following assemblies in my ASP.NET app:
Website - this is an ASP.NET website
ClassLib - this is just a class lib that contains all the business logic
Class Lib needs to interact with the HttpContext Session and Request objects. This is a code upgrade from an old ASP app, where I've hoovered all the VBScript that contained the logic and put it into VB.NET. We simply didn't have time to rewrite.
Instead of ClassLib interacting directly with HttpContext, which I thought was BAD and also prevented us from unit testing, I introduced the following abstraction layer:
Public Class Request
Private Shared _requestWrapper as IRequestWrapper
Public Shared ReadOnly Property RequestWrapper()
Get
If _requestWrapper Is Nothing Then
Throw New Exception("_requestWrapper is null. Make sure InitRequest() is called with valid parameters")
End If
Return _requestWrapper
End Get
End Property
Public Shared Sub InitRequest(ByRef requestWrapper As IRequestWrapper)
_requestWrapper = requestWrapper
End Sub
Public Shared Function GetVal(ByVal key As String) As Object
Return RequestWrapper.GetVal(key)
End Function
etc.
This means in the unit tests I can supply my own MockRequest object into this Request class, which is just a simple NameValue collection. The code in the ClassLib and the Website then simply use the Request class and are none the wiser that it isn't coming from the HttpContext, but rather this mock class.
When it comes to the real deal, I simply have the following (C#) class:
public class RealRequest : IRequestWrapper
{
public void Initialize(HttpContext context)
{
}
#region Implementation of IRequestWrapper
public object GetVal(string index)
{
return HttpContext.Current.Request[index];
}
etc.
This is initialised in Session_Start of global.asax in the Website, as follows:
protected void Session_Start(object sender, EventArgs e)
{
IRequestWrapper requestWrapper = new RealRequest();
WebSession.Request.InitRequest(ref requestWrapper);
}
I think this is similar to the Static Gateway pattern.
Now, I am aware of singletons and static vars in a multi threaded environment such as ASP.NET, but this is slightly different. When it gets down to the RequestWrapper.GetVal(), its actually going to the HttpContext for that running thread - and pulling the value from that.
Certainly, any concurrent tests that we do with multiple users hitting the same server have never shown up any strange behaviour.
I'm just looking for re-assurance that this is a sound design, and if not why not?
Thanks
Duncan

This is fine. We have a very similar case in our applications that either uses HttpContext if it exists or fake implementations otherwise.
The one thing to watch out for is that there is a very specific instance where HttpContext.Current will return a value but HttpContext.Current.Request will throw an exception when triggered by the Application_Start event. In framework code, you really don't know (or want to know) what triggered the call though.
Workaround for HttpContext.HideRequestResponse being internal? Detect if HttpContext.Request is really available?

Related

StructureMap is not disposing data context when using HttpContextScoped()

My goal is to have one data context (MainDbContext) per HTTP request in ASP.NET MVC and dispose the data context when the request ends.
I'm using the following StructureMap configuration:
public static class ContainerConfigurer
{
public static void Configure()
{
ObjectFactory.Initialize(x =>
{
x.For<MainDbContext>().HttpContextScoped();
});
}
}
Whenever I need a MainDbContext, I'm using this code:
var dbContext = ObjectFactory.GetInstance<MainDbContext>();
This is working as expected: only one data context is being created per HTTP request. The problem is, MainDbContext is not being disposed at the end of the request.
How can I configure my ObjectFactory to dispose the data context when the HTTP request finishes? Or is this just something I need to do manually using Application_EndRequest() in Global.asax.
Update
I just tried adding the following code to Global.asax:
protected virtual void Application_EndRequest()
{
ObjectFactory.GetInstance<MainDbContext>().Dispose();
}
As expected, this solves the problem. I'm still wondering if there's any way to do this automatically with StructureMap, however.
Instead of:
x.For<MainDbContext>().HttpContextScoped();
Try:
x.For<MainDbContext>().HttpContextScoped().Use(() => new MainDbContext());
Also normally it's repository classes that need a db context. So instead of ObjectFactory.GetInstance<MainDbContext>(); have your repositories take some interface db context and configure StructureMap to inject the MainDbContext into them. Then make StructureMap inject repositories into controllers, ...
In Application_EndRequest:
protected void Application_EndRequest()
{
ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects();
}
Using a nested container is the only way to get Structure Map to automatically dispose objects. If you're not using that technique the only way is to dispose the objects yourself using either the way the OP described (pulling the object from the container and disposing it; see this NHibernate example for one way to do it) or to scope the object to HttpRequest and call ReleaseAndDisposeAllHttpScopedObjects as Darin described.

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.

explain why an object has lifetime outside scope

I've written a class as follows. I've written it taking into consideration that its mainly for use on the web (i.e. it will be used from aspx pages).
public class TestHelper
{
public TestHelper()
{
HttpContext ctxt = HttpContext.Current;
IHttpHandler RequestHandler = ctxt.Handler;
Page CurrentPage;
CurrentPage = (Page)RequestHandler;
CurrentPage.Unload += new EventHandler(CurrentPage_Unload);
Debug.Print("Open all connection here...");
}
void CurrentPage_Unload(object sender, EventArgs e)
{
Debug.Print("Close all connection here...");
}
}
And I've written my aspx page's code behind like this:
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
TestHelper helper = new TestHelper();
helper = null;
}
}
In spite of assigning helper to 'null' I find that CurrentPage_Unload() gets executed. Why is this behaviour so? What is this behaviour generally called?
The reason why I've written the class in that style was because I thought I could best manage my db connections in a central fashion in the class. Usually people would call methods on the object like helper.IsValid() followed by helper.ProfileExists() in the aspx code behind. Each of those methods would have their own db connection objects(IDbConnection), and their corresponding Open() & Close() calls to open/close db connection. I just felt that we should only do this only once in code. Hence I used the constructor to open db connections, and the Page object's unload event to close the connection objects. Are there any pitfalls to writing classes this way?
What is happening is you're attaching a delegate to the Unload event of the page. Even after your variable has been set to null, your page still exists and still has an Unload event which still holds a reference to the delegate you added to it.
To remove a delegate you need to use -= syntax.
CurrentPage.Unload -= new EventHandler(CurrentPage_Unload);
Assigning null to a variable does not end its actual lifetime. Because .NET uses a non-deterministic garbage collection system (where objects are periodically purged based on several criteria, rather than as soon as they fall out of scope), you cannot rely on an object ever being collected before the process that created it ends.
Furthermore, because you're attaching an event handler (meaning a delegate, which includes a reference to your newly-constructed instance) to another object, you're extending the viable lifetime of your object as well. As long as that event handler is attached, your object cannot be collected until the object it's attached to is eligible.
You have to think about what happens when you execute the line
helper = null;
You simply have a reference to an object. When you assign that object to null, you're simply setting your reference to null. Nothing has happened to the object. Consider the following code:
var first = new object();
second = first;
first = null;
Would second now be null? You can think of a reference as simply a number - it's simply the address of the object in memory.
The .NET garbage collector simply looks at objects and checks if there are any references to that object. If not, it will remove that object.

Access/use the same object during a request - 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.

ASP.NET lock() doesn't work

i try to put a lock to a static string object to access to cache,, the lock() block executes in my local,but whenever i deploy it to the server, it locks forever. i write every single step to event log to see the process and lock(object) just causes the deadlock on the server. The command right after lock() is never executed as the i dont see an entry in the event log.
below is the code:
public static string CacheSyncObject = "CacheSync";
public static DataView GetUsers()
{
DataTable dtUsers = null;
if (HttpContext.Current.Cache["dtUsers"] != null)
{
Global.eventLogger.Write(String.Format("GetUsers() cache hit: {0}",dtUsers.Rows.Count));
return (HttpContext.Current.Cache["dtUsers"] as DataTable).Copy().DefaultView;
}
Global.eventLogger.Write("GetUsers() cache miss");
lock (CacheSyncObject)
{
Global.eventLogger.Write("GetUsers() locked SyncObject");
if (HttpContext.Current.Cache["dtUsers"] != null)
{
Global.eventLogger.Write("GetUsers() opps, another thread filled the cache, release lock");
return (HttpContext.Current.Cache["dtUsers"] as DataTable).Copy().DefaultView;
}
Global.eventLogger.Write("GetUsers() locked SyncObject"); ==> this is never written to the log, so which means to me that, lock() never executes.
You're locking on a string, which is a generally bad idea in .NET due to interning. The .NET runtime actually stores all identical literal strings only once, so you have little control over who sees a specific string.
I'm not sure how the ASP.NET runtime handles this, but the regular .NET runtime actually uses interning for the entire process which means that interned strings are shared even between different AppDomains. Thus you could be deadlocking between different instances of you method.
What happens if you use:
public static object CacheSyncObject = new object();

Resources