ASP.NET Core Web API下事件驱动型架构的实现(一):一个简单的实现 (4)

在此,将事件总线注册为单例(Singleton)服务,是因为它不保存状态。理论上讲,使用单例服务时,需要特别注意服务实例对象的生命周期管理,因为它的生命周期是整个应用程序级别,在程序运行的过程中,由其引用的对象资源将无法释放,因此,当程序结束运行时,需要合理地将这些资源dispose掉。好在ASP.NET Core的依赖注入框架中已经帮我们处理过了,因此,对于上面的PassThroughEventBus单例注册,我们不需要过多担心,程序执行结束并正常退出时,依赖注入框架会自动帮我们dispose掉PassThroughEventBus的单例实例。那么对于单例实例来说,我们是否只需要通过AddSingleton方法进行注册就可以了,而无需关注它是否真的被dispose了呢?答案是否定的,有兴趣的读者可以参考,在下一篇文章中我会对这部分内容做些介绍。

接下来,我们需要定义一个CustomerCreatedEvent对象,表示“客户信息已经创建”这一事件信息,同时,再定义一个CustomerCreatedEventHandler事件处理器,用来处理从PassThroughEventBus接收到的事件消息。代码如下,当然也很简单:

public class CustomerCreatedEvent : IEvent { public CustomerCreatedEvent(string customerName) { this.Id = Guid.NewGuid(); this.Timestamp = DateTime.UtcNow; this.CustomerName = customerName; } public Guid Id { get; } public DateTime Timestamp { get; } public string CustomerName { get; } } public class CustomerCreatedEventHandler : IEventHandler<CustomerCreatedEvent> { public bool CanHandle(IEvent @event) => @event.GetType().Equals(typeof(CustomerCreatedEvent)); public Task<bool> HandleAsync(CustomerCreatedEvent @event, CancellationToken cancellationToken = default) { return Task.FromResult(true); public Task<bool> HandleAsync(IEvent @event, CancellationToken cancellationToken = default) => CanHandle(@event) ? HandleAsync((CustomerCreatedEvent)@event, cancellationToken) : Task.FromResult(false); }

两者分别实现了我们最开始定义好的IEvent和IEventHandler接口。在CustomerCreatedEventHandler类的第一个HandleAsync重载方法中,我们暂且让它简单地返回一个true值,表示事件处理成功。下面要做的事情就是,在客户信息创建成功后,向事件总线发送CustomerCreatedEvent事件,以及在ASP.NET Core Web API程序启动的时候,注册CustomerCreatedEventHandler实例,并调用事件总线的Subscribe方法,使其开始侦听事件的派发行为。

于是,CustomerController需要依赖IEventBus,并且在CustomerController.Create方法中,需要通过调用IEventBus的Publish方法将事件发送出去。现对CustomerController的实现做一些调整,调整后代码如下:

[Route("api/[controller]")] public class CustomersController : Controller { private readonly IConfiguration configuration; private readonly string connectionString; private readonly IEventBus eventBus; public CustomersController(IConfiguration configuration, IEventBus eventBus) { this.configuration = configuration; this.connectionString = configuration["mssql:connectionString"]; this.eventBus = eventBus; } // 创建新的客户信息 [HttpPost] public async Task<IActionResult> Create([FromBody] dynamic model) { var name = (string)model.Name; if (string.IsNullOrEmpty(name)) { return BadRequest(); } const string sql = "INSERT INTO [dbo].[Customers] ([CustomerId], [CustomerName]) VALUES (@Id, @Name)"; using (var connection = new SqlConnection(connectionString)) { var customer = new Model.Customer(name); await connection.ExecuteAsync(sql, customer); await this.eventBus.PublishAsync(new CustomerCreatedEvent(name)); return Created(Url.Action("Get", new { id = customer.Id }), customer.Id); } } // Get方法暂且省略 }

然后,修改Startup.cs中的ConfigureServices方法,将CustomerCreatedEventHandler注册进来:

public void ConfigureServices(IServiceCollection services) { services.AddMvc(); services.AddTransient<IEventHandler, CustomerCreatedEventHandler>(); services.AddSingleton<IEventBus, PassThroughEventBus>(); }

并且调用Subscribe方法,开始侦听消息总线:

public void Configure(IApplicationBuilder app, IHostingEnvironment env) { var eventBus = app.ApplicationServices.GetRequiredService<IEventBus>(); eventBus.Subscribe(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseMvc(); }

OK,现在让我们在CustomerCreatedEventHandler的HandleAsync方法上设置个断点,按下F5启用Visual Studio 2017调试,然后重新使用Invoke-RestMethod命令发送一个Post请求,可以看到,HandleAsync方法上的断点被命中,同时事件已被正确派发:

image

数据库中的数据也被正确更新:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wsppwj.html