简体   繁体   English

NHibernate Windsor每个请求的实现

[英]NHibernate windsor per-request implementaion

I used NHibernate and Castle Windsor Injection in my project. 我在项目中使用了NHibernate和Castle Windsor Injection。 My NHibernate implementation is like this: 我的NHibernate实现是这样的:

Component.For<ISessionFactory>().UsingFactoryMethod(CreateSessionFactory).LifestyleSingleton(),
Component.For<IUnitOfWork>().ImplementedBy<UnitOfWork>().LifestyleSingleton(),
Component.For<ISession>().UsingFactoryMethod(k => k.Resolve<ISessionFactory>().OpenSession()).LifestylePerWebRequest(),

If I want to double refresh page or open some page on new tab, I will get error which is 如果我想刷新页面两次或在新标签页上打开某些页面,则会收到以下错误消息:

ExecuteReader requires an open and available Connection. ExecuteReader需要一个开放且可用的连接。 The connection's current state is closed. 连接的当前状态为关闭。

Is there any mistake in my implementation? 我的执行过程中有任何错误吗? What is wrong? 怎么了? How can I solve that? 我该如何解决?

This is UnitOfWork Class: public UnitOfWork Current { get { if (_current == null) _current = new UnitOfWork(sessionFactory, Session); 这是UnitOfWork类:public UnitOfWork Current {get {if(_current == null)_current = new UnitOfWork(sessionFactory,Session); return _current; 返回_current; } } [ThreadStatic] private UnitOfWork _current; }} [ThreadStatic]私有UnitOfWork _current;

    /// <summary>
    /// Gets Nhibernate session object to perform queries.
    /// </summary>
    public ISession Session { get; get; }

    /// <summary>
    /// Reference to the session factory.
    /// </summary>
    private readonly ISessionFactory sessionFactory;

    /// <summary>
    /// Reference to the currently running transcation.
    /// </summary>
    private ITransaction transaction;

    /// <summary>
    /// Creates a new instance of NhUnitOfWork.
    /// </summary>
    /// <param name="sessionFactory"></param>
    public UnitOfWork(ISessionFactory _sessionFactory, ISession _session)
    {
        sessionFactory = _sessionFactory;
        Session = _session;
    }

    /// <summary>
    /// Opens database connection and begins transaction.
    /// </summary>
    public void BeginTransaction(IsolationLevel isoLevel=IsolationLevel.ReadCommitted)
    {
        transaction = Session.BeginTransaction(isoLevel);
    }

    /// <summary>
    /// Commits transaction and closes database connection.
    /// </summary>
    public void Commit()
    {
        transaction.Commit();
    }

    /// <summary>
    /// Rollbacks transaction and closes database connection.
    /// </summary>
    public void Rollback()
    {
        transaction.Rollback();
    }

    public void Dispose()
    {
        //Session.Dispose();
    }

If you are doing this in a web project and your PerWebRequest windsor Lifestyle suggests that, I would get rid of your unit of work implementation and work directly with the request events from gloabl.asax. 如果您在Web项目中执行此操作,并且您的PerWebRequest windsor Lifestyle建议,那么我将摆脱您的工作单元实现,直接使用gloabl.asax的请求事件进行工作。 In the web, the unit of work is the request. 在Web中,工作单位是请求。 I also like to wire up Windsor using installers. 我还喜欢使用安装程序连接Windsor。 Here's a config that works for me. 这是一个适合我的配置。

public class MvcApplication : HttpApplication
{
    private const String Sessionkey = "current.session";
    private static IWindsorContainer Container { get; set; }
    private static ISessionFactory SessionFactory { get; set; }

    public static ISession CurrentSession
    {
        get { return (ISession) HttpContext.Current.Items[Sessionkey]; }
        private set { HttpContext.Current.Items[Sessionkey] = value; }
    }

