I have NHibernate hooked up in my asp.net mvc app.
Everything works fine, if I DON'T dispose the ISession. I have read however that you should dispose, but when I do, I get random "Session is closed" exceptions.
I am injecting the ISession into my other objects with Windsor.
Here is my current NHModule:
public class NHibernateHttpModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.BeginRequest += context_BeginRequest;
context.EndRequest += context_EndRequest;
}
static void context_EndRequest(object sender, EventArgs e)
{
CurrentSessionContext.Unbind(MvcApplication.SessionFactory);
}
static void context_BeginRequest(object sender, EventArgs e)
{
CurrentSessionContext.Bind(MvcApplication.SessionFactory.OpenSession());
}
public void Dispose()
{
// do nothing
}
}
Registering the ISession:
container
.Register(Component.For<ISession>()
.UsingFactoryMethod(() => MvcApplication.SessionFactory.GetCurrentSession()).LifeStyle.Transient);
The error happens when I tack the Dispose on the unbind in the module. Since I keep getting the session is closed error I assume this is not the correct way to do this, so what is the correct way?
Thanks,
Joe
Robert is correct, Windsor is disposing the session when it is releasing the components that depend on it.
Rather than having your own HttpModule I'd recommend using Windsor's PerWebRequest lifestyle for ISession.
It seems some object holding the session gets disposed, before Windsor tries to dispose the session. A quick fix is to ovveride your NHiberanteSessionFactory Dispose method and check if the session is already closed.
I think this article should help: Building a Desktop To-Do Application with NHibernate
Now I know, this is a Desktop application, but you might get inspired from this MSDN article.
Related
How do I inject dependencies into the global.asax.cs, i.e. the MvcApplication class?
Having previously used the Service Locator (anti-)pattern for dependency injection, I am trying to follow best practice advice in my latest MVC application by using an IOC container (specifically Unity.Mvc3 because it comes with an implementation of the IDependencyResolver out of the box) and constructor injection.
Everything seems quite straight forward so far except for a couple of snags, one of which is in the global.asax.cs (the other is for custom attributes but there's aleady a question on SO covering that).
The HttpApplication event handlers in the MvcApplication class such as:
Application_Start()
Application_EndRequest(object sender, EventArgs e)
Application_AcquireRequestState(object sender, EventArgs e)
may require external dependencies, e.g. a dependency on an ILogService. So how do I inject them without resorting to the service locator (anti-)pattern of e.g.
private static ILogService LogService
{
get
{
return DependencyResolver.Current.GetService<ILogService>();
}
}
Any help/advice greatly appreciated!
The class in your global.asax.cs is your Composition Root, so you can't (and shouldn't) inject anything into it from the outside.
However, there's only one instance of the MvcApplication class, so if you need a service in one of its methods, you can just declare it as a member field - e.g:
public class MvcApplication : System.Web.HttpApplication
{
private readonly ILogService log;
public MvcApplication()
{
this.log = new MyLogService();
}
protected void Application_Start()
{
// ...
this.log.Log("Application started");
}
}
You must use AutofacConfig.Resolve<T>() instead using DependencyResolver.Current.GetService<T>() to get your services without errors.
I have been struggling with WCF Proxies. What is the correct way to Dispose a WCF Proxy? The answer is not trivial.
System.ServiceModel.ClientBase violates Microsoft's own Dispose-pattern
System.ServiceModel.ClientBase<TChannel> does implement IDisposable so one must assume that it should be disposed or used in a using-block. These are best practices for anything disposable. The implementation is explicit, however, so one does have to explicitly cast ClientBase instances to IDisposable, clouding the issue.
The biggest source of confusion, however, is that calling Dispose() on ClientBase instances that faulted, even channels that faulted because they never opened in the first place, will result in an exception being thrown. This, inevitably, means that the meaningful exception explaining the fault is immediately lost when the stack unwinds, the using scope ends and Dispose() throws a meaningless exception saying that you can't dispose a faulted channel.
The above behaviour is anathema to the dispose pattern which states that objects must be tolerant of multiple explicit calls to Dispose(). (see http://msdn.microsoft.com/en-us/library/b1yfkh5e(v=vs.110).aspx, "...allow the Dispose(bool) method to be called more than once. The method might choose to do nothing after the first call.")
With the advent of inversion-of-control, this poor implementation becomes a real problem. I.O.C. containers (specifically, Ninject) detect the IDisposable interface and call Dispose() explicitly on activated instances at the end of an injection scope.
Solution: Proxy ClientBase and Intercept calls to Dispose()
My solution was to proxy ClientBase by subclassing System.Runtime.Remoting.Proxies.RealProxy and to hijack or intercept calls to Dispose(). My first replacement for Dispose() went something like this:
if (_client.State == CommunicationState.Faulted) _client.Abort();
else ((IDisposable)_client).Dispose();
(Note that _client is a typed reference to the target of the proxy.)
Problems with NetTcpBinding
I thought that this had nailed it, initially, but then I discovered a problem in production: under certain scenarios that were fiendishly difficult to reproduce, I found that channels using a NetTcpBinding were not closing properly in the unfaulted case, even though Dispose was being called on _client.
I had an ASP.NET MVC Application using my proxy implementation to connect to a WCF Service using a NetTcpBinding on the local network, hosted within a Windows NT Service on a service cluster with only one node. When I load-tested the MVC Application, certain endpoints on the WCF Service (which was using port-sharing) would stop responding after a while.
I struggled to reproduce this: the same components running across the LAN between two developer's machines worked perfectly; a console application hammering the real WCF endpoints (running on the staging service cluster) with many processes and many threads in each worked; configuring the MVC Application on the staging server to connect to the endpoints on a developer's machine worked under load; running the MVC Application on a developer's machine and connecting to the staging WCF endpoints worked. The last scenario only worked under IIS Express, however, and this was a breakthrough. The endpoints would sieze up when load-testing the MVC Application under full-fat IIS on a developer's machine, connecting to the staging service cluster.
Solution: Close the Channel
After failing to understand the problem and reading many, many pages of the MSDN and other sources that claimed the problem shouldn't exist at all, I tried a long-shot and changed my Dispose() work-around to...
if (_client.State == CommunicationState.Faulted) _client.Abort();
else if (_client.State == CommunicationState.Opened)
{
((IContextChannel)_client.Channel).Close();
((IDisposable)_client).Dispose();
}
else ((IDisposable)_client).Dispose();
... and the problem stopped occurring in all test setups and under load in the staging environment!
Why?
Can anyone explain what might have been happening and why explicitly closing the Channel before calling Dispose() solved it? As far as I can tell, this shouldn't be necessary.
Finally, I return to the opening question: What is the correct way to Dispose a WCF Proxy? Is my replacement for Dispose() adequate?
The issue, as far as I have been able to understand, is that calling Dispose disposes off the handle, but doesn't actually close the channel, which then holds on to the resources and then eventually times out.
This is why your service stopped responding after a while during load testing: because the initial calls held on to resources longer than you thought they would, and later calls could then not avail those resources.
I came up with the following solution. The premise of the solution is that calling Dispose should be enough to dispose off the handle as well as close the channel. The additional benefit is that if the client ends up in a faulted state, it is recreated so that subsequent calls succeed.
If ServiceClient<TService> is injected into another class via a dependency injection framework like Ninject, then all resources will properly be released.
NB: Please note that in the case of Ninject, the binding must define a scope, i.e., it must not be missing an InXyzScope or be defined with an InTransientScope. If no scope makes sense, then use InCallScope.
Here's what I came up with:
public class ServiceClient<TService> : IDisposable
{
private readonly ChannelFactory<TService> channelFactory;
private readonly Func<TService> createChannel;
private Lazy<TService> service;
public ServiceClient(ChannelFactory<TService> channelFactory)
: base()
{
this.channelFactory = channelFactory;
this.createChannel = () =>
{
var channel = ChannelFactory.CreateChannel();
return channel;
};
this.service = new Lazy<TService>(() => CreateChannel());
}
protected ChannelFactory<TService> ChannelFactory
{
get
{
return this.channelFactory;
}
}
protected Func<TService, bool> IsChannelFaulted
{
get
{
return (service) =>
{
var channel = service as ICommunicationObject;
if (channel == null)
{
return false;
}
return channel.State == CommunicationState.Faulted;
};
}
}
protected Func<TService> CreateChannel
{
get
{
return this.createChannel;
}
}
protected Action<TService> DisposeChannel
{
get
{
return (service) =>
{
var channel = service as ICommunicationObject;
if (channel != null)
{
switch (channel.State)
{
case CommunicationState.Faulted:
channel.Abort();
break;
case CommunicationState.Closed:
break;
default:
try
{
channel.Close();
}
catch (CommunicationException)
{
}
catch (TimeoutException)
{
}
finally
{
if (channel.State != CommunicationState.Closed)
{
channel.Abort();
}
}
break;
}
}
};
}
}
protected Action<ChannelFactory<TService>> DisposeChannelFactory
{
get
{
return (channelFactory) =>
{
var disposable = channelFactory as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
};
}
}
public void Dispose()
{
DisposeChannel(this.service.Value);
DisposeChannelFactory(this.channelFactory);
}
public TService Service
{
get
{
if (this.service.IsValueCreated && IsChannelFaulted(this.service.Value))
{
DisposeChannel(this.service.Value);
this.service = new Lazy<TService>(() => CreateChannel());
}
return this.service.Value;
}
}
}
I am using Asp.Net MVC and NHibernate.
Some of my Global.asax file is shown below:
public override void Init()
{
base.Init();
// The WebSessionStorage must be created during the Init() to tie in HttpApplication events
webSessionStorage = new WebSessionStorage(this);
}
/// <summary>
/// Due to issues on IIS7, the NHibernate initialization cannot reside in Init() but
/// must only be called once. Consequently, we invoke a thread-safe singleton class to
/// ensure it's only initialized once.
/// </summary>
protected void Application_BeginRequest(object sender, EventArgs e)
{
//the following code sets up the NHibernate Session Factory
NHibernateInitializer.Instance().InitializeNHibernateOnce(
() => InitializeNHibernateSession());
}
Whenever the AppPool recycles the next request is taking a while to execute due to it having to wait for the NHibernateSessionFactory to initialise. After that everything is fine until the next app pool recycle.
Now I'd like to move the initialization into the Application_Start method, so that when the pool recycles, the restart does the heavy lifting PRIOR to the next request coming in. However the comment "Due to issues on IIS7" which comes from S#arp architecture made me realise it's not that simple.
I did find an article: http://scottsdalewebstudio.com/blog/mvc/mvc-sharp-iis7-nhibernate/ which suggests that setting IIS to use "Classic Mode" fixes it - is this the only way?
I had my NHibernate session management setup like follows:
protected MvcApplication()
{
BeginRequest += delegate
{
NHibernateSessionManager.Instance.OpenSession();
};
EndRequest += delegate
{
NHibernateSessionManager.Instance.CloseSession();
};
}
And for when I needed to save to the database, I made an ActionFilterAttribute that looked like this:
public class TransactionAttribute: ActionFilterAttribute
{
private ITransaction _currentTransaction;
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
_currentTransaction = NHibernateSessionManager.Instance.CurrentSession.Transaction;
_currentTransaction.Begin();
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (_currentTransaction.IsActive)
{
if (filterContext.Exception == null)
_currentTransaction.Commit();
else
{
_currentTransaction.Rollback();
}
}
_currentTransaction.Dispose();
}
}
and then I could just add [Transaction] to my action method. This seemed to work in initial testing, but I then I tried using at HttpWebRequest to call an action method from another app multiple times and I had issues. Testing with Fiddler I setup a POST request and then fired them off in quick succession and it showed up the following:
THe red ones are various errors that I believe is to do with threading.
My NHibernateSessionManager uses the HTtpContext to store the session like this:
public ISession CurrentSession
{
get { return (ISession)HttpContext.Current.Items["current.session"]; }
set { HttpContext.Current.Items["current.session"] = value; }
}
So, to fixed it, I moved my Transaction code into my BeginRequest and EndRequest methods - and then I could fire off heaps in succession.
My question is - why did this fix it? I would have thought that I would have had something similar to this:
Begin Request - opens session
OnActionExecuting - starts transaction
action code
OnActionExecuted - commits transaction
End Request - closes session
and that this would be unique to each request, so it shouldn't interfere with one another, because there should be a different HttpContext for each request shouldn't there? Or are they shared or something??
Can someone enlighten me?
Quote from the release notes of ASP.NET MVC 3:
In previous versions of ASP.NET MVC,
action filters were created per
request except in a few cases. This
behavior was never a guaranteed
behavior but merely an implementation
detail and the contract for filters
was to consider them stateless. In
ASP.NET MVC 3, filters are cached more
aggressively. Therefore, any custom
action filters which improperly store
instance state might be broken.
This basically means that the _currentTransaction instance you have in your action filter might not be what you think it is. So be careful how/when is this property injected => it is not clear from the code you have shown.
I use Entity Framework 4 and ASP.NET MVC 3. I made a custom membership provider and use Ninject to inject an EFAccountRepository into it (Bound IAccountRepository to EFAccountRepository).
This account repository has an ObjectContext injected into it. I also use this repository (and others) in my controllers. For this reason when I bound IContext to my ObjectContext, I set the scope to "per request" so the ObjectContext only lives in one request and is shared between the repositories.
I am sometimes get the following error when trying to log in:"The ObjectContext instance has been disposed and can no longer be used for operations that require a connection."
I wonder how often the membership provider gets instantiated. I injected the repository into the membership provider by marking the repository property with [Inject] and calling Kernel.Inject in the Application_Start function in the global.asax file.
If the provider gets instantiated more than once I would have to inject again I suppose. However, I don't get a null pointer exception, so I don't think that's it.
Update 1
Here's some code:
MyNinjectModule.cs
public override void Load()
{
Bind<IMyContext>().To<MyObjectContext>().InRequestScope();
// put bindings here
Bind<IAccountRepository>().To<EFAccountRepository>
}
Global.asax
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
var kernel = new StandardKernel(new MyNinjectModule());
ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory(kernel));
kernel.Inject(Membership.Provider);
}
MyMembershipProvider.cs
[Inject]
public IAccountRepository accountRepository { get; set; }
public override bool ValidateUser(string username, string password)
{
// I get the exception here.
return (from a in accountRepository.Accounts
where a.UserName == username
&& a.Password == password
select true).SingleOrDefault();
}
EFAccountRepository.cs
private readonly IMyContext context;
public EFAccountRepository(IMyContext context)
{
this.context = context;
}
public IQueryable<Account> Accounts
{
get { return context.Accounts; }
}
MyObjectContext.cs
public class MyObjectContext : ObjectContext, IMyContext
{
public IObjectSet<Account> Accounts { get; private set; }
public FlorenceObjectContext()
: this("name=DomainModelContainer")
{
}
public FlorenceObjectContext(string connectionString)
: base(connectionString, "DomainModelContainer")
{
Accounts = CreateObjectSet<Account>();
}
}
PS: I'm always open to comments on my code in general ;).
The exception says that you are incorrectly handling disposing of your context. Somewhere you call context.Dispose (or have context in using) but after that you want to use context again which is not possible because context is already disposed. If you are using per request context you must dispose context only once at the end of request processing (when you are sure that no code will use the context).
You didn't specify a scope for your EFAccountRepository binding so it defaults to .InTransientScope(). This means a new instance of the object will be created each time you resolve the IAccountRepository [refer to https://github.com/ninject/ninject/wiki/Object-Scopes ].
Also, transient scope objects
are automatically garbage collected as soon as there are no references to them [Ninject doesn't cache them]
are not automatically disposed by anyone
In contrast, you bound MyObjectContext to IObjectContext .InRequestScope(). This means it will be reused when you are in the same HTTP request handling operation.
Also, a request scope object
won't be garbage collected until your http request is done
might be automatically disposed once the HTTP request is done, if it's IDisposable. [Not sure precisely when, but from other questions I have seen I suspect it depends on the version of Ninject]
Now, ObjectContext is IDisposable, so it seems reasonable to conclude that
an object reference to the IObjectContext exists, and you are using the IObjectContext outside of the HTTP request which it was created in.
Ninject has automatically disposed of it, since the HTTP request has completed.
In order to solve the issue, you need to figure out why your object context object reference is surviving so long, and consider either eliminating the long-livedness... or removing its dependency on short-lived (request-scoped) objects.
[note clearly the question already has an accepted answer, but I think the accepted answer was kind of hard to understand.]