实施的UnitOfWork与Castle.Windsor [英] Implementing UnitOfWork with Castle.Windsor

查看:280
本文介绍了实施的UnitOfWork与Castle.Windsor的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

简单的问题。


  

我如何使用带的UnitOfWork Castle.Windsor,NHibernate的,和ASP.NET MVC?


现在用于扩展的详细信息。在我的追求,了解的UnitOfWork 模式,我有困难跨采用了直接的例子连同 Castle.Windsor ,特别是在关于它的方式需要被安装。

下面是我的理解为止。

IUnitOfWork


  • IUnitOfWork 接口用于声明模式

  • 的UnitOfWork 类必须提交还原交易,以及暴露一个会话

所以,随着中说,这里是我的 IUnitOfWork 。 (我用功能NHibernate

  public接口IUnitOfWork:IDisposable接口
{
    ISession的会话{搞定;私人集; }
    无效回滚();
    无效提交();
}

因此​​,这里是我的 Castle.Windsor 集装箱引导程序(ASP.NET MVC)

 公共类WindsorContainerFactory
{
    私有静态Castle.Windsor.IWindsorContainer容器;
    私人静态只读对象SyncObject =新的对象();    公共静态电流Castle.Windsor.IWindsorContainer()
    {
        如果(集装箱== NULL)
        {
            锁定(SyncObject)
            {
                如果(集装箱== NULL)
                {
                    集装箱=新Castle.Windsor.WindsorContainer();                    container.Install(新Installers.SessionInstaller());
                    container.Install(新Installers.RepositoryInstaller());
                    container.Install(新Installers.ProviderInstaller());
                    container.Install(新Installers.ControllerInstaller());
                }
            }        }        返回容器中;
    }
}

所以,现在在我的的Global.asax 文件,我有以下...

 保护无效的Application_Start()
    {
        AreaRegistration.RegisterAllAreas();        RegisterGlobalFilters(GlobalFilters.Filters);
        的RegisterRoutes(RouteTable.Routes);        //注册温莎集装箱
        ControllerBuilder.Current
            .SetControllerFactory(新Containers.WindsorControllerFactory());
    }

现在我知道我需要将的Isession 传递给我的信息库。那么,让我承担 IMembershi prepository

 类Membershi prepository:IMembershi prepository
{
   私人只读的Isession会议;
   公共Membershi prepository(ISession的会话)
   {
      this.session =会议;
   }   公共成员RetrieveMember(字符串email)
   {
      返回session.Query&所述;会员方式>()的SingleOrDefault(ⅰ= GT; i.Email ==电子邮件);
   }
}

所以我很困惑,现在。使用这种方法,在的Isession 未得到正确摧毁,的UnitOfWork 永远不会被使用。

我被告知,的UnitOfWork 需要在Web请求级别去 - 但我找不到任何解释如何真正去了解这一点。我不使用的ServiceLocator 任何形式的(如当我试过了,有人告诉我,这也是不好的做法...)。


  

    

困惑 - 如何做了的UnitOfWork 获得创建


  
  
  

我只是不明白这一点,
  一般。我的想法是,我会
  开始传递的UnitOfWork 进入
  构造 - 但如果它
  已到Web请求去,我不
  了解其中两个涉及。


进一步code

这是额外的code澄清,只是因为我似乎从来不提供正确的信息,我的问题的习惯。

安装

 公共类ControllerInstaller:IWindsorInstaller
{
    公共无效安装(IWindsorContainer容器,IConfigurationStore店)
    {
        container.Register(
            AllTypes.FromThisAssembly()
            .BasedOn<一个IController>()
            .Configure(C => c.LifeStyle.Transient));
    }
}公共类ProviderInstaller:IWindsorInstaller
{
    公共无效安装(IWindsorContainer容器,IConfigurationStore店)
    {
        container.Register(
            零件
            。对于< Membership.IFormsAuthenticationProvider>()
            .ImplementedBy< Membership.FormsAuthenticationProvider>()
            .LifeStyle.Singleton
        );
    }
}公共类RepositoryInstaller:IWindsorInstaller
{
    公共无效安装(IWindsorContainer容器,IConfigurationStore店)
    {
        container.Register(
            零件
            。对于< Membership.IMembershi prepository>()
            .ImplementedBy< Membership.Membershi prepository>()
            .LifeStyle.Transient
        );        container.Register(
            零件
            。对于< Characters.ICharacterRepository>()
            .ImplementedBy< Characters.CharacterRepository>()
            .LifeStyle.Transient
        );
    }
}公共类SessionInstaller:Castle.MicroKernel.Registration.IWindsorInstaller
{
    私有静态ISessionFactory厂;
    私人静态只读对象SyncObject =新的对象();    公共无效安装(Castle.Windsor.IWindsorContainer容器,IConfigurationStore店)
    {
        container.Register(
            Component.For< ISessionFactory>()
                .UsingFactoryMethod(SessionFactoryFactory)
                .LifeStyle.Singleton
            );        container.Register(
            Component.For<&ISession的GT;()
            .UsingFactoryMethod(C => SessionFactoryFactory()的openSession()。)
            .LifeStyle.Transient
        );
    }    私有静态ISessionFactory SessionFactoryFactory()
    {
        如果(出厂== NULL)
            锁定(SyncObject)
                如果(出厂== NULL)
                    厂= Persistence.SessionFactory.Map(System.Web.Configuration.WebConfigurationManager.ConnectionStrings[\"Remote\"].ConnectionString);
        回厂;
    }
}

的UnitOfWork

下面是我的的UnitOfWork 类一字不差。

 公共类的UnitOfWork:IUnitOfWork
{
    私人只读ISessionFactory SessionFactory的;
    私人只读ITransaction交易;    公众的UnitOfWork(ISessionFactory SessionFactory的)
    {
        this.sessionFactory = SessionFactory的;
        会话= this.sessionFactory.OpenSession();
        交易= Session.BeginTransaction();
    }    公众的ISession会议{搞定;私人集; }    公共无效的Dispose()
    {
        Session.Close();
        会话= NULL;
    }    公共无效回滚()
    {
        如果(transaction.IsActive)
            transaction.Rollback();
    }    公共无效的commit()
    {
        如果(transaction.IsActive)
            器transaction.commit();
    }
}


解决方案

您NH会议是一个工作单元已经的http://nhforge.org/wikis/patternsandpractices/nhibernate-and-the-unit-of-work-pattern.aspx

所以我不知道你为什么会需要抽象了这一点任何进一步。 (如果有人读这个答案知道为什么我会很高兴地听到,我说实话从来没有听说过任何理由,你为什么会需要...)

我想实现一个简单的会话依据请求。我不知道你会怎么做,与温莎,因为我从来没有使用过它,但它是相当简单的用StructureMap。

我包住structuremap工厂握住我的会话工厂,并根据需要注入会话进入仓库。

 公共静态类的IoC
    {
        静态IOC()
        {
            ObjectFactory.Initialize(X =>
            {
                x.UseDefaultStructureMapConfigFile = FALSE;                // NHibernate的ISessionFactory
                x.ForSingletonOf< ISessionFactory>()
                 。使用(新SessionFactoryManager()CreateSessionFactory());                // NHibernate的ISession的
                x.For()。HybridHttpOrThreadLocalScoped()
                 。使用(S => s.GetInstance&下; ISessionFactory>()的openSession());                x.Scan(S => s.AssembliesFromApplicationBaseDirectory());
            });            ObjectFactory.AssertConfigurationIsValid();
        }        公共静态ŧ解决< T>()
        {
            返回ObjectFactory.GetInstance< T>();
        }        公共静态无效ReleaseAndDisposeAllHttpScopedObjects()
        {
            ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects();
        }
    }

在上Request_End Global.asax文件我称之为ReleaseAndDisposeAllHttpScopedObjects()方法。

 保护无效Application_EndRequest(对象发件人,EventArgs的发送)
        {
            IoC.ReleaseAndDisposeAllHttpScopedObjects();
        }

所以,当我把我的第一个资料库,并在请求结束它的处理会话被打开。该库有一个构造函数,需要的ISession并将其分配给一个属性。然后,我只是喜欢解决回购:

  VAR productRepository = IoC.Resolve< IProductRepository>();

希望有所帮助。有做的许多其他方式,这是我的作品。

Simple question.

How do I use UnitOfWork with Castle.Windsor, nHibernate, and ASP.NET MVC?

Now for the extended details. In my quest to understand the UnitOfWork pattern, I'm having difficulty coming across anything that uses a direct example in conjunction with Castle.Windsor, specifically in regards to the way it needs to be installed.

Here is my understanding so far.

IUnitOfWork

  • The IUnitOfWork interface is used to declare the pattern
  • The UnitOfWork class must Commit and Rollback transactions, and Expose a Session.

So with that said, here is my IUnitOfWork. (I am using Fluent nHibernate)

public interface IUnitOfWork : IDisposable
{
    ISession Session { get; private set; }
    void Rollback();
    void Commit();
}

So here is my Castle.Windsor Container Bootstrapper (ASP.NET MVC)

public class WindsorContainerFactory
{
    private static Castle.Windsor.IWindsorContainer container;
    private static readonly object SyncObject = new object();

    public static Castle.Windsor.IWindsorContainer Current()
    {
        if (container == null)
        {
            lock (SyncObject)
            {
                if (container == null)
                {
                    container = new Castle.Windsor.WindsorContainer();

                    container.Install(new Installers.SessionInstaller());
                    container.Install(new Installers.RepositoryInstaller());
                    container.Install(new Installers.ProviderInstaller());
                    container.Install(new Installers.ControllerInstaller());
                }
            }

        }

        return container;
    }
}

So now, in my Global.asax file, I have the following...

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);

        // Register the Windsor Container
        ControllerBuilder.Current
            .SetControllerFactory(new Containers.WindsorControllerFactory());
    }

Repository

Now I understand that I need to pass the ISession to my Repository. So then, let me assume IMembershipRepository.

class MembershipRepository : IMembershipRepository
{
   private readonly ISession session;
   public MembershipRepository(ISession session)
   {
      this.session = session;
   }

   public Member RetrieveMember(string email)
   {
      return session.Query<Member>().SingleOrDefault( i => i.Email == email );
   }
}

So I am confused, now. Using this method, the ISession doesn't get destroyed properly, and the UnitOfWork never gets used.

I've been informed that UnitOfWork needs to go in the Web Request Level - but I cannot find anything explaining how to actually go about this. I do not use a ServiceLocator of any sort ( as when I tried, I was told this was also bad practice... ).

Confusion -- How does a UnitOfWork get created?

I just don't understand this, in general. My thought was that I would start passing UnitOfWork into the Repository constructors - but if it has to go in the Web Request, I'm not understanding where the two relate.

Further Code

This is extra code for clarification, simply because I seem to have a habit of never providing the right information for my questions.

Installers

public class ControllerInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(
            AllTypes.FromThisAssembly()
            .BasedOn<IController>()
            .Configure(c => c.LifeStyle.Transient));
    }
}

