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. CentOS 6 安装Oracle11g

    原创作品.从 "深蓝blog" 博客,欢迎转载,请务必注明转载如下源.否则追究其版权责任. 深蓝的blog:http://blog.csdn.net/huangyanlong/ar ...

  2. java自学者的福音

    谈到自学对于程序员来说并不陌生,自从我们离开校门就开始了自学之路.这一路上绝大部分都是 百步止于九十 步, 不是因为他们不够坚持,而是没有找到学习的方法和资源.当然这一路上我也走得很辛苦,刚毕业后自学 ...

  3. IOS --- 日期时间格式 更改

    1.怎样怎样将一个字符串如" 20110826134106"装化为随意的日期时间格式.以下列举两种类型:    NSString* string =@"201108261 ...

  4. nyoj 47 江 河问题 【贪婪】

    经典的贪婪. 两种方案:一个:让我们来最快,第二快,在过去的第一,最快的回.然后最慢,最慢第二,在过去.次最快的回来a[0]+a[1]+a[1]+a[n-1] 二:最快的和最慢的过去,最快的回来,最快 ...

  5. wpf做的3d滑动gallery

    原文:wpf做的3d滑动gallery wpf做的3d滑动gallery 随着iphone\ipad的流行及热捧,现在做移动产品不管是什么平台的,领导总想做成像ios系统的样子.自从微软发布了wind ...

  6. window忘记密码怎么办

    net命令   Net User 功能:添加或更改用户帐号或显示用户帐号信息. 格式:net user [username [password | *] [options]] [/domain] ne ...

  7. [WebGL入门]二十四,补色着色

    注:文章译自http://wgld.org/,原作者杉本雅広(doxas),文章中假设有我的额外说明,我会加上[lufy:],另外,鄙人webgl研究还不够深入,一些专业词语,假设翻译有误,欢迎大家指 ...

  8. Android 随着输入框控件的清除功能ClearEditText,抄IOS输入框

    今天给大家带来一个非常有用的小控件ClearEditText,就是在Android系统的输入框右边增加一个小图标,点击小图标能够清除输入框里面的内容,IOS上面直接设置某个属性就能够实现这一功能.可是 ...

  9. linux下一个oracle11G DG建立(一个):准备环境

    linux下一个oracle11G  DG建立(一个):准备环境 周围环境 名称 主库 备库 主机名 bjsrv shsrv 软件版本号 RedHat Enterprise5.5.Oracle 11g ...

  10. java学习笔记2015-6-6

    类与对象  (概念型  Demo演示)    面向对象   java  C++   包裹  承受  多态    分类  物    面向过程   C    结构体 1.获取用户输入  2.逻辑推断   ...