C# 使用Autofac的每个HttpRequest的会话。NHProf“显示”;“多个会话”;不通过DependencyResolver访问ISession时发出警告
我已经使用Autofac成功地实现了每个HttpRequest的会话 我对我的实现不满意,因为我正在经历C# 使用Autofac的每个HttpRequest的会话。NHProf“显示”;“多个会话”;不通过DependencyResolver访问ISession时发出警告,c#,session,nhibernate,autofac,C#,Session,Nhibernate,Autofac,我已经使用Autofac成功地实现了每个HttpRequest的会话 我对我的实现不满意,因为我正在经历依赖解析程序,并且不依赖AutoFac提供的参数。如果我依赖AutoFac提供的ISession参数,那么我会收到NHProf发出的警告,指示有多个会话正在使用。如果我通过DependencyResolver,NHProf发出的警告将消失,但我觉得用法不正确 我遵循了此处概述的Autofac+MVC4.0指南: 我还将本指南用作参考。它表示可以接受ISession作为构造函数参数: 以下是我如
依赖解析程序
,并且不依赖AutoFac提供的参数。如果我依赖AutoFac提供的ISession
参数,那么我会收到NHProf发出的警告,指示有多个会话正在使用。如果我通过DependencyResolver
,NHProf发出的警告将消失,但我觉得用法不正确
我遵循了此处概述的Autofac+MVC4.0指南:
我还将本指南用作参考。它表示可以接受ISession作为构造函数参数:
以下是我如何构建Autofac容器:
public class AutofacRegistrations
{
public static void RegisterAndSetResolver()
{
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterControllers(Assembly.GetExecutingAssembly());
// Only generate one SessionFactory ever because it is expensive.
containerBuilder.Register(x => new NHibernateConfiguration().Configure().BuildSessionFactory()).SingleInstance();
// Everything else wants an instance of Session per HTTP request, so indicate that:
containerBuilder.Register(x => x.Resolve<ISessionFactory>().OpenSession()).As<ISession>().InstancePerHttpRequest();
containerBuilder.Register(x => LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType)).As<ILog>().InstancePerHttpRequest();
containerBuilder.RegisterType<NHibernateDaoFactory>().As<IDaoFactory>().InstancePerHttpRequest();
containerBuilder.RegisterType<StreamusManagerFactory>().As<IManagerFactory>().InstancePerHttpRequest();
// containerBuilder.RegisterModule adds all the required http modules to support per web request lifestyle and change default controller factory to the one that uses Autofac.
containerBuilder.RegisterModule(new AutofacWebTypesModule());
IContainer container = containerBuilder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
}
公共类自动传真注册
{
公共静态无效注册表AndSetResolver()
{
var containerBuilder=新的containerBuilder();
containerBuilder.RegisterController(Assembly.getExecutionGassembly());
//仅生成一个SessionFactory,因为它非常昂贵。
Register(x=>newNHibernateConfiguration().Configure().BuildSessionFactory()).SingleInstance();
//其他所有内容都希望每个HTTP请求都有一个会话实例,因此请指出:
containerBuilder.Register(x=>x.Resolve().OpenSession()).As().InstancePerHttpRequest();
containerBuilder.Register(x=>LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType)).As().InstancePerhtPrequest();
containerBuilder.RegisterType().As().InstancePerHttpRequest();
containerBuilder.RegisterType().As().InstancePerHttpRequest();
//containerBuilder.RegisterModule添加所有必需的http模块以支持每个web请求的生活方式,并将默认控制器工厂更改为使用Autofac的工厂。
RegisterModule(新的AutofacWebTypesModule());
IContainer container=containerBuilder.Build();
SetResolver(新的AutofacDependencyResolver(容器));
}
}
这是我的基本控制器类。请注意注释掉的代码,该代码最初接受会话作为参数:
public abstract class StreamusController : Controller
{
protected readonly ILog Logger;
protected new readonly ISession Session;
protected StreamusController(ILog logger, /*ISession session*/)
{
if (logger == null) throw new ArgumentNullException("logger");
//if (session == null) throw new ArgumentNullException("session");
Logger = logger;
// TODO: Is this different than passing ISession into Controller with AutoFac?
Session = DependencyResolver.Current.GetService<ISession>();
//Session = session;
}
}
公共抽象类StreamusController:Controller
{
受保护的只读ILog记录器;
受保护的新只读会话;
受保护的StreamusController(ILog记录器,/*ISession会话*/)
{
如果(logger==null)抛出新的ArgumentNullException(“logger”);
//如果(session==null)抛出新的ArgumentNullException(“session”);
记录器=记录器;
//TODO:这与使用AutoFac将ISession传递到控制器不同吗?
会话=DependencyResolver.Current.GetService();
//会话=会话;
}
}
根据我是将ISession用作参数还是通过DependencyResolver访问它,我在NHProf中体验到不同的结果。为什么?我的理解是这两种方法应该完全相同
作为参考,这里是我的惰性NHibernateConfiguration/ISessionFactory实现。我认为这与当前的问题没有太大关系:
public class NHibernateConfiguration
{
public FluentConfiguration Configure()
{
string connectionString = ConfigurationManager.ConnectionStrings["default"].ConnectionString;
FluentConfiguration fluentConfiguration = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008.ConnectionString(connectionString).ShowSql().FormatSql())
.Mappings(cfg => cfg.FluentMappings.AddFromAssemblyOf<UserMapping>())
.ExposeConfiguration(ConfigureStreamusDataAccess);
return fluentConfiguration;
}
private static void ConfigureStreamusDataAccess(Configuration configuration)
{
// NHibernate.Context.WebSessionContext - analogous to ManagedWebSessionContext above, stores the current session in HttpContext.
// You are responsible to bind and unbind an ISession instance with static methods of class CurrentSessionContext.
configuration.SetProperty("current_session_context_class", "web");
configuration.SetProperty("connection.isolation", "ReadUncommitted");
configuration.SetProperty("default_schema", "[Streamus].[dbo]");
configuration.SetProperty("generate_statistics", "true");
}
}
公共类NHibernateConfiguration
{
public FluentConfiguration Configure()
{
string connectionString=ConfigurationManager.connectionString[“默认值”]。connectionString;
FluentConfiguration FluentConfiguration=Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008.ConnectionString(ConnectionString.ShowSql().FormatSql())
.Mappings(cfg=>cfg.FluentMappings.AddFromAssemblyOf())
.ExposeConfiguration(配置StreamUSDataAccess);
返回流配置;
}
私有静态void配置StreamUSDataAccess(配置)
{
//NHibernate.Context.WebSessionContext-类似于上面的ManagedWebSessionContext,将当前会话存储在HttpContext中。
//您负责使用类CurrentSessionContext的静态方法绑定和解除绑定ISession实例。
SetProperty(“当前会话上下文类”、“web”);
SetProperty(“connection.isolation”、“ReadUncommitted”);
SetProperty(“默认的_模式”,“[Streamus].[dbo]”;
SetProperty(“生成_统计数据”、“true”);
}
}
以下是NHProf的屏幕截图,表示我的CreateMultiple操作上有多个会话,另一个屏幕截图不表示多个会话。第一个屏幕截图使用传入的ISession作为参数,第二个屏幕截图使用DependencyResolver:
我不知道为什么会发生这种情况,但您可以这样写注册:
containerBuilder.Register(x=>{
返回x.Resolve().OpenSession();//在此处设置断点
}).As().InstancePerHttpRequest();
在OpenSession()调用上设置一个断点,然后调试代码,查看每次调用调用堆栈时调用堆栈的样子。好的,所以我找到了罪魁祸首。这不是很明显 我使用AutoMapper将DTO映射到域和域。显然,这是一个错误 我的逻辑是这样的:
public static PlaylistItem Create(PlaylistItemDto playlistItemDto, IPlaylistManager playlistManager)
{
PlaylistItem playlistItem = new PlaylistItem
{
Cid = playlistItemDto.Cid,
Id = playlistItemDto.Id,
Playlist = playlistManager.Get(playlistItemDto.PlaylistId),
Sequence = playlistItemDto.Sequence,
Title = playlistItemDto.Title,
Video = Video.Create(playlistItemDto.Video)
};
return playlistItem;
}
- 应用程序启动
- AutofacRegistrations.RegisterAndSetResolver
- AutoMapper.SetMappings