Reputation: 25573
On ASP.NET MVC 2 I have an ActionFilterAttribute
called [Transaction]
that starts an NHibernate transaction before executing the action and commits or rolls it back afterward, depending on whether or not an exception was thrown. The ISession
instance is HttpRequestScoped()
and injected by Autofac. It looks like this and works great:
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public sealed class TransactionAttribute : ActionFilterAttribute
{
private ITransaction transaction;
public TransactionAttribute()
{
this.Order = 0;
}
public ISession Session
{
get;
set;
}
public override void OnActionExecuted(
ActionExecutedContext filterContext)
{
if (this.Session != null && this.transaction != null)
{
try
{
if (this.transaction.IsActive)
{
if (filterContext.Exception == null)
{
this.transaction.Commit();
}
else
{
this.transaction.Rollback();
}
}
}
finally
{
this.transaction.Dispose();
this.transaction = null;
}
}
}
public override void OnActionExecuting(
ActionExecutingContext filterContext)
{
if (this.Session != null)
{
this.transaction = this.Session.BeginTransaction();
}
}
}
Fantastic. Seems to be a common pattern.
In the ASP.NET MVC 3 notes, I see this little blurb under "Breaking Changes" (emphasis mine):
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.
Oops.
Thanks for any insight.
Upvotes: 7
Views: 5992
Reputation: 1390
I just asked a similar question on google forums. Here is the link https://groups.google.com/forum/#!topic/autofac/a0qqp2b3WA8
I got the answer:
builder.RegisterType<ExtensibleActionInvoker>().As<IActionInvoker>();
builder.RegisterControllers(Assembly.GetExecutingAssembly()).InjectActionInvoker();
Then you can use property injection in your attributes.
Upvotes: 7
Reputation: 1541
Oh yuck.... Nicholas, you might need to store your ISession and Transaction in HttpContext.Items, which you should be able to get to via the ActionExecutedContext/ActionExecutingContext (perhaps setting it in the OnActionExecuting event handler), instead of keeping them in instance members. Either that, or you could call a ServiceLocator inside your filter to grab them for you (also yuck).
Now I have to go look through my MVC 3 code and see if I have any similar problems myself!
Upvotes: 2