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

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

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

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

  2. 说说ABP项目中的AutoMapper,Castle Windsor(痛并快乐着)

    这篇博客要说的东西跟ABP,AutoMapper和Castle Windsor都有关系,而且也是我在项目中遇到的问题,最终解决了,现在的感受就是“痛并快乐着”. 首先,这篇博客不是讲什么新的知识点,而 ...

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

    http://www.codeproject.com/Articles/1080517/Aspect-Oriented-Programming-using-Interceptors-wit Downl ...

  4. Castle Windsor 项目中快速使用

    Castle Windsor 项目中快速使用 新建项目如下: 一个模型类,一个接口,一个实现方法.我的目的很明确就是在UI层通过Castle 调用数据访问层的方法. 添加项目引用 CastleDemo ...

  5. AutoMapper之ABP项目中的使用介绍

    最近在研究ABP项目,昨天写了Castle Windsor常用介绍以及其在ABP项目的应用介绍 欢迎各位拍砖,有关ABP的介绍请看阳光铭睿 博客 AutoMapper只要用来数据转换,在园里已经有很多 ...

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

    过了几天,我又来了.上一篇中有博友提到要分享下属于我们abp初学者的历程,今天抽出点时间写写吧.起初,我是直接去看阳光铭睿的博客,看了一遍下来,感觉好多东西没接触过,接着我又去下了github 里面下 ...

  7. ABP项目中的使用AutoMapper

    AutoMapper之ABP项目中的使用 最近在研究ABP项目,昨天写了Castle Windsor常用介绍以及其在ABP项目的应用介绍 欢迎各位拍砖,有关ABP的介绍请看阳光铭睿 博客 AutoMa ...

  8. ABP项目概述

    在系统性介绍整个ABP框架之前,我们首先需要对ABP框架有一个大概的了解,ABP框架的全称是:Asp.Net Boilerplate Project(即Asp.Net 的样板项目)顾名思义就是能够通过 ...

  9. [Castle Windsor]学习依赖注入

    初次尝试使用Castle Windsor实现依赖注入DI,或者叫做控制反转IOC. 参考: https://github.com/castleproject/Windsor/blob/master/d ...

随机推荐

  1. ASP.NET Core MVC Hello World

    ASP.NET Core 现在ASP.NET Core还在不断成长.更新中,说不定到了明天又换了个模样,就如同一个小孩,从蹒跚学步,到奔向未来. 所以我们可以相应的去理解更新中所发生的变化,包容它.呵 ...

  2. [Cacti] cacti监控mongodb性能实战

    .生成监控图 在界面.选择"Device".选择mongodb服务器连接"3.X2_mongodb".再选择右上角的"Create Graphs fo ...

  3. IT增值服务,客户案例(一)--山东青岛在职人士,2年.Net经验,转Java开发半年

    客户总体情况:2年.Net开发经验,2014年刚刚转Java半年.对Java的若干问题不是非常清楚,仅仅是对JSP/Servlet/JavaBean Spring.SpringMVC.Mybatis有 ...

  4. mysql重装后出现乱码解决办法

    查看当前连接系统参数:SHOW VARIABLES LIKE '%char%'; mysql> show variables like 'char%'; +------------------- ...

  5. 重新想象 Windows 8 Store Apps (6) - 控件之媒体控件: Image, MediaElement

    原文:重新想象 Windows 8 Store Apps (6) - 控件之媒体控件: Image, MediaElement [源码下载] 重新想象 Windows 8 Store Apps (6) ...

  6. APK ubuntu下 数字签名

    Android系统要求每个Android应用程序必需要经过数字签名才可以安装到系统中,也就是说假设一个Android应用程序没有经过数字签名,是没有办法安装到系统中的! Android通过数字签名来标 ...

  7. 栈实现java

    栈是一种“先去后出”的抽象的数据结构.例如:我们在洗盘子的时候,洗完一个盘子,将其放在一摞盘子的最上面,但我们全部洗完后,要是有盘子时,我们会先从最上面的盘子开始使用,这种例子就像栈的数据结构一样,先 ...

  8. Dubbo-Admin管理平台和Zookeeper注册中心的搭建(转)

    林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubb ...

  9. 无阻塞情况connect生产EINPROGRESS错

    今天的游戏开发client测试程序,非常多,因为出现client.后connect成功.代码证recv系统调用.后来发现,可能是由于socket默认模式被阻止,这将使很多client 接处于链接却不能 ...

  10. Java 对象的生命周期

    Java对象的生命周期 在Java中,对象的生命周期包含下面几个阶段: 1.      创建阶段(Created) 2.      应用阶段(In Use) 3.      不可见阶段(Invisib ...