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应用启动初 ...
随机推荐
- 关于StreamReader.ReadToEnd方法
以前写抓取网页的代码喜欢用ReadToEnd,因为简单省事,后来发现,在爬取网页的时候,如果网速很慢,ReadToEnd超时的几率很大.使用Read改写后,超时几率大大减小,完整代码如下: /// & ...
- 总结目前为止学到的关键字(break,continue,private,static,this,super,final,abstract)
1.控制跳转语句:break(结束) 使用的场景: a.循环当中 b.switch break关键字需要注意的问题: 1.break关键字只能用于循环和switch语句当中,其本质就是结束整段语句的意 ...
- 虚拟化安全 sandbox 技术分析
原文链接:https://cloud.tencent.com/developer/news/215218 前言: libvirt-4.3搭配qemu-2.12使用,如果使用默认的编译选项,可能会让qe ...
- GO学习笔记 - map
map是GO语言中的一种高级数据类型,特点是key和value对应,这和Delphi中的Dictionary一样!map的声明格式:map[key数据类型]value数据类型.使用map前,必须用ma ...
- B - Bridging signals (LIS)
点击打开链接 B - Bridging signals 'Oh no, they've done it again', cries the chief designer at the Waferlan ...
- 【OCP-12c】CUUG 071题库考试原题及答案解析(24)
24. choose the best answer In the EMPLOYEES table there are 1000 rows and employees are working in t ...
- OCP考试题库更新,052最新考题及答案整理-第8题
8.Which two are true about the Fast Recovery Area (FRA)? A) It should be larger than the database. B ...
- SQL Server 根据树状结构表生成以/号分割的路由字符串
很多情况下,我们有必要把树形结构进行数据梳理.比如,要方便的过滤出一个父节点下的所有子节点等等... 这个时候,我们可以生成一个路径表字符串,在应用时只需要对该字符串进行索引即可达成目的. 目标:按图 ...
- [Objective-C语言教程]复合对象(33)
在Objective-C中,可以在类集群中创建子类,该类集合定义了一个嵌入在其中的类. 这些类对象是复合对象.你可能想知道什么是类集群,下面首先了解什么是类集群. 1. 类集群 类集群是基础框架广泛使 ...
- [Swift]数学库函数math.h | math.h -- mathematical library function
常用数学函数 1. 三角函数 double sin (double);//正弦 double cos (double);//余弦 double tan (double);//正切 2 .反三角函数 d ...