asp.net-mvc – 城堡温莎IoC在一个MVC应用程序

准备一个代码墙…这是一个漫长的阅读,但它是一样冗长,我可以得到.

响应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的一部分,但我似乎无法弄清楚如何做到这一点.我也对我在控制器中创建存储库的方式感到困惑.这是否意味着我每次使用存储库时都必须执行所有的“映射”?这似乎是非常耗资源的.

解决方法

首先是一些概念细节.在ASP.NET MVC应用程序中,页面请求的典型入口点是控制器.我们希望控制反转控制容器为我们解决我们的控制器,因为控制器所拥有的任何依赖关系也可以通过将依赖项列为控制器构造函数中的参数来简单地自动解析.

困惑了吗以下是使用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应该被定义为您的域的一部分,因为它是为您的域行为定义界面.如上所述,处理数据库的域接口的实现被添加到持久层.

相关文章

判断URL文件是不是在于在。private static bool UrlIsExist(...
由于在.net中,Request时出现有HTML或Javascript等字符串时,...
public static bool ProcessIdCard(this string idCard, out...
protected void Page_Load(object sender, EventArgs e){ Sc...