8
\$\begingroup\$

I've recently been learning (and struggling with) integrating AutoFac, NHibernate & ASP.NET Web API. I have found several tutorials with code that did not work as anticipated but managed to finally find a working solution.

Essentially what I'm doing is registering a singleton of my SessionFactory to the WebApiApplication.SessionFactory object, registering a per-API-request ISession & IClientRepository. After these are registered, I'm creating a controller with a DI'ed IClientRepository (which in turn has an ISession injected which creates a new session as seen in the code below).

My controllers are marked with a custom TranscationActionFilterAttribute to bind (or create) a session. The issue I was initially encountering while implementing this pattern is that considering a new session is created every time IClientRepository was injected with an ISession, the session was never automatically bound and the code in my Transcation action filter would always create an extraneous session, thereby making updates and deletes not function properly. I got around this by binding the ISession in the constructor of my ClientRepository.

Is this safe?

Global.asax:

public class WebApiApplication : System.Web.HttpApplication
{
 public static ISessionFactory SessionFactory { get; set; }
 public static void RegisterGlobalFilters(GlobalFilterCollection filters)
 {
 }
 protected void Application_Start()
 {
 AreaRegistration.RegisterAllAreas();
 FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
 RouteConfig.RegisterRoutes(RouteTable.Routes);
 BundleConfig.RegisterBundles(BundleTable.Bundles);
 var configuration = GlobalConfiguration.Configuration;
 var builder = new ContainerBuilder();
 // Register ISessionFactory as Singleton
 builder.Register(x => NHibernateConfigurator.BuildSessionFactory()).SingleInstance();
 // Register API controller types using assembly scanning.
 builder.RegisterAssemblyTypes(
 Assembly.GetExecutingAssembly())
 .Where(t =>
 !t.IsAbstract && typeof(ApiController).IsAssignableFrom(t));
 // Register ISession as instance per web request
 builder.Register(x => x.Resolve<ISessionFactory>().OpenSession()).InstancePerApiRequest();
 // Register clients controller as instance per web request
 builder.RegisterType<ClientRepository>().As<IClientRepository>().InstancePerApiRequest();
 // Register all controllers
 builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
 .AsSelf();
 // Override default dependency resolver to use Autofac
 var container = builder.Build();
 // Set the dependency resolver implementation.
 var resolver = new AutofacWebApiDependencyResolver(container);
 configuration.DependencyResolver = resolver;
 }
}

TransactionAttribute.cs:

public class TransactionAttribute : System.Web.Http.Filters.ActionFilterAttribute
{
 private ISessionFactory SessionFactory { get; set; }
 public TransactionAttribute()
 {
 SessionFactory = WebApiApplication.SessionFactory;
 }
 public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
 {
 if (!CurrentSessionContext.HasBind(SessionFactory))
 {
 CurrentSessionContext.Bind(SessionFactory.OpenSession());
 }
 var session = SessionFactory.GetCurrentSession();
 session.BeginTransaction();
 }
 public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
 {
 var session = SessionFactory.GetCurrentSession();
 var transcation = session.Transaction;
 if (transcation != null && transcation.IsActive)
 {
 transcation.Commit();
 }
 session = CurrentSessionContext.Unbind(SessionFactory);
 session.Close();
 }
}

And the constructor for my repository:

 public ClientRepository(ISession session) 
 {
 if (session == null) throw new ArgumentNullException("nhSession");
 this._session = session;
 CurrentSessionContext.Bind(_session);
 }
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Oct 25, 2012 at 20:05
\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

This is not going to answer your question directly but..

By definition I suppose that Code Review allows me to suggest and share subjective ideas (to be determined)...

By convention, stuff that needs to be done on the application start can be located in a App_Start folder.

Here's a template for AutoFac, ~/App_Start/AutofacMvcConfig.cs:

using System.Web.Mvc;
using Autofac;
using Autofac.Integration.Mvc;
using Models;
using MvcApplication.App_Start;
[assembly: WebActivator.PreApplicationStartMethod(typeof(AutofacMvcConfig), "Start")]
namespace MvcApplication.App_Start
{
 public class AutofacMvcConfig
 {
 public static void Start()
 {
 var builder = new ContainerBuilder();
 builder.RegisterControllers(typeof(MvcApplication).Assembly);
 builder.RegisterType<TodoCommands>().As<ITodoCommands>().InstancePerHttpRequest();
 builder.RegisterType<TodoQueries>().As<ITodoQueries>();
 var container = builder.Build();
 // Install-Package Autofac.Mvc3
 DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
 }
 }
}

Readings

Keywords: mvc, unit of work, autofac, actionfilterattribute

answered Nov 13, 2012 at 19:47
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.