最近在研究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. sql 笔记(mysql)

    Windows 安装mysql(zip包) 1,zip包解压到要安装目录 2,配置环境变量,Path后加mysql路径\bin 3,修改配置文件,mysql目录下my-default.ini base ...

  2. 每天一个linux命令(45):free 命令

    free命令可以显示Linux系统中空闲的.已用的物理内存及swap内存,及被内核使用的buffer.在Linux系统监控的工具中,free命令是最经常使用的命令之一. 1.命令格式: free [参 ...

  3. 20个JS优化代码技巧

    原文网址链接为:http://www.jstips.co/ .截取了一部分本人认为比较实用的技巧分享给大家.其中一小部分技巧为JS面向对象的写法,不宜一一列出.关于JS面向对象的写法可参考本人前几篇随 ...

  4. Spring学习记录(八)---Bean的生命周期

    之前说过,在调用下面时,就创建了容器和对象 ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml&quo ...

  5. Java的学习之路

    记事本 EditPlus eclipse Java的学习软件,已经系统性学习Java有一段时间了,接下来我想讲一下我在Java学习用到的软件. 1.第一个软件:记事本 记事本是Java学习中最基础的编 ...

  6. KnockoutJS 3.X API 第六章 组件(2) 组件注册

    要使Knockout能够加载和实例化组件,必须使用ko.components.register注册它们,从而提供如此处所述的配置. 注意:作为替代,可以实现一个自定义组件加载器(自定义加载器下一节介绍 ...

  7. li 前面的缩进怎么去除?

    异常处理汇总-前端系列 http://www.cnblogs.com/dunitian/p/4523015.html 设置margin和padding为0或者为比较小的值就可以了

  8. 火狐、谷歌、IE关于document.body.scrollTop和document.documentElement.scrollTop 以及值为0的问题

    一.先遇到document.body.scrollTop值为0的问题 做页面的时候可能会用到位置固定的层,读取document.body.scrollTop来设置层的位置,像这样, window.on ...

  9. Linq 知识回顾

    开篇语 在说LINQ之前必须先说说几个重要的C#语言特性 与LINQ有关的语言特性 隐式类型 (1)源起 在隐式类型出现之前, 我们在声明一个变量的时候, 总是要为一个变量指定他的类型 甚至在fore ...

  10. OpenCASCADE Make Primitives-Box

    OpenCASCADE Make Primitives-Box eryar@163.com Abstract. By making a simple box to demonstrate the BR ...