ASP.net MVC 过滤器中的 NHibernate 工作单元使用 AutoFac
NHibernate unit of work in ASP.net MVC filter using AutoFac
我正在尝试使用 NHibernate 和事务为每个请求创建一个工作单元。我在 MVC 中有一个全局应用的过滤器。它看起来像下面这样。
public class TransactionAttribute : ActionFilterAttribute
{
private ISession _session;
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//Constructor does NOT get run per request.
_session = DependencyResolver.Current.GetService<ISession>();
_session.FlushMode = FlushMode.Commit;
_session.BeginTransaction();
base.OnActionExecuting(filterContext);
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.Exception == null)
{
_session.Transaction.Commit();
}
else
{
_session.Transaction.Rollback();
}
_session.Dispose();
base.OnActionExecuted(filterContext);
}
}
请注意,我正在使用依赖项解析器来获取服务,这意味着它调用每个请求而不是缓存的构造函数,或者我相信是这样。
现在我的 Autofac 模块如下所示:
public class AutoFacModule
{
public static IContainer Build()
{
return Build(new ContainerBuilder());
}
public static IContainer Build(ContainerBuilder builder)
{
// You can register controllers all at once using assembly scanning...
builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder.RegisterModule<AutofacWebTypesModule>();
builder.Register(x => NHibernateSetup.CreateSessionFactory()).SingleInstance();
builder.Register(x => x.Resolve<ISessionFactory>().OpenSession()).InstancePerHttpRequest();
//Build Registry.
var returnContainer = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(returnContainer));
return returnContainer;
}
}
因此,我认为我会为每个 HTTP 请求获得一个新的 _session。但事实似乎并非如此。如果我在 MVC 操作中设置一个断点,并加载一个页面,等待它到达断点,然后启动一个新选项卡并加载同一页面,等待它到达断点,然后让两者继续。我得到一个错误:
Transaction not successfully started
当我尝试提交时。我认为这是因为第一个请求已经提交了事务。这似乎是因为两个请求共享一个 ISession 而不是每个请求都是唯一的。
发帖到 Whosebug 的行为突然让一切都变得有意义了。
所以出于某种原因,它与全局注册过滤器有关。因为有点懒,所以做了以下
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new TransactionAttribute());
}
所以基本上将每个请求包装在一个事务中。这似乎在使用 DependencyResolver 时不起作用。如果我删除它,并直接在方法上添加属性,事情就会开始起作用。
作为站点说明,我还发现了一种不使用 Autofac 的构造函数来注入属性的不同方法:http://alexmg.com/filterattribute-property-injection-in-autofac-mvc-3-integration/ 这似乎是在 autofac 下处理过滤器时的默认方式。
关于这种方法的一些事情让我有点恼火,因为像这样的 属性 public 看起来有点奇怪(因为它真的不应该由任何人设置,除了在构造函数中)。但是,它确实使事情能够进行单元测试(尽管我假设依赖项解析器方式也可以进行单元测试)。
所以现在,我将把属性直接放在操作上。但它可能需要被研究,因为像 logging/error 这样的处理可能需要注入肯定会在 globalfilters 集合中?
我正在尝试使用 NHibernate 和事务为每个请求创建一个工作单元。我在 MVC 中有一个全局应用的过滤器。它看起来像下面这样。
public class TransactionAttribute : ActionFilterAttribute
{
private ISession _session;
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//Constructor does NOT get run per request.
_session = DependencyResolver.Current.GetService<ISession>();
_session.FlushMode = FlushMode.Commit;
_session.BeginTransaction();
base.OnActionExecuting(filterContext);
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.Exception == null)
{
_session.Transaction.Commit();
}
else
{
_session.Transaction.Rollback();
}
_session.Dispose();
base.OnActionExecuted(filterContext);
}
}
请注意,我正在使用依赖项解析器来获取服务,这意味着它调用每个请求而不是缓存的构造函数,或者我相信是这样。
现在我的 Autofac 模块如下所示:
public class AutoFacModule
{
public static IContainer Build()
{
return Build(new ContainerBuilder());
}
public static IContainer Build(ContainerBuilder builder)
{
// You can register controllers all at once using assembly scanning...
builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder.RegisterModule<AutofacWebTypesModule>();
builder.Register(x => NHibernateSetup.CreateSessionFactory()).SingleInstance();
builder.Register(x => x.Resolve<ISessionFactory>().OpenSession()).InstancePerHttpRequest();
//Build Registry.
var returnContainer = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(returnContainer));
return returnContainer;
}
}
因此,我认为我会为每个 HTTP 请求获得一个新的 _session。但事实似乎并非如此。如果我在 MVC 操作中设置一个断点,并加载一个页面,等待它到达断点,然后启动一个新选项卡并加载同一页面,等待它到达断点,然后让两者继续。我得到一个错误:
Transaction not successfully started
当我尝试提交时。我认为这是因为第一个请求已经提交了事务。这似乎是因为两个请求共享一个 ISession 而不是每个请求都是唯一的。
发帖到 Whosebug 的行为突然让一切都变得有意义了。
所以出于某种原因,它与全局注册过滤器有关。因为有点懒,所以做了以下
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new TransactionAttribute());
}
所以基本上将每个请求包装在一个事务中。这似乎在使用 DependencyResolver 时不起作用。如果我删除它,并直接在方法上添加属性,事情就会开始起作用。
作为站点说明,我还发现了一种不使用 Autofac 的构造函数来注入属性的不同方法:http://alexmg.com/filterattribute-property-injection-in-autofac-mvc-3-integration/ 这似乎是在 autofac 下处理过滤器时的默认方式。
关于这种方法的一些事情让我有点恼火,因为像这样的 属性 public 看起来有点奇怪(因为它真的不应该由任何人设置,除了在构造函数中)。但是,它确实使事情能够进行单元测试(尽管我假设依赖项解析器方式也可以进行单元测试)。
所以现在,我将把属性直接放在操作上。但它可能需要被研究,因为像 logging/error 这样的处理可能需要注入肯定会在 globalfilters 集合中?