Ben*_*ter 10 structuremap nhibernate asp.net-mvc-3
我一直在玩ASP.NET MVC RC2中的DI支持.
我已经为NHibernate的每个请求实现了会话,并且需要注入ISession我的"工作单元"动作过滤器.
如果我直接引用StructureMap容器(ObjectFactory.GetInstance)或使用DependencyResolver来获取我的会话实例,一切正常:
ISession Session {
get { return DependencyResolver.Current.GetService<ISession>(); }
}
Run Code Online (Sandbox Code Playgroud)
但是,如果我尝试使用我的StructureMap过滤器提供程序(继承FilterAttributeFilterProvider),我在请求结束时提交NHibernate事务时遇到问题.
就像ISession在请求之间共享对象一样.我经常看到这一点,因为我的所有图像都是通过MVC控制器加载的,因此我在正常页面加载时创建了20个左右的NHibernate会话.
我在动作过滤器中添加了以下内容:
ISession Session {
get { return DependencyResolver.Current.GetService<ISession>(); }
}
public ISession SessionTest { get; set; }
public override void OnResultExecuted(System.Web.Mvc.ResultExecutedContext filterContext) {
bool sessionsMatch = (this.Session == this.SessionTest);
Run Code Online (Sandbox Code Playgroud)
使用StructureMap过滤器提供程序注入SessionTest.
我发现在一个有20个图像的页面上,"sessionsMatch"对于2-3个请求是假的.
我对会话管理的StructureMap配置如下:
For<ISessionFactory>().Singleton().Use(new NHibernateSessionFactory().GetSessionFactory());
For<ISession>().HttpContextScoped().Use(ctx => ctx.GetInstance<ISessionFactory>().OpenSession());
Run Code Online (Sandbox Code Playgroud)
在global.asax中,我在每个请求结束时调用以下内容:
public Global() {
EndRequest += (sender, e) => {
ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects();
};
}
Run Code Online (Sandbox Code Playgroud)
这个配置线程安全吗?以前我使用自定义将依赖项注入到同一个过滤器中IActionInvoker.当我开始遇到上述问题时,这一直工作到MVC 3 RC2,这就是为什么我认为我会尝试使用过滤器提供程序.
任何帮助,将不胜感激.
我正在使用NHibernate 3 RC和最新版本的StructureMap
更新:
以下是我的实现DependencyResolver和FilterAttributeFilterProvider:
public class StructureMapDependencyResolver : IDependencyResolver {
private readonly IContainer container;
public StructureMapDependencyResolver(IContainer container) {
this.container = container;
}
public object GetService(Type serviceType) {
var instance = container.TryGetInstance(serviceType);
if (instance==null && !serviceType.IsAbstract){
instance = AddTypeAndTryGetInstance(serviceType);
}
return instance;
}
private object AddTypeAndTryGetInstance(Type serviceType) {
container.Configure(c=>c.AddType(serviceType,serviceType));
return container.TryGetInstance(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType) {
return container.GetAllInstances(serviceType).Cast<object>();
}
}
public class StructureMapFilterAttributeFilterProvider : FilterAttributeFilterProvider
{
private readonly IContainer container;
public StructureMapFilterAttributeFilterProvider(IContainer container) {
this.container = container;
}
protected override IEnumerable<FilterAttribute> GetControllerAttributes(ControllerContext controllerContext, ActionDescriptor actionDescriptor) {
return BuildUp(base.GetControllerAttributes(controllerContext, actionDescriptor));
}
protected override IEnumerable<FilterAttribute> GetActionAttributes(ControllerContext controllerContext, ActionDescriptor actionDescriptor) {
return BuildUp(base.GetActionAttributes(controllerContext, actionDescriptor));
}
private IEnumerable<FilterAttribute> BuildUp(IEnumerable<FilterAttribute> attributes) {
foreach (var attr in attributes)
container.BuildUp(attr);
return attributes;
}
}
Run Code Online (Sandbox Code Playgroud)
以为我会回来提供解决方案.
正如@Thomas上面指出的那样,Action Filters现在缓存在MVC 3中.这意味着如果你注入一个预期寿命较短的对象(例如http请求),它将被缓存.
要修复,而不是注入ISession我们注入Func<ISession>.然后每次我们需要访问ISession时,我们都会调用该函数.这样可以确保即使缓存了ActionFilter,也可以正确确定ISession的范围.
我不得不像这样配置StructureMap来注入"懒惰"实例(不幸的是它不像Ctor注入那样自动注入一个惰性实例):
x.SetAllProperties(p => {
p.OfType<Func<ISession>>();
});
Run Code Online (Sandbox Code Playgroud)
我更新的ActionFilter如下:
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class UnitOfWorkAttribute : ActionFilterAttribute {
public Func<ISession> SessionFinder { get; set; }
public override void OnActionExecuting(System.Web.Mvc.ActionExecutingContext filterContext) {
var session = SessionFinder();
session.BeginTransaction();
}
public override void OnResultExecuted(System.Web.Mvc.ResultExecutedContext filterContext) {
var session = SessionFinder();
var txn = session.Transaction;
if (txn == null || !txn.IsActive) return;
if (filterContext.Exception == null || filterContext.ExceptionHandled)
{
session.Transaction.Commit();
}
else
{
session.Transaction.Rollback();
session.Clear();
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2749 次 |
| 最近记录: |