在ABP项目的应用Castle Windsor

Castle Windsor常用介绍以及其在ABP项目的应用介绍

最近在研究ABP项目,有关ABP的介绍请看阳光铭睿 博客,ABP的DI和AOP框架用的是Castle Windsor
下面就对Castle Windsor项目常用方法介绍和关于ABP的使用总结

1、下载Castle.Windsor所需要的dll,在程序包管理器控制台 运行Install-Package Castle.Windsor

下面先看个简单的例子


1

2

3

4

5

6

7

8

var container = new WindsorContainer();

container.Register(

Component.For(typeof(IMyService)

.ImplementedBy(typeof(MyServiceImpl)

);

//控制反转 得到实例

var myService= container.Resolve<IMyService>();

我们首先创建了WindsorContainer然后注册了MyServiceImpl以及它的接口,然后我们用容器创建了一个MyServiceImpl的实例

2、注册 Castle.Windsor有很多方法来注册你的类,下面一一介绍几种注册方法

常规注册 

我们可以使用Castle.MicroKernel.Registration.Component这个静态类,的For方法进行注册,返回一个 ComponentRegistration,就可以用他来进一步注册
注册一个类到容器,默认的注册类型是Singleton也就是单例


1

2

3

container.Register(

    Component.For<MyServiceImpl>()

);

给接口注册一个默认实例,这种做abp项目中应用很多


1

2

3

4

container.Register(

    Component.For(typeof(IMyService)

        .ImplementedBy(typeof(MyServiceImpl)

);

当然我们也可以指定注册的实例方式,主要有Transient和Singleton,Transient是每次请求都创建一个新实例,Singleton是单例,他们都是LifeStyle的属性


1

2

3

4

5

container.Register(

   Component.For<IMyService>()

      .ImplementedBy<MyServiceImpl>()

      .LifeStyle.Transient

);

当注册一个接口有多个实例的时候,我们可以以命名的方式来注册,下面这个是没有重命名的情况下,默认是注册第一个MyServiceImpl的


1

2

3

4

container.Register(

    Component.For<IMyService>().ImplementedBy<MyServiceImpl>(),

    Component.For<IMyService>().ImplementedBy<OtherServiceImpl>()

);

比如Nop项目中的缓存,但是Nop项目是用Autofac,那么你反转的时候就可以根据名字进行反转了


1

2

builder.RegisterType<MemoryCacheManager>().As<ICacheManager>().Named<ICacheManager>("nop_cache_static").SingleInstance();

builder.RegisterType<PerRequestCacheManager>().As<ICacheManager>().Named<ICacheManager>("nop_cache_per_request").InstancePerLifetimeScope();

在Castle Windsor我们可以


1

2

3

container.Register(

    Component.For<IMyService>().Named("OtherServiceImpl").ImplementedBy<OtherServiceImpl>()

);

以上讲到了windsor项目中常用的最简单的注册方式,那么我们也可以按照程序集进行注册,比如根据当前程序集注册以IController为接口的实例


1

2

3

4

5

6

7

8

9

10

public WindsorControllerFactory(IWindsorContainer container)

{

   this.container = container;

   var controllerTypes =

       from in Assembly.GetExecutingAssembly().GetTypes()

       where typeof(IController).IsAssignableFrom(t)

       select t;

       foreach (var in controllerTypes)

          container.Register(Component.For(t).LifeStyle.Transient);

}

Assembly.GetExecutingAssembly()是获取当前运行的程序集,或者你也可以这样,下面是ABP代码


1

2

3

4

5

6

7

8

context.IocManager.IocContainer.Register(

                Classes.FromAssembly(context.Assembly)

                    .IncludeNonPublicTypes()

                    .BasedOn<ISingletonDependency>()

                    .WithService.Self()

                    .WithService.DefaultInterfaces()

                    .LifestyleSingleton()

                );

  

自定义注册

你也可以重写IWindsorInstaller方法Install进行统一注册 


1

2

3

4

5

6

7

8

9

10

public class RepositoriesInstaller : IWindsorInstaller

{

    public void Install(IWindsorContainer container, IConfigurationStore store)

    {

        container.Register(Classes.FromThisAssembly()

                            .Where(Component.IsInSameNamespaceAs<King>())

                            .WithService.DefaultInterfaces()

                            .LifestyleTransient());

    }

}

构造函数&属性注入

构造函数和属性注入是项目开发的最佳实践,你可以使用去获取你的类的依赖关系。


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

public class PersonAppService

{

    public ILogger Logger { getset; }

    private IPersonRepository _personRepository;

    public PersonAppService(IPersonRepository personRepository)

    {

       _personRepository = personRepository;

       Logger = NullLogger.Instance;

    }

    public void CreatePerson(string name, int age)

    {

       Logger.Debug("Inserting a new person to database with name = " + name);

       var person = new Person { Name = name, Age = age };

       _personRepository.Insert(person);

       Logger.Debug("Successfully inserted!");

    }

}

IPersonRepository 从构造函数注入, ILogger 实例从公共属性注入。这样, 你的代码不会体现依赖注入系统。这是使用 DI 系统最适当的方式。

一般的控制器的话我们会统一注册,下面是ABP注册控制器的代码


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

public class WindsorControllerFactory : DefaultControllerFactory

{

    private readonly IKernel kernel;

    public WindsorControllerFactory(IKernel kernel)

    {

        this.kernel = kernel;

    }

    public override void ReleaseController(IController controller)

    {

        kernel.ReleaseComponent(controller);

    }

    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)

    {

        if (controllerType == null)

        {

            throw new HttpException(404, string.Format("The controller for path ‘{0}‘ could not be found.", requestContext.HttpContext.Request.Path));

        }

        return (IController)kernel.Resolve(controllerType);

    }

}

采用构造函数的注入模式是一个完美的提供类的依赖关系的方式。通过这种方式, 只有提供了依赖你才能创建类的实例。 同时这也是一个强大的方式显式地声明,类需要什么样的
依赖才能正确的工作。但是,在有些情况下,该类依赖于另一个类,但也可以没有它。这通常是适用于横切关注点(如日志记录)。一个类可以没有工作日志,但它可以写日志如果你提供一个日志对象。
在这种情况下, 你可以定义依赖为公共属性,而不是让他们放在构造函数。---摘自abp中文文档

好了,到了终于把Castle Windsor一些常用的注册写完了,上面主要还是讲依赖注入,下面开始ABP的相关介绍

ABP定义了一个统一的注册类IocManager,主要提供注册、反转、注销等操作


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

public class IocManager : IIocManager

{

    public static IocManager Instance { getprivate set; }

    public IWindsorContainer IocContainer { getprivate set; }

    private readonly List<IConventionalDependencyRegistrar> _conventionalRegistrars;

    static IocManager()

    {

        Instance = new IocManager();

    }

    public IocManager()

    {

        IocContainer = new WindsorContainer();

        _conventionalRegistrars = new List<IConventionalDependencyRegistrar>();

        //Register self!

        IocContainer.Register(

            Component.For<IocManager, IIocManager, IIocRegistrar, IIocResolver>().UsingFactoryMethod(() => this)

            );

    }

    /// <summary>

    /// Registers types of given assembly by all conventional registrars. See <see cref="AddConventionalRegistrar"/> method.

    /// </summary>

    /// <param name="assembly">Assembly to register</param>

    /// <param name="config">Additional configuration</param>

    public void RegisterAssemblyByConvention(Assembly assembly, ConventionalRegistrationConfig config)

    {

        var context = new ConventionalRegistrationContext(assembly, this, config);

        //这个循环还是要进行四个注册,

        foreach (var registerer in _conventionalRegistrars)

        {

            registerer.RegisterAssembly(context);

        }

        if (config.InstallInstallers)

        {

            IocContainer.Install(FromAssembly.Instance(assembly));

        }

    }

有个重要的方法是RegisterAssemblyByConvention会循环遍历继承IConventionalDependencyRegistrar接口的所有类,并进行注册

查看ABP的代码发现,实现该接口的主要有四个类,分别注册DbContex类型,控制器和ApiController和注册基于接口ITransientDependency和ISingletonDependency和IInterceptor 实现的类

由于篇幅关系 我就只展示注册控制器


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

/// <summary>

/// Registers all MVC Controllers derived from <see cref="Controller"/>.

/// </summary>

public class ControllerConventionalRegistrar : IConventionalDependencyRegistrar

{

    /// <inheritdoc/>

    public void RegisterAssembly(IConventionalRegistrationContext context)

    {

        context.IocManager.IocContainer.Register(

            Classes.FromAssembly(context.Assembly)

                .BasedOn<Controller>()

                .LifestyleTransient()

            );

    }

}

关于Castle.Windsor注册有一个实体,一般我们常用的有Singleton(单例)和Transient(每次创建新对象)那么我们看下ABP是怎么做的吧


1

2

3

4

5

6

7

8

9

10

11

12

public enum DependencyLifeStyle

{

    /// <summary>

    /// Singleton object. Created a single object on first resolving

    /// and same instance is used for subsequent resolves.

    /// </summary>

    Singleton,

    /// <summary>

    /// Transient object. Created one object for every resolving.

    /// </summary>

    Transient

}

定义了一个关于LifeStyle的枚举进行相关注册


1

2

3

4

public void Register(Type type, DependencyLifeStyle lifeStyle = DependencyLifeStyle.Singleton)

{

    IocContainer.Register(ApplyLifestyle(Component.For(type), lifeStyle));

}

  

另外Castle Windsor还支持日志,这点在ABP也有应用到,支持log4net等

首先需要下载相应的dll ,Install-Package Castle.Windsor-log4net

其次自动注册一个Log实例


1

2

3

4

5

6

7

public class LoggerInstaller : IWindsorInstaller

{

    public void Install(IWindsorContainer container, IConfigurationStore store)

    {

        container.AddFacility<LoggingFacility>(f => f.UseLog4Net());

    }

}

第三配置下log4net.config文件,下面是我的简单配置


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

<?xml version="1.0" encoding="utf-8"?>

<configuration>

  <configSections>

    <!--日志配置部分-->

    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />

  </configSections>

  <log4net>

    <root>

      <priority value="All" />

      <appender-ref ref="FileAppender" />

      <appender-ref ref="InfoLoging" />

    </root>

    <appender name="FileAppender" type="log4net.Appender.RollingFileAppender">

      <file value="log\\log.txt" />

      <appendToFile value="true" />

      <maxSizeRollBackups value="10" />

      <maximumFileSize value="10000KB" />

      <rollingStyle value="Size" />

      <staticLogFileName value="true" />

      <filter type="log4net.Filter.LevelRangeFilter">

        <levelMin value="ERROR" />

        <levelMax value="ERROR" />

      </filter>

      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />

      <layout type="log4net.Layout.PatternLayout">

        <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />

      </layout>

    </appender>

    <appender name="InfoLoging" type="log4net.Appender.RollingFileAppender">

      <file value="log\\logData.txt" />

      <appendToFile value="true" />

      <maxSizeRollBackups value="10" />

      <maximumFileSize value="10000KB" />

      <rollingStyle value="Size" />

      <staticLogFileName value="true" />

      <filter type="log4net.Filter.LevelRangeFilter">

        <levelMin value="INFO" />

        <levelMax value="INFO" />

      </filter>

      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />

      <layout type="log4net.Layout.PatternLayout">

        <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />

      </layout>

    </appender>

  </log4net>

</configuration>

文章最后会附源码,包含配置等

最后我们就可以使用了,下面我用的是属性注入方式


1

2

3

4

5

6

7

8

9

10

11

12

13

public class AccountController : Controller

{

    public ILogger Logger { getset; }

    public AccountController()

    {

        Logger = NullLogger.Instance;

    }

    public ActionResult LogOn()

    {

        Logger.Error("test");

        return View();

    }

}

当然ABP也是提供这种方式用log4net日志的,但是它驱动的时候是在Global中配置

上面是Castle Windsor的IOC的应用,当然在ABP中也有用到其AOP方法,我们可以继承IInterceptor的Intercept方法来进行拦截


1

2

3

4

5

6

7

8

9

namespace Castle.DynamicProxy

{

    using System;

    

    public interface IInterceptor

    {

        void Intercept(IInvocation invocation);

    }

}

下面看下ABP最重要的一个拦截方法


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

internal class UnitOfWorkInterceptor : IInterceptor

{

    private readonly IUnitOfWorkManager _unitOfWorkManager;

    public UnitOfWorkInterceptor(IUnitOfWorkManager unitOfWorkManager)

    {

        _unitOfWorkManager = unitOfWorkManager;

    }

    /// <summary>

    /// Intercepts a method.

    /// </summary>

    /// <param name="invocation">Method invocation arguments</param>

    public void Intercept(IInvocation invocation)

    {

        if (_unitOfWorkManager.Current != null)

        {

            //Continue with current uow

            invocation.Proceed();

            return;

        }

        var unitOfWorkAttr = UnitOfWorkAttribute.GetUnitOfWorkAttributeOrNull(invocation.MethodInvocationTarget);

        if (unitOfWorkAttr == null || unitOfWorkAttr.IsDisabled)

        {

            //No need to a uow

            invocation.Proceed();

            return;

        }

        //No current uow, run a new one

        PerformUow(invocation, unitOfWorkAttr.CreateOptions());

    }

它的注册是在模块中进行注册的,注册主要包含IRepository和IApplicationService和UnitOfWorkAttribute,所以包含[UnitOfWork]的方法和继承IRepository和IApplicationService的方法都会被拦截


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

/// <summary>

/// 拦截注册事件

/// </summary>

/// <param name="key"></param>

/// <param name="handler"></param>

private static void ComponentRegistered(string key, IHandler handler)

{

    if (UnitOfWorkHelper.IsConventionalUowClass(handler.ComponentModel.Implementation))

    {

        //Intercept all methods of all repositories.

        handler.ComponentModel.Interceptors.Add(new InterceptorReference(typeof(UnitOfWorkInterceptor)));

    }

    else if (handler.ComponentModel.Implementation.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Any(UnitOfWorkHelper.HasUnitOfWorkAttribute))

    {

        //Intercept all methods of classes those have at least one method that has UnitOfWork attribute.

        //TODO: Intecept only UnitOfWork methods, not other methods!

        handler.ComponentModel.Interceptors.Add(new InterceptorReference(typeof(UnitOfWorkInterceptor)));

    }

}

以上就把Castle Windsor的常用功能和ABP项目中的使用简单的讲完了。主要参考的几个项目ABP、NOP、Prodinner

简单的源码地址:http://pan.baidu.com/s/1kTCNpQZ

参考文章:

https://github.com/ABPFrameWorkGroup/AbpDocument2Chinese

https://github.com/castleproject/Windsor/blob/master/docs/README.md

http://www.cnblogs.com/wucg/archive/2012/03/09/2387946.html

时间: 2024-12-21 19:42:58

在ABP项目的应用Castle Windsor的相关文章

Castle Windsor常用介绍以及其在ABP项目的应用介绍

最近在研究ABP项目,有关ABP的介绍请看阳光铭睿 博客,ABP的DI和AOP框架用的是Castle Windsor下面就对Castle Windsor项目常用方法介绍和关于ABP的使用总结 1.下载Castle.Windsor所需要的dll,在程序包管理器控制台 运行Install-Package Castle.Windsor 下面先看个简单的例子 var container = new WindsorContainer(); container.Register( Component.For

Aspect Oriented Programming using Interceptors within Castle Windsor and ABP Framework AOP

http://www.codeproject.com/Articles/1080517/Aspect-Oriented-Programming-using-Interceptors-wit Download sample application (or see the latest on Github) Contents Introduction What is Aspect Oriented Programming (AOP) and Method Interception? Manual W

ABP项目中的使用AutoMapper

AutoMapper之ABP项目中的使用 最近在研究ABP项目,昨天写了Castle Windsor常用介绍以及其在ABP项目的应用介绍 欢迎各位拍砖,有关ABP的介绍请看阳光铭睿 博客 AutoMapper只要用来数据转换,在园里已经有很多这方面文章了,本文主要介绍其在实际项目常用总结,以及在ABP项目中的应用介绍.AutoMapper应用非常简单,大家稍微看下文档就可以上手,但是性能不好啊,所以一般用在后台项目,对外的项目千万不要用.就那NOP来说吧,它也是把AutoMapper放在后台项目

小白初学Ioc、DI、Castle Windsor依赖注入,大神勿入(不适)

过了几天,我又来了.上一篇中有博友提到要分享下属于我们abp初学者的历程,今天抽出点时间写写吧.起初,我是直接去看阳光铭睿的博客,看了一遍下来,感觉好多东西没接触过,接着我又去下了github 里面下了几个例子来看,看起来还是有点吃力,毕竟我只用过MVC3和asp.net4.0以及EntityFramework3.5 ,突然感觉自己好像跟世界脱轨了,什么IOC只是听老师提过,当时不知道有什么用就没怎么听,AutoMapper,AngularJS,Less什么的没听过.没办法,只好先去一个一个把他

ASP.NET Web API - 使用 Castle Windsor 依赖注入

示例代码 项目启动时,创建依赖注入容器 定义一静态容器 IWindsorContainer 1 private static IWindsorContainer _container; 在 Application_Start() 中,创建该容器 1 _container = new WindsorContainer(); 调用 Container Install 方法,向容器内注册组件 1 _container.Install(FromAssembly.This()); 该语句会调用整个程序集中

Castle.Windsor IOC/AOP的使用

Castle最早在2003年诞生于Apache Avalon项目,目的是为了创建一个IOC(控制反转)框架.发展到现在已经有4个组件了,分别是ActiveRecord(ORM组件).Windsor(IOC组件).DynamicProxy(动态代理组件).MonoRail(Web MVC组件). 这里我们要学习的是Windsor组件,Windsor是Castle提供的一个IOC框架. 使用之前,首先需要引用两个DLL,分别是:Castle.Core 和 Castle.Windsor. IOC(控制

在ASP.NET MVC中使用Castle Windsor

平常用Inject比较多,今天接触到了Castle Windsor.本篇就来体验其在ASP.NET MVC中的应用过程. Visual Studio 2012创建一个ASP.NET MVC 4网站. 通过NuGet安装Castle Windsor. 在当前项目下创建一个名称为"IOC"的文件夹. 在ASP.NET MVC中,每次请求,DefaultControllerFactory都会为我们创建controller实例,我们需要自定义一个派生自DefaultControllerFact

对Castle Windsor的Resolve方法的解析时new对象的探讨

依赖注入框架Castle Windsor从容器里解析一个实例时(也就是调用Resolve方法),是通过调用待解析对象的构造函数new一个对象并返回,那么问题是:它是调用哪个构造函数呢? 无参的构造函数 带参但参数不是靠依赖注入的构造函数 带参且参数是靠依赖注入的构造函数 有多个带参且参数是靠依赖注入的构造函数 带着这个问题,我写了一段测试代码. 测试1: 只有一个无参构造函数: CtorTest类(在控制台程序里用Windsor解析这个类) public class CtorTest { pub

Abp项目构建、swagger及代码生成器

推荐博客 1. Abp项目实践推荐参照大神角落的白板报的系列博客,比较新,并且是亲身体验. http://www.cnblogs.com/wer-ltm/p/6824716.html 2. Abp源码整体原理结构.类关系图等参看大神Hk Zhang http://www.cnblogs.com/1zhk/p/5268054.html 一.利用abp模板构建项目 1.打开官网https://aspnetboilerplate.com/Templates (2)     生成项目后会自动下载代码 二