    protected void Application_Start()
    {
        Version version = Assembly.GetExecutingAssembly().GetName().Version;
        Application["Version"] = String.Format("{0}.{1}", version.Major, version.Minor);
        Application["Name"] = ConfigurationManager.AppSettings["ApplicationName"];

        //create empty container
        //scan this assembly for any installers to register services/components with Windsor
        Container = new WindsorContainer().Install(FromAssembly.This());

        //API controllers use the dependency resolver and need to be initialized differently than the mvc controllers
        GlobalConfiguration.Configuration.DependencyResolver = new WindsorDependencyResolver(Container.Kernel);

        //tell ASP.NET to get its controllers from Castle
        ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(Container.Kernel));

        //initialize NHibernate
        ConnectionStringSettings connectionString = ConfigurationManager.ConnectionStrings[Environment.MachineName];

        if (connectionString == null)
            throw new ConfigurationErrorsException(String.Format("Connection string {0} is empty.",
                Environment.MachineName));

        if (String.IsNullOrWhiteSpace(connectionString.ConnectionString))
            throw new ConfigurationErrorsException(String.Format("Connection string {0} is empty.",
                Environment.MachineName));

        string mappingAssemblyName = ConfigurationManager.AppSettings["NHibernate.Mapping.Assembly"];

        if (String.IsNullOrWhiteSpace(mappingAssemblyName))
            throw new ConfigurationErrorsException(
                "NHibernate.Mapping.Assembly key not set in application config file.");

        var nh = new NHInit(connectionString.ConnectionString, mappingAssemblyName);
        nh.Initialize();
         SessionFactory = nh.SessionFactory;

        AutoMapConfig.RegisterMaps();
        AreaRegistration.RegisterAllAreas();
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
        ModelBinderConfig.RegisterModelBinders(ModelBinders.Binders);

        AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;
    }

    protected void Application_OnEnd()
    {
        //dispose Castle container and all the stuff it contains
        Container.Dispose();
    }

    protected void Application_BeginRequest() { CurrentSession = SessionFactory.OpenSession(); }

    protected void Application_EndRequest()
    {
        if (CurrentSession != null)
            CurrentSession.Dispose();
    }

} } }}

Here's my NhInit class 这是我的NhInit课程

public class NHInit : NHibernateInitializer
{
    public NHInit(String connectionString, String mappingAssemblyName) : base(connectionString, mappingAssemblyName)
    {
    }
}

NHibernateInitializer NHibernateInitializer

public abstract class NHibernateInitializer : IDomainMapper
{
    protected Configuration Configure;
    private ISessionFactory _sessionFactory;
    private readonly ModelMapper _mapper = new ModelMapper();
    private Assembly _mappingAssembly;
    private readonly String _mappingAssemblyName;
    private readonly String _connectionString;

    protected NHibernateInitializer(String connectionString, String mappingAssemblyName)
    {
        if (String.IsNullOrWhiteSpace(connectionString))
            throw new ArgumentNullException("connectionString", "connectionString is empty.");

        if (String.IsNullOrWhiteSpace(mappingAssemblyName))
            throw new ArgumentNullException("mappingAssemblyName", "mappingAssemblyName is empty.");

        _mappingAssemblyName = mappingAssemblyName;
        _connectionString = connectionString;
    }

    public ISessionFactory SessionFactory
    {
        get
        {
            return _sessionFactory ?? (_sessionFactory = Configure.BuildSessionFactory());
        }
    }

    private Assembly MappingAssembly
    {
        get
        {
            return _mappingAssembly ?? (_mappingAssembly = Assembly.Load(_mappingAssemblyName));
        }
    }

    public void Initialize()
    {
        Configure = new Configuration();
        Configure.EventListeners.PreInsertEventListeners = new IPreInsertEventListener[] { new EventListener() };
        Configure.EventListeners.PreUpdateEventListeners = new IPreUpdateEventListener[] { new EventListener() };
        Configure.SessionFactoryName(System.Configuration.ConfigurationManager.AppSettings["SessionFactoryName"]);
        Configure.DataBaseIntegration(db =>
                                      {
                                          db.Dialect<MsSql2008Dialect>();
                                          db.Driver<SqlClientDriver>();
                                          db.KeywordsAutoImport = Hbm2DDLKeyWords.AutoQuote;
                                          db.IsolationLevel = IsolationLevel.ReadCommitted;
                                          db.ConnectionString = _connectionString;
                                          db.BatchSize = 20;
                                          db.Timeout = 10;
                                          db.HqlToSqlSubstitutions = "true 1, false 0, yes 'Y', no 'N'";
                                      });
        Configure.SessionFactory().GenerateStatistics();

        Map();
    }

