在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 ...
随机推荐
- Bulk Insert Data
Bulk Insert Data 命名空间:Oracle.DataAccess.Client 组件:Oracle.DataAccess.dll(2.112.1.0) ODP.NET 版本:ODP.NE ...
- kb3035583
dism /online /Get-Packages /Format:Table|findstr 3035583 升级到w10补丁
- JavaScript实现的购物车效果-效果好友列表
JavaScript实现的购物车效果.当然,可以在许多地方使用这种效果.朋友的.例如,在选择.人力资源模块,工资的计算,人才选拔等..下面来看一下班似有些车效果图: watermark/2/text/ ...
- ESFramework 开发手册(07) -- 掉线与心跳机制(转)
虽然我们前面已经介绍完了ESFramework开发所需掌握的各种基础设施,但是还不够.想要更好地利用ESFramework这一利器,有些背景知识是我们必须要理解的.就像本文介绍的心跳机制,在严峻的In ...
- "Cannot find entry symbol nable-stdcll-fixup; defaulting to 00401000" 解决方案
在使用Qt 4.7.3, Qt 4.7.2 ,Qt 4.7.1(mingw 4.6.2 )的时候都会有一个问题无法编译通过,即用Qt Creator 编译的时候会发生一个错误 "Cannot ...
- [ACM] HDU 3395 Special Fish (最大重量二分图匹配,KM算法)
Special Fish Problem Description There is a kind of special fish in the East Lake where is closed to ...
- Duanxx的STM32学习: 启动模式,BOOT0和BOOT1具体解释
在画STM32的电路图的时候,关于STM32的启动方式纠结了一下,现有的參考设计都是在STM32的启动选择引脚BOOT0和BOOT1上使用了跳帽,用以人工选择STM32的启动方式,可是在实际应用中这样 ...
- Matrix+POJ+二维树状数组初步
...
- poj 2935 Basic Wall Maze
是一个图论的基础搜索题- 没什么好说的就是搜索就好 主要是别把 代码写的太屎,错了不好找 #include<cstdio> #include<algorithm> #inclu ...
- java编程规范之java注释规范
代码要是没有注释,对读者来说就是一堆乱七八糟的字母,为了提高代码的可读性和可维护性,必须对代码进行必要的注释,这里小编整理了一下java注释规范. (一)技巧 1:注释当前行快捷方式:ctrl+/ 2 ...