在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 ...
随机推荐
- 上delloc 无呼叫 故障排除 笔记
经验 delloc 无呼叫 基本上可以得出结论,即循环引用的原因. 遇到这样的情况基本上可分为 1: 属性声明weak的地方 写成了 strong .比方delegate. 2: block语法块中 ...
- AMD宣布裁员7% 约710员工将失去工作
10 月 17 日.美国芯片生产商 AMD 周四宣布将裁员7%.并公布了不及预期的第四季度业绩展望.这将是 AMD 自 2011 年以来的第三轮大裁员. 就在一周之前,AMD 宣布罗瑞德(Rory R ...
- 面向对象的方式进行数据交换网络之间的差异--无缝切换的发展到单机游戏C/S模式
上一页本文描述描述有关数据的发展过程之间的差异支撑点,这里展示的另一个特点:无缝切换的发展,以独立C/S模式 一般C/S模式都面临一个问题: 就是开发过程中的调试难题,由于涉及到client和服务端相 ...
- 使用LabVIEWPC的制备
使用LabVIEWPC的制备 1.下载.安装LabVIEW 如今,互联网搜索,你可以搜索出一大推LabVIEW下载并安装破解教程.因此,这里没有具体描述的.请自行百度~~.另外.提醒一下,下载LabV ...
- JDK源码学习系列05----LinkedList
JDK源码学习系列05----LinkedList 1.LinkedList简介 LinkedList是基于双向链表实 ...
- 通达OA 新旧两种数据库连接方式
老的连接方式: include_once("/inc/conn.php"); $cursor = exequery($connection,$query); 新的连接方式: inc ...
- 使用cm-12.0源代码编译twrp
Select the newest branch available. This step is not necessary with Omni because Omni already includ ...
- 【我的书】Unity Shader的书 — 文件夹(2015.12.21更新)
写在前面 感谢全部点进来看的朋友.没错.我眼下打算写一本关于Unity Shader的书. 出书的目的有以下几个: 总结我接触Unity Shader以来的历程,给其它人一个借鉴.我非常明确学Shad ...
- Hive自己定义函数的使用——useragent解析
想要从日志数据中分析一下操作系统.浏览器.版本号使用情况.可是hive中的函数不能直接解析useragent,于是能够写一个UDF来解析.useragent用于表示用户的当前操作系统,浏览器版本号信息 ...
- 3、Spring4之Bean 配置的细节
1). 若字面值中包括特殊字符,则能够使用 value 节点的 <![CDATA[]]> 把字面值包裹起来. <constructor-arg> ...