38b60f83a4da685cd5f05737bb8b349c.jpeg

在这篇文章中,我们将探讨 C# 中介模式的实现。要掌握中介模式的概念及其用例,我建议阅读我之前的博客。

随着时间的推移,将调解器合并到应用程序中可能会导致复杂性增加。对于较小的应用程序,采用多种设计模式可能会引入不必要的复杂性。然而,随着应用程序的扩展,积累业务逻辑并遵守 KISS(保持简单、愚蠢)和 DRY(不要重复自己)等原则可能涉及在服务或经理之间直接调用。虽然依赖项注入可以解决紧密耦合问题,但它仍然可能导致类在各种依赖项下变得繁琐。

这就是调解人模式被证明是有益的。在业务逻辑的上下文中,每个组件都与中介进行通信,而中介则承担促进不同组件之间通信的责任。中介模式找到实用工具的另一种情况是在 .NET 控制器中。您可以简单地注入一个中介器,使其能够处理与其他管理器的通信,而不是将所有管理器注入控制器。

f9e4df8b5074ceb2a56cb9a9750478a5.png

误解

很多时候,人们听到与 CQRS 一起使用的中介模式,并认为 CQRS 需要中介模式。事实并非如此,您也可以在没有中介模式的情况下实现 CQRS。在 CQRS 中使用中介模式可以减少命令/查询和处理程序之间的耦合。我们将在以后的博客中看到 CQRS 和事件溯源示例。

MediatR

MediatR 是 Mediator 模式的 .NET 实现,它为同步和异步请求/响应、命令、查询、通知和事件提供支持。它采用使用 C# 泛型方差的智能调度。MediatR 简化了命令查询责任分离 (CQRS) 模式的采用,提供了一种管理命令和查询处理程序的简单方法。作为中介,MediatR 有效地将命令和查询定向到其指定的处理程序。

MediatR 的主要特点

  • 解耦:MediatR 有助于将请求发送者(命令或查询)与其接收者(处理者)分离,从而有助于提高代码的可维护性和模块化。

  • 管道行为:它适应管道行为的合并,允许轻松添加跨领域关注点,如验证、日志记录和身份验证。

  • 自动发现处理程序:MediatR 具有自动识别和注册处理程序的能力,减少了对显式配置的需求。

让我们通过在电子商务应用程序中构建一个示例客户 API,来探索 C# 中 MediatR 的功能。在此上下文中,我们将命令和查询称为请求,负责处理它们的相应类将称为处理程序。

步骤 1:创建项目并安装所需的包

为此,我们将创建 2 个项目,一个称为 MediatRAPI,它将服务器客户 API。另一个名为 MediatRHandlers 的类库,我们在其中配置请求和请求处理程序。还可以使用以下命令安装 MediatR nuget 包。

dotnet add package MediatR

步骤 2:创建请求

让我们创建两个请求,如下所示,用于创建客户并按客户 ID 检索客户

public class Customer  
    {  
        public string FirstName { get; set; }  
  
        public string LastName { get; set; }  
  
        public string EmailAddress { get; set; }  
  
        public string Address { get; set; }  
    }

using MediatR;  
using MediatRHandlers.Entities;  
  
namespace MediatRHandlers.Requests  
{  
    public class CreateCustomerRequest : IRequest<int>  
    {  
        public Customer Customer { get; set; }  
    }  
}

using MediatR;  
using MediatRHandlers.Entities;  
  
namespace MediatRHandlers.Requests  
{  
    public class GetCustomerRequest : IRequest<Customer>  
    {  
        public int CustomerId { get; set; }  
    }  
}

步骤 3:创建处理程序

对于上述每个请求,请创建处理程序,如下所示。

using MediatR;
using MediatRHandlers.Repositories;
using MediatRHandlers.Requests;

namespace MediatRHandlers.RequestHandlers
{
    public class CreateCustomerHandler : IRequestHandler<CreateCustomerRequest, int>
    {
        //Inject Validators 
        private readonly ICustomerRepository _customerRepository;

        public CreateCustomerHandler(ICustomerRepository customerRepository)
        {
            _customerRepository = customerRepository;
        }

        public async Task<int> Handle(CreateCustomerRequest request, 
            CancellationToken cancellationToken)
        {
            // First validate the request
            return await _customerRepository.CreateCustomer(request.Customer);
        }
    }
}
using MediatR;
using MediatRHandlers.Entities;
using MediatRHandlers.Repositories;
using MediatRHandlers.Requests;

namespace MediatRHandlers.RequestHandlers
{
    public class GetCustomerHandler : IRequestHandler<GetCustomerRequest, Customer>
    {
        private readonly ICustomerRepository _customerRepository;

        public GetCustomerHandler(ICustomerRepository customerRepository)
        {
            _customerRepository = customerRepository;
        }

        public async Task<Customer> Handle(GetCustomerRequest request, CancellationToken cancellationToken)
        {
            return await _customerRepository.GetCustomer(request.CustomerId);
        }
    }
}

步骤 4:创建控制器

创建一个客户控制器,如下所示,如果您注意到我们没有注入所有处理程序,而是只注入中介器。

using MediatR;
using MediatRHandlers.Entities;
using MediatRHandlers.Requests;
using Microsoft.AspNetCore.Mvc;

namespace MediatRAPI.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class CustomerController : ControllerBase
    {
        private readonly IMediator _mediator;

        public CustomerController(IMediator mediator)
        {
            _mediator = mediator;
        }

        [HttpGet("customerId")]
        public async Task<Customer?> GetCustomerAsync(int customerId)
        {
            var customerDetails = await _mediator.Send(new GetCustomerRequest() { CustomerId = customerId});

            return customerDetails;
        }

        [HttpPost]
        public async Task<int> CreateCustomerAsync(Customer customer)
        {
            var customerId = await _mediator.Send(new CreateCustomerRequest() { Customer = customer});
            return customerId;
        }
    }
}

第 5 步:连接注册

在程序或启动文件中注册 MediatR 注册,如下所示。

using Microsoft.Extensions.DependencyInjection;

namespace MediatRHandlers
{
    public static class MediatRDependencyHandler
    {
        public static IServiceCollection RegisterRequestHandlers(
        this IServiceCollection services)
        {
            return services
                .AddMediatR(cf => cf.RegisterServicesFromAssembly(typeof(MediatRDependencyHandler).Assembly));
        }
    }
}
using MediatRHandlers;
using MediatRHandlers.Repositories;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddScoped<ICustomerRepository, CustomerRepository>();
builder.Services.RegisterRequestHandlers();

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();



var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseAuthorization();

app.MapControllers();

app.Run();

步骤 6:运行 API

点击运行API项目后,您将看到客户API大摇大摆,您可以在其中测试创建客户并获取客户,如下所示。

c9ee54afcdca27d90c47f3a637d1a6ee.png

21231b9ce92839ddb68c97a0f63a1a94.png

114f8b683d440dae302cd2883c02c09a.jpeg

在将 Mediator 模式纳入您的项目之前,彻底评估其优缺点至关重要。尽管它可以作为协调系统中对象之间通信的可靠解决方案,但它可能不是每个方案的最佳选择。

如果你喜欢我的文章,请给我一个赞!谢谢

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