public class ProviderInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(
            Component
            .For<Membership.IFormsAuthenticationProvider>()
            .ImplementedBy<Membership.FormsAuthenticationProvider>()
            .LifeStyle.Singleton
        );
    }
}

public class RepositoryInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(
            Component
            .For<Membership.IMembershipRepository>()
            .ImplementedBy<Membership.MembershipRepository>()
            .LifeStyle.Transient
        );

        container.Register(
            Component
            .For<Characters.ICharacterRepository>()
            .ImplementedBy<Characters.CharacterRepository>()
            .LifeStyle.Transient
        );
    }
}

public class SessionInstaller : Castle.MicroKernel.Registration.IWindsorInstaller
{
    private static ISessionFactory factory;
    private static readonly object SyncObject = new object();

    public void Install(Castle.Windsor.IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(
            Component.For<ISessionFactory>()
                .UsingFactoryMethod(SessionFactoryFactory)
                .LifeStyle.Singleton
            );

        container.Register(
            Component.For<ISession>()
            .UsingFactoryMethod(c => SessionFactoryFactory().OpenSession())
            .LifeStyle.Transient
        );
    }

    private static ISessionFactory SessionFactoryFactory()
    {
        if (factory == null)
            lock (SyncObject)
                if (factory == null)
                    factory = Persistence.SessionFactory.Map(System.Web.Configuration.WebConfigurationManager.ConnectionStrings["Remote"].ConnectionString);
        return factory;
    }
}

