概述

看源码是一件吃力又很爽的事情,昨天还被搞的一头雾水,今天忽然守得云开见月明。明白它设计意图的同时,感觉自己又提升了一步:)

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&lt;StubEventBus&gt;().As&lt;IEventBus&gt;();
builder.RegisterSource(new EventsRegistrationSource());
builder.RegisterType&lt;TestClass&gt;();
_container = builder.Build(); var c =_container.Resolve&lt;TestClass&gt;();
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的更多相关文章

  1. Orchard源码分析(5):Host相关(Orchard.Environment.DefaultOrchardHost类)

    概述 Host 是应用程序域级的单例,代表了Orchard应用程序.其处理应用程序生命周期中的初始化.BeginRequest事件.EndRequest事件等. 可以简单理解为HttpApplicat ...

  2. Orchard 源码探索(Log)

    简单工厂模式.抽象工厂模式和适配器模式 依赖倒置原则也叫依赖倒转原则,Dependence Inversion Principle,对抽象进行编程,不要对实现进行编程. A.高层次的模块不应该依赖于低 ...

  3. Orchard源码分析(7.1):Routing(路由)相关

    概述 关于ASP.NET MVC中路由有两个基本核心作用,一是通过Http请求中的Url参数等信息获取路由数据(RouteData),路由数据包含了area.controller.action的名称等 ...

  4. Orchard源码分析(4.4):Orchard.Caching.CacheModule类

    概述 CacheModule也是一个Autofac模块.   一.CacheModule类 CacheModule将DefaultCacheManager注册为ICacheManager:       ...

  5. Orchard源码分析(6):Shell相关

    概述在Orchard中,提出子站点(Tenant)的概念,目的是为了增加站点密度,即一个应用程序域可以有多个子站点. Shell是子站点(Tenant)级的单例,换句话说Shell代表了子站点.对比来 ...

  6. Orchard源码分析(5.1):Host初始化(DefaultOrchardHost.Initialize方法)

    概述 Orchard作为一个可扩展的CMS系统,是由一系列的模块(Modules)或主题(Themes)组成,这些模块或主题统称为扩展(Extensions).在初始化或运行时需要对扩展进行安装:De ...

  7. Orchard源码分析(4.3):Orchard.Events.EventsModule类(Event Bus)

    概述 采用Event Bus模式(事件总线),可以使观察者模式中的观察者和被观察者实现解耦. 在.Net 中使用观察者模式,可以使用事件(委托)和接口(类).Orchard Event  Bus使用的 ...

  8. Orchard源码分析(4.1):Orchard.Environment.CollectionOrderModule类

    CollectionOrderModule类是一个Autofac模块(Module,将一系列组件和相关的功能包装在一起),而非Orchard模块.其作用是保证多个注册到容器的组件能按FIFO(Firs ...

  9. Orchard源码分析(3):Orchard.WarmupStarter程序集

    概述 Orchard.WarmupStarter程序集包含三个类:WarmupUtility.WarmupHttpModule和Starter<T>.该程序集主要为Orchard应用启动初 ...

随机推荐

  1. 关于StreamReader.ReadToEnd方法

    以前写抓取网页的代码喜欢用ReadToEnd,因为简单省事,后来发现,在爬取网页的时候,如果网速很慢,ReadToEnd超时的几率很大.使用Read改写后,超时几率大大减小,完整代码如下: /// & ...

  2. 总结目前为止学到的关键字(break,continue,private,static,this,super,final,abstract)

    1.控制跳转语句:break(结束) 使用的场景: a.循环当中 b.switch break关键字需要注意的问题: 1.break关键字只能用于循环和switch语句当中,其本质就是结束整段语句的意 ...

  3. 虚拟化安全 sandbox 技术分析

    原文链接:https://cloud.tencent.com/developer/news/215218 前言: libvirt-4.3搭配qemu-2.12使用,如果使用默认的编译选项,可能会让qe ...

  4. GO学习笔记 - map

    map是GO语言中的一种高级数据类型,特点是key和value对应,这和Delphi中的Dictionary一样!map的声明格式:map[key数据类型]value数据类型.使用map前,必须用ma ...

  5. B - Bridging signals (LIS)

    点击打开链接 B - Bridging signals 'Oh no, they've done it again', cries the chief designer at the Waferlan ...

  6. 【OCP-12c】CUUG 071题库考试原题及答案解析(24)

    24. choose the best answer In the EMPLOYEES table there are 1000 rows and employees are working in t ...

  7. OCP考试题库更新,052最新考题及答案整理-第8题

    8.Which two are true about the Fast Recovery Area (FRA)? A) It should be larger than the database. B ...

  8. SQL Server 根据树状结构表生成以/号分割的路由字符串

    很多情况下,我们有必要把树形结构进行数据梳理.比如,要方便的过滤出一个父节点下的所有子节点等等... 这个时候,我们可以生成一个路径表字符串,在应用时只需要对该字符串进行索引即可达成目的. 目标:按图 ...

  9. [Objective-C语言教程]复合对象(33)

    在Objective-C中,可以在类集群中创建子类,该类集合定义了一个嵌入在其中的类. 这些类对象是复合对象.你可能想知道什么是类集群,下面首先了解什么是类集群. 1. 类集群 类集群是基础框架广泛使 ...

  10. [Swift]数学库函数math.h | math.h -- mathematical library function

    常用数学函数 1. 三角函数 double sin (double);//正弦 double cos (double);//余弦 double tan (double);//正切 2 .反三角函数 d ...