准备一堵代码墙……这是一本很长的书,但我尽其所能。

回应Still lost on Repositories and Decoupling, ASP.NET MVC

我想我将开始更加了解这一切。
我正试图习惯使用它。这是我到目前为止所拥有的。

项目


Project.Web(ASP.NET MVC 3.0 RC)



使用Project.Models
使用Project.Persistence


项目


Project.Models(域对象)



Membership.Member
Membership.IMembershipProvider


项目


Project.Persistence(Fluent nHibernate)



使用Project.Models
使用Castle.Core
使用Castle.Windsor
Membership.MembershipProvider : 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);
    }


所以我首先要问..

我在正确的轨道上吗?

如何为我的ISessionFactory使用Castle.Windsor

我有我的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的一部分,但是我似乎无法弄清楚该怎么做。我对在Controller中创建存储库的方式也感到困惑。这是否意味着我每次使用存储库时都必须进行所有“映射”?看来这将非常耗费资源。

最佳答案

首先是一些概念上的细节。在ASP.NET MVC应用程序中,页面请求的典型入口点是控制器。我们希望Inversion of Control容器能够为我们解析控制器,因为这样,只要将依赖项作为参数在控制器的构造函数中列出,也可以自动解决控制器具有的任何依赖项。

感到困惑了吗?这是所有设置完成后如何使用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, model.Password);
        }

        // If we got this far, something failed, 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。

我喜欢使用多个“安装程序”来配置我的Castle容器。每个安装程序负责不同类型的依赖项,因此,例如,我将拥有一个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应该定义为域的一部分,因为它正在定义域行为方式的接口。如上所述,处理数据库的域接口的实现已添加到持久层。

关于asp.net-mvc - MVC应用程序中的CaSTLe Windsor IoC,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/4401244/

10-12 22:35