I'm using Spring.NET 1.3.2, NHibernate 3.1 and the OSIV pattern in a ASP.NET application.
I have a custom EventListener
that needs to be request scoped because it uses
HttpContext.Current.Items as a constructor dependency.
Since ISession
is also request scoped, I should be able to use Spring.NET to manage these dependencies for me.
The problem is that EventListener
, like IInterceptor
, is a property of ISessionFactory
which is not request scoped (it's a singleton). The mismatch between the web object scopes is problematic.
I tried the following XML snippet, but the conditional expression always yields null. I think this is due to Spring creating EventListener
object at an application level scope, and before HttpContext.Current.Items
has had a chance to be populated.
<object id="EventListener" scope="request" type="MyEventListener,DAL">
<constructor-arg index="0" expression="T(System.Web.HttpContext).Current.Items.Contains('Principal')?T(System.Web.HttpContext).Current.Items['Principal']:null"/>
</object>
So my requirement is:
Configure custom EventListener
object in Spring so that it is created on a per-request basis
EventListener
instantiation must occur late enough in the request lifecycle so that HttpContext.Current.Items['Princpial'] has been populated by a custom IHttpModule
The EventListener
instance is injected into the the current OSIV ISession
I think you're trying to do this the wrong way around. According to the NHibernate documentation EventListener
s should basically be considered singletons for your application.
Even when you register your custom EventListener
with the SessionFactory
, say at the start of the request, you still have no guarantee whatsoever that this listener will only receive events raised in the current HttpContext
.
Instead you should register your eventhandlers globally, when configuring the session factory. If you need context information, such as a principal, you can inject a dependency with a (http)context-aware implementation or implement it as an ambient context.
From the custom listener, you can get access to the session that raised the event. Take for instance this ILoadEventListener
implementation:
public class CustomLoadEventListener : ILoadEventListener
{
private IPrincipalProvider _principalProvider;
public CustomLoadEventListener(IPrincipalProvider provider)
{
_principalProvider = provider;
}
public void OnLoad(LoadEvent @event, LoadType loadType)
{
var sessionThatRaisedTheEvent = @event.Session;
var principalForTheCurrentContext = _principalProvider.GetCurrentPrincipal();
}
}
public interface IPrincipalProvider
{
IPrincipal GetCurrentPrincipal();
}
public class HttpContextPrincipalProvider : IPrincipalProvider
{
public IPrincipal GetCurrentPrincipal()
{
return System.Web.HttpContext.Current.User;
}
}
This might not be the answer you hoped to get, but IMO what your are asking for would be fighting the infrastructure, which I generally try to avoid.
If you post some more details on what you are trying to achieve, we might be able to propose a better solution. What should your EventListener
do?