UnitOfWork

Here is my UnitOfWork class verbatim.

public class UnitOfWork : IUnitOfWork
{
    private readonly ISessionFactory sessionFactory;
    private readonly ITransaction transaction;

    public UnitOfWork(ISessionFactory sessionFactory)
    {
        this.sessionFactory = sessionFactory;
        Session = this.sessionFactory.OpenSession();
        transaction = Session.BeginTransaction();
    }

    public ISession Session { get; private set; }

    public void Dispose()
    {
        Session.Close();
        Session = null;
    }

    public void Rollback()
    {
        if (transaction.IsActive)
            transaction.Rollback();
    }

    public void Commit()
    {
        if (transaction.IsActive)
            transaction.Commit();
    }
}

解决方案

Your NH Session is a Unit of Work already http://nhforge.org/wikis/patternsandpractices/nhibernate-and-the-unit-of-work-pattern.aspx

So I'm not sure why you would ever need to abstract this out any further. (if anyone reading this answer know's why I would be happy to hear, I've honestly never heard of any reason why you would need to...)

I would implement a simple Session Per Request. I don't know how you would do that with Windsor since I've never used it, but with It's rather simple with StructureMap.

I wrap the structuremap factory to hold my session factory and inject the session into the repositories as required.

    public static class IoC
    {
        static IoC()
        {
            ObjectFactory.Initialize(x =>
            {
                x.UseDefaultStructureMapConfigFile = false;

                // NHibernate ISessionFactory
                x.ForSingletonOf<ISessionFactory>()
                 .Use(new SessionFactoryManager().CreateSessionFactory());

                // NHibernate ISession
                x.For().HybridHttpOrThreadLocalScoped()
                 .Use(s => s.GetInstance<ISessionFactory>().OpenSession());

                x.Scan(s => s.AssembliesFromApplicationBaseDirectory());
            });

            ObjectFactory.AssertConfigurationIsValid();
        }

        public static T Resolve<T>()
        {
            return ObjectFactory.GetInstance<T>();
        }

        public static void ReleaseAndDisposeAllHttpScopedObjects()
        {
            ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects();
        }
    }

In the global.asax file on Request_End I call the ReleaseAndDisposeAllHttpScopedObjects() method.

        protected void Application_EndRequest(object sender, EventArgs e)
        {
            IoC.ReleaseAndDisposeAllHttpScopedObjects();
        }

So the session is opened when I call my first repository, and when the request is ended it's disposed of. The repositories have a constructor which takes ISession and assigns it to a property. Then I just resolve the repo like:

var productRepository = IoC.Resolve<IProductRepository>();

Hope that helps. There are many other ways of doing it, this is what works for me.

这篇关于实施的UnitOfWork与Castle.Windsor的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