响应Still lost on Repositories and Decoupling,ASP.NET MVC
我想我已经开始越来越了解这一切了.
我试图习惯使用这个.这是我到目前为止.
项目
Project.Web (ASP.NET MVC 3.0 RC)
>使用Project.Models
>使用Project.Persistence
项目
Project.Models (Domain Objects)
>会员.会员
>会员资格
项目
Project.Persistence (Fluent nHibernate)
>使用Project.Models
>使用Castle.Core
>使用Castle.Windsor
>会员.会员提供者:IMembershipProvider
我在Project.Persistence中有以下类
using Castle.Windsor; using Castle.MicroKernel.Registration; using Castle.MicroKernel.SubSystems.Configuration; namespace Project.Persistence { public static class IoC { private static IWindsorContainer _container; public static void Initialize() { _container = new WindsorContainer() .Install( new Persistence.Containers.Installers.RepositoryInstaller() ); } public static T Resolve<T>() { return _container.Resolve<T>(); } } } namespace Persistence.Containers.Installers { public class RepositoryInstaller : IWindsorInstaller { public void Install(IWindsorContainer container,IConfigurationStore store) { container.Register( Component .For<Membership.IMembershipProvider>() .ImplementedBy<Membership.MembershipProvider>() .LifeStyle.Singleton ); } } }
现在,在Project.Web Global.asax Application_Start中,我有以下代码.
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RegisterGlobalFilters(GlobalFilters.Filters); RegisterRoutes(RouteTable.Routes); // Register the Windsor Container Project.Persistence.IoC.Initialize(); }
现在,在Project.Web.Controllers.MembershipController中,我有以下代码.
[HttpPost] public ActionResult Register( Web.Models.Authentication.Registration model) { if (ModelState.IsValid) { var provider = IoC.Resolve<Membership.IMembershipProvider>(); provider.CreateUser(model.Email,model.Password); } // If we got this far,something Failed,redisplay form return View(model); }
所以我先问一下..
我在正确的轨道上吗?
我如何使用Castle.Windsor作为我的ISessionFactory
我有我的SessionFactory这样工作…
namespace Project.Persistence.Factories { public sealed class SessionFactoryContainer { private static readonly ISessionFactory _instance = CreateSessionFactory(); static SessionFactoryContainer() { } public static ISessionFactory Instance { get { return _instance; } } private static ISessionFactory CreateSessionFactory() { return Persistence.SessionFactory.Map(@"Data Source=.\sqlEXPRESS;Initial Catalog=FluentExample;Integrated Security=true",true); } } } namespace Project.Persistence { public static class SessionFactory { public static ISessionFactory Map(string connectionString,bool createSchema) { return FluentNHibernate.Cfg.Fluently.Configure() .Database(FluentNHibernate.Cfg.Db.MssqlConfiguration.Mssql2008 .ConnectionString(c => c.Is(connectionString))) .ExposeConfiguration(config => { new NHibernate.Tool.hbm2ddl.SchemaExport(config) .SetOutputFile("Output.sql") .Create(/* Output to console */ false,/* Execute script against database */ createSchema); }) .Mappings(m => { m.FluentMappings.Conventions.Setup(x => { x.AddFromAssemblyOf<Program>(); x.Add(FluentNHibernate.Conventions.Helpers.AutoImport.Never()); }); m.FluentMappings.AddFromAssemblyOf<Mapping.MembershipMap>(); }).BuildSessionFactory(); }
所以基本上,在我的Project.Persistence层,我称之为SessionFactory这样..
var session = SessionFactoryContainer.Instance.OpenSession()
我甚至接近做这个吗?我仍然感到困惑 – 我觉得ISessionFactory应该是Castle.Windsor的一部分,但我似乎无法弄清楚如何做到这一点.我也对我在控制器中创建存储库的方式感到困惑.这是否意味着我每次使用存储库时都必须执行所有的“映射”?这似乎是非常耗资源的.
解决方法
困惑了吗以下是使用IoC的一个例子.我认为这样解释使事情更容易!
public class HomeController : Controller { // lets say your home page controller depends upon two providers private readonly IMembershipProvider membershipProvider; private readonly IBlogProvider blogProvider; // constructor,with the dependencies being passed in as arguments public HomeController( IMembershipProvider membershipProvider,IBlogProvider blogProvider) { this.membershipProvider = membershipProvider; this.blogProvider = blogProvider; } // so taking your Registration example... [HttpPost] public ActionResult Register( Web.Models.Authentication.Registration model) { if (ModelState.IsValid) { this.membershipProvider.CreateUser(model.Email,redisplay form return View(model); } }
注意,你没有必要做任何解决自己,你刚刚在控制器中指定了依赖关系.实际上也没有指出依赖关系是如何实现的 – 它们都是脱钩的.这很简单,这里没有什么复杂的:-)
希望在这一点上你会问,“但是构造函数如何被实例化?这是我们开始设置您的Castle容器的地方,我们完全在MVC Web项目(不是Persistence或Domain)中完成.编辑Global.asax文件,将Castle Windsor设置为控制器工厂:
protected void Application_Start() { //... ControllerBuilder.Current .SetControllerFactory(typeof(WindsorControllerFactory)); }
…并定义WindsorControllerFactory,以便您的控制器由Windsor实例化:
/// Use Castle Windsor to create controllers and provide DI public class WindsorControllerFactory : DefaultControllerFactory { private readonly IWindsorContainer container; public WindsorControllerFactory() { container = ContainerFactory.Current(); } protected override IController GetControllerInstance( RequestContext requestContext,Type controllerType) { return (IController)container.Resolve(controllerType); } }
ContainerFactory.Current()方法是静态单例,返回配置的Castle Windsor容器.容器的配置指示Windsor如何解决应用程序的依赖关系.因此,例如,您可能有一个容器被配置为解析NHibernate SessionFactory和您的IMembershipProvider.
我喜欢使用几个“安装程序”配置我的城堡容器.每个安装程序都负责不同类型的依赖关系,所以我有一个Controller安装程序,一个NHibernate安装程序,一个Provider安装程序.
首先我们有ContainerFactory:
public class ContainerFactory { private static IWindsorContainer container; private static readonly object SyncObject = new object(); public static IWindsorContainer Current() { if (container == null) { lock (SyncObject) { if (container == null) { container = new WindsorContainer(); container.Install(new ControllerInstaller()); container.Install(new NHibernateInstaller()); container.Install(new ProviderInstaller()); } } } return container; } }
…然后我们需要每个安装程序. ControllerInstaller第一:
public class ControllerInstaller : IWindsorInstaller { public void Install(IWindsorContainer container,IConfigurationStore store) { container.Register( AllTypes .FromAssembly(Assembly.GetExecutingAssembly()) .BasedOn<IController>() .Configure(c => c.Named( c.Implementation.Name.ToLowerInvariant()).LifeStyle.PerWebRequest)); } }
…这里是我的NHibernateInstaller,尽管它与你的不同,你可以使用自己的配置.请注意,每次解决时,我都会重复使用相同的ISessionFactory实例:
public class NHibernateInstaller : IWindsorInstaller { private static ISessionFactory factory; private static readonly object SyncObject = new object(); public void Install(IWindsorContainer container,IConfigurationStore store) { var windsorContainer = container.Register( Component.For<ISessionFactory>() .UsingFactoryMethod(SessionFactoryFactory)); } private static ISessionFactory SessionFactoryFactory() { if (factory == null) { lock (SyncObject) { if (factory == null) { var cfg = new Configuration(); factory = cfg.Configure().BuildSessionFactory(); } } } return factory; } }
最后,您将需要定义您的ProvidersInstaller:
public class ProvidersInstaller : IWindsorInstaller { public void Install(IWindsorContainer container,IConfigurationStore store) { var windsorContainer = container .Register( Component .For<IMembershipProvider>() .ImplementedBy<SubjectQueries>()) .Register( Component .For<IBlogProvider>() .ImplementedBy<SubjectQueries>()); // ... and any more that your need to register } }
这应该是足够的代码去走了!希望你还在我身边,因为城堡容器的美丽很快就变得明显.
当您在持久层中定义您的IMembershipProvider的实现时,请记住它与NHibernate ISessionFactory有依赖关系.所有你需要做的是这样的:
public class NHMembershipProvider : IMembershipProvider { private readonly ISessionFactory sessionFactory; public NHMembershipProvider(ISessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } }
请注意,因为Castle Windsor正在创建控制器并将提供程序传递给您的控制器构造函数,所以提供程序将自动传递在Windsor容器中配置的ISessionFactory实现!
您不必担心再次实例化任何依赖关系.您的容器会自动为您完成.
最后,请注意,IMembershipProvider应该被定义为您的域的一部分,因为它是为您的域行为定义界面.如上所述,处理数据库的域接口的实现被添加到持久层.