最近在研究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(typeof(IMyService)
.ImplementedBy(typeof(MyServiceImpl)
);
//控制反转 得到实例
var myService= container.Resolve<IMyService>();

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

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

常规注册 

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

container.Register(
Component.For<MyServiceImpl>()
);

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

container.Register(
Component.For(typeof(IMyService)
.ImplementedBy(typeof(MyServiceImpl)
);

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

container.Register(
Component.For<IMyService>()
.ImplementedBy<MyServiceImpl>()
.LifeStyle.Transient
);

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

container.Register(
Component.For<IMyService>().ImplementedBy<MyServiceImpl>(),
Component.For<IMyService>().ImplementedBy<OtherServiceImpl>()
);

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

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我们可以

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

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

public WindsorControllerFactory(IWindsorContainer container)
{
this.container = container;
var controllerTypes =
from t in Assembly.GetExecutingAssembly().GetTypes()
where typeof(IController).IsAssignableFrom(t)
select t;
foreach (var t in controllerTypes)
container.Register(Component.For(t).LifeStyle.Transient);
}

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

context.IocManager.IocContainer.Register(
Classes.FromAssembly(context.Assembly)
.IncludeNonPublicTypes()
.BasedOn<ISingletonDependency>()
.WithService.Self()
.WithService.DefaultInterfaces()
.LifestyleSingleton()
);

  

自定义注册

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

public class RepositoriesInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly()
.Where(Component.IsInSameNamespaceAs<King>())
.WithService.DefaultInterfaces()
.LifestyleTransient());
}
}

构造函数&属性注入

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

public class PersonAppService
{
public ILogger Logger { get; set; }
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注册控制器的代码

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,主要提供注册、反转、注销等操作

    public class IocManager : IIocManager
{
public static IocManager Instance { get; private set; }
public IWindsorContainer IocContainer { get; private 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 实现的类

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

    /// <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是怎么做的吧

    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的枚举进行相关注册

    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实例
public class LoggerInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.AddFacility<LoggingFacility>(f => f.UseLog4Net());
}
}

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

<?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>

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

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

    public class AccountController : Controller
{
public ILogger Logger { get; set; }
public AccountController()
{
Logger = NullLogger.Instance;
}
public ActionResult LogOn()
{
Logger.Error("test");
return View();
}
}

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

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

namespace Castle.DynamicProxy
{
using System; public interface IInterceptor
{
void Intercept(IInvocation invocation);
}
}

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

    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的方法都会被拦截

        /// <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

Castle Windsor常用介绍以及其在ABP项目的应用介绍的更多相关文章

  1. 在ABP项目的应用Castle Windsor

    Castle Windsor常用介绍以及其在ABP项目的应用介绍 最近在研究ABP项目,有关ABP的介绍请看阳光铭睿 博客,ABP的DI和AOP框架用的是Castle Windsor下面就对Castl ...

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

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

  3. ABP项目中的使用AutoMapper

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

  4. 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 ...

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

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

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

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

  7. 依赖注入容器之Castle Windsor

    一.Windsor的使用 Windsor的作为依赖注入的容器的一种,使用起来比较方便,我们直接在Nuget中添加Castle Windsor,将会自动引入Castle.Core 和 Castle.Wi ...

  8. 在ASP.NET MVC中使用Castle Windsor

    平常用Inject比较多,今天接触到了Castle Windsor.本篇就来体验其在ASP.NET MVC中的应用过程. Visual Studio 2012创建一个ASP.NET MVC 4网站. ...

  9. ASP.NET MVC Castle Windsor 教程

    一.[转]ASP.NET MVC中使用Castle Windsor 二.[转]Castle Windsor之组件注册 平常用Inject比较多,今天接触到了Castle Windsor.本篇就来体验其 ...

随机推荐

  1. Node.js开发者最常范的10个错误

    目录 前言 1 不使用开发工具 1.1 自动重启工具 1.2 浏览器自动刷新工具 2 阻塞event loop 3 频繁调用回调函数 4 圣诞树结构的回调(回调的地狱) 5 创建一个大而完整的应用程序 ...

  2. Mysql 备份

    MySQL数据库备份命令   备份MySQL数据库的命令 mysqldump -hhostname -uusername -ppassword databasename > backupfile ...

  3. struts1二:基本环境搭建

    首先建立一个web项目 引入需要的jar包 建立包com.bjpowernode.struts创建LoginAction package com.bjpowernode.struts; import ...

  4. Atitit 分区后的查询  mysql分区记录的流程与原理

    Atitit 分区后的查询  mysql分区记录的流程与原理 1.1.1. ibd是MySQL数据文件.索引文件1 1.2. 已经又数据了,如何分区? 给已有的表加上分区 ]1 1.3. 分成4个区, ...

  5. fir.im Weekly - 让 iOS 应用更加安全

    攻易防难,关于 iOS 应用安全看起来有些神秘.iOS Security , 源于@吴发伟_则平博客翻译的关于iOS安全的一系列文章,现在站点已经系统收集了大量关于 iOS 逆向.安全.反编译.静动态 ...

  6. JavaScript易错点

    JavaScript知识点1.变量作用域   var a = 1;function test() {    var a = 2;     console.log(a); // 2} test();   ...

  7. 利用Bootstrap快速搭建个人响应式主页(附演示+源码)

    1.前言 我们每个程序员都渴望搭建自己的技术博客平台与他人进行交流分享,但使用别人的博客模板没有创意.做网站后台的开发人员可能了解前端,可是自己写一个不错的前端还是很费事的.幸好我们有Bootstra ...

  8. Lightmaping

    一.基本知识点 1.Baked Only:不会传入shader,只有烘焙时才有用,也就是_LightColor0等这种变量不会表示一个Baked Only Light(前提是场景有lightmap,如 ...

  9. Razor Engine,实现代码生成器的又一件利器

    Razor Engine,之前仅仅是ASP.NET MVC的一种View引擎,目前已经完全成为一种可以独立使用的模版引擎,并且已经成为了CodePlex上一个开源的项目(http://razoreng ...

  10. ASP.NET MVC之Unobtrusive Ajax(五)

    前言 这一节我们来讲讲Unobtrusive中的Ajax提交,大部分情况下我们是利用JQuery来进行Ajax请求,当然利用JQuery来进行表单Ajax请求也不例外,但是相对于Unobtrusive ...