Asp.net core webapi CQRS设计模式的正确实现?
我正在开发一些使用CQRS设计模式的遗留应用程序(.Net核心和框架应用程序) 基本上,我们有一个使用Dapper的数据访问层存储库。然后,我们通过创建两个不同的接口来应用CQR,一个用于命令,一个用于查询。这些接口看起来像: //查询接口 公共接口IOrderQuery { 订单GetOrderById(int-id); } //命令界面Asp.net core webapi CQRS设计模式的正确实现?,asp.net-core-webapi,cqrs,mediatr,Asp.net Core Webapi,Cqrs,Mediatr,我正在开发一些使用CQRS设计模式的遗留应用程序(.Net核心和框架应用程序) 基本上,我们有一个使用Dapper的数据访问层存储库。然后,我们通过创建两个不同的接口来应用CQR,一个用于命令,一个用于查询。这些接口看起来像: //查询接口 公共接口IOrderQuery { 订单GetOrderById(int-id); } //命令界面 公共接口IOrderCommand { bool PlaceOrder(订单placedOrder) } 在我看来,这可能不是CQR的正确实现,因为我们
公共接口IOrderCommand
{
bool PlaceOrder(订单placedOrder)
}
在我看来,这可能不是CQR的正确实现,因为我们对输入和输出使用相同的模型,并且每个操作都没有特定的处理程序。然而,我的主要开发人员说,这是正确的方法,因为我们只需要将命令和查询分开,然后归档CQRS模式。我现在很困惑
此外,我们正在对web api应用相同的方法,其中存储库使用httpClient
一、 因此,建议使用MediatR应用CQR和DDD,但看起来他们不想使用它,因为它太复杂了
我只是一个初级开发人员,所以有人能为我解释一下,我们目前使用的方法是CQR的正确实现吗?我应该在HttpClient上应用CQR吗?使用CQR的好处是什么
谢谢您有一个正确的观点,这不是实现CQR的典型方法。在我看来,它更像是一个单一的方法存储库。虽然CQRS的主要目标是分离查询和命令,但从长远来看,这种方法可能会使事情变得复杂 无论是查询还是命令,CQRS的一个典型实现是,您拥有一个查询(或命令)对象,该对象包含执行此查询所需的所有信息+处理此查询的处理程序。检查下面的示例
public class OrdersQuery
{
public DateTime? FromDate { get; }
public DateTime? ToDate { get; }
public OrdersQuery(DateTime? fromDate, DateTime? toDate)
{
FromDate = fromDate;
ToDate = toDate;
}
}
public class OrdersQueryHandler
{
public List<Order> Handle(OrdersQuery query)
{
//Implementation Goes Here
}
}
public class OrdersQuery : IRequest<List<Order>>
{
public DateTime? FromDate { get; }
public DateTime? ToDate { get; }
public OrdersQuery(DateTime? fromDate, DateTime? toDate)
{
FromDate = fromDate;
ToDate = toDate;
}
}
public class OrdersQueryHandler : IRequestHandler<OrdersQuery, List<Order>>
{
public Task<List<Order>> Handle(OrdersQuery request, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
}
public static class Program
{
public static async Task Main(string[] args)
{
var services = new ServiceCollection()
.AddMediatR(typeof(Program).Assembly)
.BuildServiceProvider();
var mediator = services.GetRequiredService<IMediator>();
var orders = await mediator.Send(new OrdersQuery(DateTime.Now.AddDays(-30), DateTime.Now));
}
}
但您可能已经看到了这个问题,在现实世界的应用程序中,您将需要使用依赖项注入、工厂或某种方式,以便于使用查询处理程序
您不能每次需要使用新的SomeHandler(),这将创建对处理程序的硬依赖,并使代码更难维护。如果您采用问题中建议的方法,那么每个查询/命令处理程序将有一个接口。想一想在某个时刻需要注入多少接口来执行一些复杂的业务规则
CQR和Mediator模式在解决这类问题方面发挥了很好的作用,在我看来,MediatR是最好的库,它一点也不复杂。检查下面的示例
public class OrdersQuery
{
public DateTime? FromDate { get; }
public DateTime? ToDate { get; }
public OrdersQuery(DateTime? fromDate, DateTime? toDate)
{
FromDate = fromDate;
ToDate = toDate;
}
}
public class OrdersQueryHandler
{
public List<Order> Handle(OrdersQuery query)
{
//Implementation Goes Here
}
}
public class OrdersQuery : IRequest<List<Order>>
{
public DateTime? FromDate { get; }
public DateTime? ToDate { get; }
public OrdersQuery(DateTime? fromDate, DateTime? toDate)
{
FromDate = fromDate;
ToDate = toDate;
}
}
public class OrdersQueryHandler : IRequestHandler<OrdersQuery, List<Order>>
{
public Task<List<Order>> Handle(OrdersQuery request, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
}
public static class Program
{
public static async Task Main(string[] args)
{
var services = new ServiceCollection()
.AddMediatR(typeof(Program).Assembly)
.BuildServiceProvider();
var mediator = services.GetRequiredService<IMediator>();
var orders = await mediator.Send(new OrdersQuery(DateTime.Now.AddDays(-30), DateTime.Now));
}
}
公共类OrdersQuery:IRequest
{
公共日期时间?从日期{get;}
公共日期时间?ToDate{get;}
公共订单查询(DateTime?fromDate,DateTime?toDate)
{
FromDate=FromDate;
ToDate=ToDate;
}
}
公共类OrdersQueryHandler:IRequestHandler
{
公共任务句柄(OrdersQuery请求、CancellationToken CancellationToken)
{
抛出新的NotImplementedException();
}
}
公共静态类程序
{
公共静态异步任务主(字符串[]args)
{
var services=newservicecolection()
.AddMediatR(类型(程序).Assembly)
.BuildServiceProvider();
var mediator=services.GetRequiredService();
var orders=wait mediator.Send(new OrdersQuery(DateTime.Now.AddDays(-30),DateTime.Now));
}
}
这里,您的查询将实现IRequest,其中T是结果,您的查询处理程序将实现IRequestHandler,其中T是查询类型,TResult是结果(例如,List)(注意:TResult必须与IRequest中的类型参数匹配)。在本例中,我使用MS依赖项注入,但您可以使用您选择的DI库
MediatR在此扫描程序集中的所有处理程序(如果需要,可以手动注册它们)。现在要使用它,您只需要了解IMediator接口,不再需要IORDersky、IOrdersCommand等等。您将只引用IMediator,中介将负责为正确的查询解析正确的处理程序
现在讨论是否应该通过HTTP为资源使用CQR的问题。如果说CQR,您指的是这里与调解人讨论的模式。是的,你肯定能做到
但CQR通常指的是数据库查询/命令。有时人们也会实现CQR来对不同的数据库进行读写操作。因此,为了避免混淆,只需将其称为中介模式,它肯定适用于Http。您有一个正确的观点,这不是实现CQR的典型方法。在我看来,它更像是一个单一的方法存储库。虽然CQRS的主要目标是分离查询和命令,但从长远来看,这种方法可能会使事情变得复杂 无论是查询还是命令,CQRS的一个典型实现是,您拥有一个查询(或命令)对象,该对象包含执行此查询所需的所有信息+处理此查询的处理程序。检查下面的示例
public class OrdersQuery
{
public DateTime? FromDate { get; }
public DateTime? ToDate { get; }
public OrdersQuery(DateTime? fromDate, DateTime? toDate)
{
FromDate = fromDate;
ToDate = toDate;
}
}
public class OrdersQueryHandler
{
public List<Order> Handle(OrdersQuery query)
{
//Implementation Goes Here
}
}
public class OrdersQuery : IRequest<List<Order>>
{
public DateTime? FromDate { get; }
public DateTime? ToDate { get; }
public OrdersQuery(DateTime? fromDate, DateTime? toDate)
{
FromDate = fromDate;
ToDate = toDate;
}
}
public class OrdersQueryHandler : IRequestHandler<OrdersQuery, List<Order>>
{
public Task<List<Order>> Handle(OrdersQuery request, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
}
public static class Program
{
public static async Task Main(string[] args)
{
var services = new ServiceCollection()
.AddMediatR(typeof(Program).Assembly)
.BuildServiceProvider();
var mediator = services.GetRequiredService<IMediator>();
var orders = await mediator.Send(new OrdersQuery(DateTime.Now.AddDays(-30), DateTime.Now));
}
}
但您可能已经看到了这个问题,在现实世界的应用程序中,您将需要使用依赖项注入、工厂或某种方式,以便于使用查询处理程序
您不能每次需要使用新的SomeHandler(),这将创建对处理程序的硬依赖,并使代码更难维护。如果您采用问题中建议的方法,那么每个查询/命令处理程序将有一个接口。想一想在某个时刻需要注入多少接口来执行一些复杂的业务规则
CQR和Mediator模式在解决这类问题方面发挥了很好的作用,在我看来,Mediator是最好的库,可以实现这一目的,而且目前并不复杂