在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 ...
随机推荐
- 线程锁的概念函数EnterCriticalSection和LeaveCriticalSection的使用方法
线程锁的概念函数EnterCriticalSection和LeaveCriticalSection的使用方法 注:使用结构CRITICAL_SECTION 需增加头文件#include “afxmt. ...
- php laravel 帧 该文件上传
好,我承认我的忠告. 今天laravel框架编写一个文件上传部分.总能找到不正确的路径.但是,终于攻克. 以下我分享一下自己的学习体会吧. client <form method="P ...
- 开源Math.NET基础数学类库使用(16)C#计算矩阵秩
原文:[原创]开源Math.NET基础数学类库使用(16)C#计算矩阵秩 本博客所有文章分类的总目录:http://www.cnblogs.com/asxinyu/p/4 ...
- C++习题 对象转换
[Submit][Status][Web Board] Description 定义一个Teacher(教师)类(教师号,姓名,性别,薪金)和一个Student(学生)类(学号,姓名,性别,成绩),二 ...
- Android项目包装apk和apk反编译,xml反编译
一.项目和一般原则其不足之处包 (1)开发一个简单的项目.当发布了APK档.假设我们不使用签名的方式,直接地bin文件夹中找到*.apk档.非常方便,但是,当我们在使用的用户,可能有其他方案覆盖安装. ...
- iSwifting如何发送照片社区
登录iSwifting社区 1,首先点击"帖子": 2,点击"照片": 3.点击"选择文件上传" 4,上传后的照片: 5,点击上传的照片: ...
- cocos2d-x适配多分辨率
现在用的2d-x版本是2.1.1.现在的项目要求是iphone ,iphone Retina,ipad和ipad Retina都有各自的路径来存放各自需要的资源.在AppDelegate的 appli ...
- ios-上拉电阻负载许多其他接口
想尝试拉加载意识到有多少开始了他的研究之旅,我看了两天做出最终的界面. 之所以这么慢是由于,我不知道要将上拉出现的view放在哪.就能在scrollView拉究竟部的时候被拉出来.还有就是怎么拉出来之 ...
- Linux/UNIX流程关系
流程关系 过程组 除了一个过程,每个过程ID此外.也属于一个进程组.过程基是一个或多个过程的集合. 通常它们与相同的作业相关联,它接受各种信号从相同终端. #include<unistd.h&g ...
- 返璞归真 asp.net mvc (5) - Action Filter, UpdateModel, ModelBinder, Ajax, Unit Test
原文:返璞归真 asp.net mvc (5) - Action Filter, UpdateModel, ModelBinder, Ajax, Unit Test [索引页] [源码下载] 返璞归真 ...