    public virtual void InitializeAudit()
    {
        var enversConf = new Envers.Configuration.Fluent.FluentConfiguration();

        enversConf.Audit(GetDomainEntities());

        Configure.IntegrateWithEnvers(enversConf);
    }

    public void CreateSchema()
    {
        new SchemaExport(Configure).Create(false, true);
    }

    public void DropSchema()
    {
        new SchemaExport(Configure).Drop(false, true);
    }

    private void Map()
    {
        _mapper.AddMappings(MappingAssembly.GetExportedTypes());
        Configure.AddDeserializedMapping(_mapper.CompileMappingForAllExplicitlyAddedEntities(), "MyWholeDomain");
    }

    public HbmMapping HbmMapping
    {
        get { return _mapper.CompileMappingFor(MappingAssembly.GetExportedTypes()); }
    }

    public IList<HbmMapping> HbmMappings
    {
        get { return _mapper.CompileMappingForEach(MappingAssembly.GetExportedTypes()).ToList(); }
    }

    /// <summary>
    /// Gets the domain entities.
    /// </summary>
    /// <returns></returns>
    /// <remarks>by default anything that derives from EntityBase and isn't abstract or generic</remarks>
    protected virtual IEnumerable<System.Type> GetDomainEntities()
    {
        List<System.Type> domainEntities = (from t in MappingAssembly.GetExportedTypes()
                                            where typeof(EntityBase<Guid>).IsAssignableFrom(t)
                                            && (!t.IsGenericType || !t.IsAbstract)
                                            select t
                                           ).ToList();

        return domainEntities;
    }
}

SessionInstaller 会话安装程序

public class SessionInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container
            .Register(Component.For<ISession>().UsingFactoryMethod(() => MvcApplication.CurrentSession)
                .LifeStyle
                .PerWebRequest);
    }
}

ControllersInstaller 控制器安装程序

public class ControllersInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(Classes.FromThisAssembly()
            .BasedOn<IController>()
            .LifestyleTransient());
    }
}

Controller Factory 控制器厂

public class WindsorControllerFactory : DefaultControllerFactory
{
    // Fields
    private readonly IKernel _kernel;

    // Methods
    public WindsorControllerFactory(IKernel kernel)
    {
        if (kernel == null)
            throw new ArgumentNullException("kernel");

        _kernel = kernel;
    }

    protected override IController GetControllerInstance(RequestContext context, Type controllerType)
    {
        if (controllerType == null)
            throw new HttpException(0x194,
                string.Format(
                    "The controller for path '{0}' could not be found or it does not implement IController.",
                    context.HttpContext.Request.Path));

        return (IController) _kernel.Resolve(controllerType);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用后处理 ObjectContext(按请求) - Disposing ObjectContext (per-request) after use Unity DI:从每个请求到全局单例再到每个请求 - Unity DI: Resolving from per-request to global singleton to per-request 在StartUp中使用Autofac解决每用户/每请求的依赖性 - Resolving per-user/per-request dependency with Autofac in StartUp 使用 .NET Flurl/HttpClient 设置每个请求的代理(或轮换代理) - Setting a per-request proxy (or rotating proxies) with .NET Flurl/HttpClient 如何在 ASP.net 核心中按请求缓存 - How to Per-Request caching in ASP.net core 如何在 ASP.NET 中限制每个请求 memory 的使用? - How to limit per-request memory usage in ASP.NET? 具有每个请求生存期范围的ServiceStack自托管应用程序 - ServiceStack self-hosted application with per-request lifetime scope 从Autofac函数工厂获取每个请求的依赖关系 - Get per-request dependency from an Autofac func factory 实体框架每个请求上下文-如何处理错误? - Entity Framework per-request context - how are errors handled? 具有依赖注入的Filters和FilterProvider; 管理每个请求? - Filters and FilterProvider with Dependency Injection; Manage Per-request?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM