Orchard源码:EventBus&EventHandler
概述
看源码是一件吃力又很爽的事情,昨天还被搞的一头雾水,今天忽然守得云开见月明。明白它设计意图的同时,感觉自己又提升了一步:)
Orchard刚开始看往往毫无头绪,建议可以从Orchard.Framework&UnitTest入手,先弄明白底层框架机制,抽丝剥茧,一步一步农村包围城市。不用着急,说不定哪天睡觉一下子就理解了。
今天看一下它的事件通知模块的设计,相关类

1.IEventBus 事件总线接口
public interface IEventBus : IDependency {
IEnumerable Notify(string messageName, IDictionary<string, object> eventData);
}
只提供了一个Notify方法,用于事件通知。
2.DefaultOrchardEventBus 事件总线具体实现
相当于实现一个中转,根据messageName反射调用实现IEventHandler的方法
3.DelegateHelper 委托辅助类
静态类,委托方式调用方法
4.EventsInterceptor 事件拦截器
使用Castle.DynamicProxy作为AOP的实现
5.EventsModule 注册事件拦截器
系统启动时注册Events模块
6.EventsRegistrationSource 实现Orchard动态注入总线接口
Autofac动态依赖注入实现
7.IEventHandler 事件处理类
具体处理业务
实现
看一下它们是如何整合到一起工作的。
1.注册相关模块
private IContainer _container;
private IEventBus _eventBus;
private StubEventHandler _eventHandler; //[SetUp]
public void Init() {
_eventHandler = new StubEventHandler(); var builder = new ContainerBuilder();
builder.RegisterType<DefaultOrchardEventBus>().As<IEventBus>();
builder.RegisterType<StubExceptionPolicy>().As<IExceptionPolicy>(); builder.RegisterType<StubEventHandler2>()
.Named(typeof(ITestEventHandler).Name, typeof(IEventHandler))
.Named(typeof(IEventHandler).Name, typeof(IEventHandler))
.WithMetadata("Interfaces", typeof(StubEventHandler2).GetInterfaces().ToDictionary(i => i.Name));
builder.RegisterInstance(_eventHandler)
.Named(typeof(ITestEventHandler).Name, typeof(IEventHandler))
.Named(typeof(IEventHandler).Name, typeof(IEventHandler))
.WithMetadata("Interfaces", typeof(StubEventHandler).GetInterfaces().ToDictionary(i => i.Name)); _container = builder.Build();
_eventBus = _container.Resolve<IEventBus>();
}
事件处理类
public interface ITestEventHandler : IEventHandler {
void Increment();
void Sum(int a);
void Sum(int a, int b);
void Sum(int a, int b, int c);
void Substract(int a, int b);
void Concat(string a, string b, string c);
IEnumerable<string> Gather(int a, string b);
string GetString();
int GetInt();
}
public class StubEventHandler : ITestEventHandler {
public int Count { get; set; }
public int Result { get; set; }
public string Summary { get; set; }
public void Increment() {
Count++;
}
public void Sum(int a) {
Result = 3 * a;
}
public void Sum(int a, int b) {
Result = 2 * (a + b);
}
public void Sum(int a, int b, int c) {
Result = a + b + c;
}
public void Substract(int a, int b) {
Result = a - b;
}
public void Concat(string a, string b, string c) {
Summary = a + b + c;
}
public IEnumerable<string> Gather(int a, string b) {
yield return String.Format("[{0},{1}]", a, b);
}
public string GetString() {
return "Foo";
}
public int GetInt() {
return 1;
}
}
public class StubEventHandler2 : ITestEventHandler {
public void Increment() {
}
public void Sum(int a) {
}
public void Sum(int a, int b) {
}
public void Sum(int a, int b, int c) {
}
public void Substract(int a, int b) {
}
public void Concat(string a, string b, string c) {
}
public IEnumerable<string> Gather(int a, string b) {
return new[] { a.ToString(), b };
}
public string GetString() {
return "Bar";
}
public int GetInt() {
return 2;
}
}
2.使用(UnitTest)
Assert.That(_eventHandler.Count, Is.EqualTo(0));
_eventBus.Notify("ITestEventHandler.Increment", new Dictionary<string, object>());
Assert.That(_eventHandler.Count, Is.EqualTo(1));
Notify方法的字符串"ITestEventHandler.Increment" 就是 interface + method,DefaultOrchardEventBus接受到这个字符串分解委托调用StubEventHandler的Increment方法。
动态注入&拦截器
完成这个功能主要依靠 EventsRegistrationSource.cs和EventsInterceptor.cs,前者负责动态注入事件总线,后者负责拦截处理。看它的源码前最好了解下Autofac和Castle.DynamicProxy.
最简单的示例演示
1.注册模块
var builder = new ContainerBuilder();
builder.RegisterType<StubEventBus>().As<IEventBus>();
builder.RegisterSource(new EventsRegistrationSource());
builder.RegisterType<TestClass>();
_container = builder.Build();
2.相关类
[Test]
public void MyTest()
{
var builder = new ContainerBuilder();
builder.RegisterType<StubEventBus>().As<IEventBus>();
builder.RegisterSource(new EventsRegistrationSource());
builder.RegisterType<TestClass>();
_container = builder.Build(); var c =_container.Resolve<TestClass>();
c.Invoke();
Assert.Fail();
} public class TestClass {
private readonly ICustomerEventHandler eventHandler;
public TestClass(ICustomerEventHandler eventHandler) {
this.eventHandler = eventHandler;
} public void Invoke()
{
eventHandler.Changed("AAA");
}
} public class StubEventBus : IEventBus
{
public string LastMessageName { get; set; }
public IDictionary<string, object> LastEventData { get; set; } public IEnumerable Notify(string messageName, IDictionary<string, object> eventData)
{
Assert.IsTrue(eventData["str1"] == "AAA");
Assert.Pass();
return new object[0];
}
}
public interface ICustomerEventHandler : IEventHandler
{
void Changed(string str1);
}
3.执行代码
var c =_container.Resolve<TestClass>();
c.Invoke();
Assert.Fail()
原理:
ICustomerEventHandler 没有实现类,并且也没有注册,能运行成功就是靠着EventsRegistrationSource和EventsInterceptor为它进行了动态注册和生成了代理类。
EventsInterceptor负责拦截所有实现IEventHandler类的方法,当调用Changed方法时,拦截并且调用所有IEventBus.Notify方法,eventData存储调用参数值。
Orchard源码:EventBus&EventHandler的更多相关文章
- Orchard源码分析(5):Host相关(Orchard.Environment.DefaultOrchardHost类)
概述 Host 是应用程序域级的单例,代表了Orchard应用程序.其处理应用程序生命周期中的初始化.BeginRequest事件.EndRequest事件等. 可以简单理解为HttpApplicat ...
- Orchard 源码探索(Log)
简单工厂模式.抽象工厂模式和适配器模式 依赖倒置原则也叫依赖倒转原则,Dependence Inversion Principle,对抽象进行编程,不要对实现进行编程. A.高层次的模块不应该依赖于低 ...
- Orchard源码分析(7.1):Routing(路由)相关
概述 关于ASP.NET MVC中路由有两个基本核心作用,一是通过Http请求中的Url参数等信息获取路由数据(RouteData),路由数据包含了area.controller.action的名称等 ...
- Orchard源码分析(4.4):Orchard.Caching.CacheModule类
概述 CacheModule也是一个Autofac模块. 一.CacheModule类 CacheModule将DefaultCacheManager注册为ICacheManager: ...
- Orchard源码分析(6):Shell相关
概述在Orchard中,提出子站点(Tenant)的概念,目的是为了增加站点密度,即一个应用程序域可以有多个子站点. Shell是子站点(Tenant)级的单例,换句话说Shell代表了子站点.对比来 ...
- Orchard源码分析(5.1):Host初始化(DefaultOrchardHost.Initialize方法)
概述 Orchard作为一个可扩展的CMS系统,是由一系列的模块(Modules)或主题(Themes)组成,这些模块或主题统称为扩展(Extensions).在初始化或运行时需要对扩展进行安装:De ...
- Orchard源码分析(4.3):Orchard.Events.EventsModule类(Event Bus)
概述 采用Event Bus模式(事件总线),可以使观察者模式中的观察者和被观察者实现解耦. 在.Net 中使用观察者模式,可以使用事件(委托)和接口(类).Orchard Event Bus使用的 ...
- Orchard源码分析(4.1):Orchard.Environment.CollectionOrderModule类
CollectionOrderModule类是一个Autofac模块(Module,将一系列组件和相关的功能包装在一起),而非Orchard模块.其作用是保证多个注册到容器的组件能按FIFO(Firs ...
- Orchard源码分析(3):Orchard.WarmupStarter程序集
概述 Orchard.WarmupStarter程序集包含三个类:WarmupUtility.WarmupHttpModule和Starter<T>.该程序集主要为Orchard应用启动初 ...
随机推荐
- 在VC++中执行VBS代码
此代码来自https://blog.csdn.net/zhu2695/article/details/13770671 作者: zhu2695 时间:2013年10月31日 13:08:41 #i ...
- Java50道经典习题-程序19 输入行数打印菱形图案
题目:根据用户输入的行数打印菱形图案,若用户传入的是为偶数则提示用户重新输入,例如输入数字7打印出如下菱形图案 * *** ************ ***** *** *分析:先把图形分 ...
- jdk1.6 支持 tls1.2协议 并忽略身份验证
jdk1.6不支持tls1.2协议,jdk1.8默认支持,比较好的解决方案是升级jdk,但是升级jdk风险极大.不能升级jdk的情况下,可以使用如下方式. 引入依赖 <dependency> ...
- [CSS3] :nth-child的用法
:nth-child(2)选取第几个标签,“2可以是你想要的数字” .demo01 li:nth-child(2){background:#090} :nth-child(n+4)选取大于等于4标签, ...
- 「工具」三分钟了解一款在线流程绘制工具:Whimsical
Whimsical 是一款在线流程绘制工具,只需要一个浏览器就随时随地绘制精美的流程图.除了流程图(Flowcharts)功能,官方还推出了线框图(Wireframes).便利贴(Sticky Not ...
- Solr7.4的学习与使用
学习的原因: 17年的时候有学习使用过lucene和solr,但是后来也遗忘了,最近公司有个项目需要使用到全文检索,正好也顺便跟着学习一下,使用的版本是Solr7.4的,下载地址:http://arc ...
- ES6之新增const命令使用方法
hi,我又回来了,今天学习一下const命令. 声明一个常量 const声明一个只读常量,一旦声明,常量的值便不可改变. 例子如下: const food = 12; food = 23; // Un ...
- 使用hexo+coding搭建免费个人博客
1.检测node和npm 先检测一下有没有node.js和npm $ node -v //如果有,说明node.js安装成功! $ node -v v8.4.0 //如果有,说明npm安装成功! $n ...
- k-近邻算法 python实现
必要的注释已经写在code里面了: import operator from numpy import* def init(): grp=array([[1.0,1.1],[1.0,1.0],[0,0 ...
- FZU_1894 志愿者选拔 【单调队列】
1 题面 FZU1894 2 分析 单调队列的典型引用 需要注意的是在用维护辅助队列的时候,$L$和$R$的初始化都是0时,队列第一个数就是$L$,最后一个数就是$R-1$. 3 AC代码 #incl ...