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. 线程锁的概念函数EnterCriticalSection和LeaveCriticalSection的使用方法

    线程锁的概念函数EnterCriticalSection和LeaveCriticalSection的使用方法 注:使用结构CRITICAL_SECTION 需增加头文件#include “afxmt. ...

  2. php laravel 帧 该文件上传

    好,我承认我的忠告. 今天laravel框架编写一个文件上传部分.总能找到不正确的路径.但是,终于攻克. 以下我分享一下自己的学习体会吧. client <form method="P ...

  3. 开源Math.NET基础数学类库使用(16)C#计算矩阵秩

    原文:[原创]开源Math.NET基础数学类库使用(16)C#计算矩阵秩                本博客所有文章分类的总目录:http://www.cnblogs.com/asxinyu/p/4 ...

  4. C++习题 对象转换

    [Submit][Status][Web Board] Description 定义一个Teacher(教师)类(教师号,姓名,性别,薪金)和一个Student(学生)类(学号,姓名,性别,成绩),二 ...

  5. Android项目包装apk和apk反编译,xml反编译

    一.项目和一般原则其不足之处包 (1)开发一个简单的项目.当发布了APK档.假设我们不使用签名的方式,直接地bin文件夹中找到*.apk档.非常方便,但是,当我们在使用的用户,可能有其他方案覆盖安装. ...

  6. iSwifting如何发送照片社区

    登录iSwifting社区 1,首先点击"帖子": 2,点击"照片": 3.点击"选择文件上传" 4,上传后的照片: 5,点击上传的照片: ...

  7. cocos2d-x适配多分辨率

    现在用的2d-x版本是2.1.1.现在的项目要求是iphone ,iphone Retina,ipad和ipad Retina都有各自的路径来存放各自需要的资源.在AppDelegate的 appli ...

  8. ios-上拉电阻负载许多其他接口

    想尝试拉加载意识到有多少开始了他的研究之旅,我看了两天做出最终的界面. 之所以这么慢是由于,我不知道要将上拉出现的view放在哪.就能在scrollView拉究竟部的时候被拉出来.还有就是怎么拉出来之 ...

  9. Linux/UNIX流程关系

    流程关系 过程组 除了一个过程,每个过程ID此外.也属于一个进程组.过程基是一个或多个过程的集合. 通常它们与相同的作业相关联,它接受各种信号从相同终端. #include<unistd.h&g ...

  10. 返璞归真 asp.net mvc (5) - Action Filter, UpdateModel, ModelBinder, Ajax, Unit Test

    原文:返璞归真 asp.net mvc (5) - Action Filter, UpdateModel, ModelBinder, Ajax, Unit Test [索引页] [源码下载] 返璞归真 ...