在ABP项目的应用Castle Windsor
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 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代码
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 { 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注册控制器的代码
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 { 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 实现的类
由于篇幅关系 我就只展示注册控制器
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)); } |
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 { 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方法来进行拦截
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的更多相关文章
- Castle Windsor常用介绍以及其在ABP项目的应用介绍
最近在研究ABP项目,有关ABP的介绍请看阳光铭睿 博客,ABP的DI和AOP框架用的是Castle Windsor下面就对Castle Windsor项目常用方法介绍和关于ABP的使用总结 1.下载 ...
- 说说ABP项目中的AutoMapper,Castle Windsor(痛并快乐着)
这篇博客要说的东西跟ABP,AutoMapper和Castle Windsor都有关系,而且也是我在项目中遇到的问题,最终解决了,现在的感受就是“痛并快乐着”. 首先,这篇博客不是讲什么新的知识点,而 ...
- 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 ...
- Castle Windsor 项目中快速使用
Castle Windsor 项目中快速使用 新建项目如下: 一个模型类,一个接口,一个实现方法.我的目的很明确就是在UI层通过Castle 调用数据访问层的方法. 添加项目引用 CastleDemo ...
- AutoMapper之ABP项目中的使用介绍
最近在研究ABP项目,昨天写了Castle Windsor常用介绍以及其在ABP项目的应用介绍 欢迎各位拍砖,有关ABP的介绍请看阳光铭睿 博客 AutoMapper只要用来数据转换,在园里已经有很多 ...
- 小白初学Ioc、DI、Castle Windsor依赖注入,大神勿入(不适)
过了几天,我又来了.上一篇中有博友提到要分享下属于我们abp初学者的历程,今天抽出点时间写写吧.起初,我是直接去看阳光铭睿的博客,看了一遍下来,感觉好多东西没接触过,接着我又去下了github 里面下 ...
- ABP项目中的使用AutoMapper
AutoMapper之ABP项目中的使用 最近在研究ABP项目,昨天写了Castle Windsor常用介绍以及其在ABP项目的应用介绍 欢迎各位拍砖,有关ABP的介绍请看阳光铭睿 博客 AutoMa ...
- ABP项目概述
在系统性介绍整个ABP框架之前,我们首先需要对ABP框架有一个大概的了解,ABP框架的全称是:Asp.Net Boilerplate Project(即Asp.Net 的样板项目)顾名思义就是能够通过 ...
- [Castle Windsor]学习依赖注入
初次尝试使用Castle Windsor实现依赖注入DI,或者叫做控制反转IOC. 参考: https://github.com/castleproject/Windsor/blob/master/d ...
随机推荐
- CentOS 6 安装Oracle11g
原创作品.从 "深蓝blog" 博客,欢迎转载,请务必注明转载如下源.否则追究其版权责任. 深蓝的blog:http://blog.csdn.net/huangyanlong/ar ...
- java自学者的福音
谈到自学对于程序员来说并不陌生,自从我们离开校门就开始了自学之路.这一路上绝大部分都是 百步止于九十 步, 不是因为他们不够坚持,而是没有找到学习的方法和资源.当然这一路上我也走得很辛苦,刚毕业后自学 ...
- IOS --- 日期时间格式 更改
1.怎样怎样将一个字符串如" 20110826134106"装化为随意的日期时间格式.以下列举两种类型: NSString* string =@"201108261 ...
- nyoj 47 江 河问题 【贪婪】
经典的贪婪. 两种方案:一个:让我们来最快,第二快,在过去的第一,最快的回.然后最慢,最慢第二,在过去.次最快的回来a[0]+a[1]+a[1]+a[n-1] 二:最快的和最慢的过去,最快的回来,最快 ...
- wpf做的3d滑动gallery
原文:wpf做的3d滑动gallery wpf做的3d滑动gallery 随着iphone\ipad的流行及热捧,现在做移动产品不管是什么平台的,领导总想做成像ios系统的样子.自从微软发布了wind ...
- window忘记密码怎么办
net命令 Net User 功能:添加或更改用户帐号或显示用户帐号信息. 格式:net user [username [password | *] [options]] [/domain] ne ...
- [WebGL入门]二十四,补色着色
注:文章译自http://wgld.org/,原作者杉本雅広(doxas),文章中假设有我的额外说明,我会加上[lufy:],另外,鄙人webgl研究还不够深入,一些专业词语,假设翻译有误,欢迎大家指 ...
- Android 随着输入框控件的清除功能ClearEditText,抄IOS输入框
今天给大家带来一个非常有用的小控件ClearEditText,就是在Android系统的输入框右边增加一个小图标,点击小图标能够清除输入框里面的内容,IOS上面直接设置某个属性就能够实现这一功能.可是 ...
- linux下一个oracle11G DG建立(一个):准备环境
linux下一个oracle11G DG建立(一个):准备环境 周围环境 名称 主库 备库 主机名 bjsrv shsrv 软件版本号 RedHat Enterprise5.5.Oracle 11g ...
- java学习笔记2015-6-6
类与对象 (概念型 Demo演示) 面向对象 java C++ 包裹 承受 多态 分类 物 面向过程 C 结构体 1.获取用户输入 2.逻辑推断 ...