实施的UnitOfWork与Castle.Windsor [英] Implementing UnitOfWork with Castle.Windsor
问题描述
简单的问题。
我如何使用带的UnitOfWork Castle.Windsor,NHibernate的,和ASP.NET MVC?
块引用>现在用于扩展的详细信息。在我的追求,了解
的UnitOfWork
模式,我有困难跨采用了直接的例子连同Castle.Windsor $任何未来C $ C>,特别是在关于它的方式需要被安装。
下面是我的理解为止。
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 withCastle.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 mustCommit
andRollback
transactions, and Expose aSession
.So with that said, here is my
IUnitOfWork
. (I am usingFluent 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 assumeIMembershipRepository
.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 theUnitOfWork
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 aServiceLocator
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 theRepository
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屋!