我在我的 asp.net 核心项目中使用 CQS 模式。让我们从一个例子开始,以更好地解释我想要实现的目标。我创建了一个命令:
public class EmptyCommand : INotification{}
命令处理程序:
public class EmptyCommandHandler : INotificationHandler<EmptyCommand>
{
public Task Handle(EmptyCommand notification, CancellationToken cancellationToken)
{
return Task.FromResult(string.Empty);
}
}
查询:
public class EmptyQuery : IRequest<string>{}
查询处理程序:
public class EmptyQueryHandler : IRequestHandler<EmptyQuery, string>
{
public Task<string> Handle(EmptyQuery notification, CancellationToken cancellationToken)
{
return Task.FromResult(string.Empty);
}
}
这是一个简单的示例,说明如何运行命令并从 EmptyCommandHandler 和 EmptyQueryHandler 查询和调用 Handle 方法:
readonly IMediator _mediator;
public HomeController(IMediator mediator)
{
_mediator = mediator;
}
public async Task<IActionResult> Index()
{
await _mediator.Publish(new EmptyCommand());
var queryResult = await _mediator.Send(new EmptyQuery());
return View();
}
请记住,查询可以返回其他类型,不一定是 string。
我想创建某种桥接类,例如MediatorBoostrapper,它允许我在每次调用 Publish 方法时运行一些业务逻辑(例如,通过 Logger 记录命令/查询),然后
从命令处理程序调用 public Task Handle(EmptyCommand notification,... 方法。解决方案必须是通用的,因此每次运行 Publish 时都会调用此方法方法。我还希望能够对 Send 方法执行相同的操作。
我正在考虑创建 public class MediatorBoostrapper : IMediator
但不确定该类的正确实现应该是什么以及我的想法是否好。
有任何想法吗?干杯
编辑
我想要一个如何使用 Behaviors 的例子
每次我运行查询的 Send 方法时,创建一种从通用处理程序运行一些外部方法的通用方法。我想要一个类似的 Publish 方法示例,我用它来发送命令。
我想要一个如何使用 Polymorphic dispatch 的例子 用于创建 GenericCommandHandler 和 GenericQueryHandler
我在 GitHub 上创建了一个示例项目,可以找到 here 您可以随意尝试使用您的解决方案扩展此项目。
最佳答案
这次我想从头开始回答问题。
2.
TL;DR Polymorphic Dispatch cannot be used for the CQS
在使用了 MediatR 库一段时间后,阅读了我的问题下的评论并咨询了我的 friend ,我发现Polymorphic Dispatch(PD) 只能用于创建通用处理程序命令的情况。 Queries 无法实现 PD 方案。基于Documentation ,处理程序是逆变而不是协变的。这意味着 PD 仅在 TResponse 的情况下起作用。是常量类型。对于查询,这是错误的,每个查询处理程序都可以返回不同的结果。
我还找到了this issue .我认为了解只有在您的容器支持的情况下才能使用多态分派(dispatch)是一件很有趣的事情。
1. Behaviors是使用 MediatR 时 CQS 的唯一解决方案。 基于#Steve 和 comment from jbogard 在我的问题下的评论我找到了如何使用 Behaviors 和 IRequestHandler 来实现严格的命令模式。完整评论:
Just to summarize the changes, there are 2 main flavors of requests: those that return a value, and those that do not. The ones that do not now implement
IRequest<T>whereT : Unit. This was to unify requests and handlers into one single type. The diverging types broke the pipeline for many containers, the unification means you can use pipelines for any kind of request.It forced me to add the Unit type in all cases, so I've added some helper classes for you.
IRequestHandler<T>- implement this and you will returnTask<Unit>.AsyncRequestHandler<T>- inherit this and you will returnTask.RequestHandler<T>- inherit this and you will return nothing(void).For requests that do return values:
IRequestHandler<T, U>- you will returnTask<U>RequestHandler<T, U>- you will returnUI got rid of the AsyncRequestHandler because it really wasn't doing anything after the consolidation, a redundant base class.
例子
a) 命令管理:
public class EmptyCommand : IRequest{...}
public class EmptyCommandHandler : RequestHandler<EmptyCommand>
{
protected override void Handle(EmptyCommand request){...}
}
b) 查询管理:
// can be any other type not necessarily `string`
public class EmptyQuery : IRequest<string>{...}
public class EmptyQueryHandler : IRequestHandler<EmptyQuery, string>
{
public Task<string> Handle(EmptyQuery notification, CancellationToken cancellationToken)
{
return Task.FromResult("Sample response");
}
}
c) 样本 LogginBehavior类:
public class LoggingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
readonly ILogger<LoggingBehavior<TRequest, TResponse>> _logger;
public LoggingBehavior(ILogger<LoggingBehavior<TRequest, TResponse>> logger)
{
_logger = logger;
}
public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
{
var requestType = typeof(TRequest).Name;
var response = await next();
if (requestType.EndsWith("Command"))
{
_logger.LogInformation($"Command Request: {request}");
}
else if (requestType.EndsWith("Query"))
{
_logger.LogInformation($"Query Request: {request}");
_logger.LogInformation($"Query Response: {response}");
}
else
{
throw new Exception("The request is not the Command or Query type");
}
return response;
}
}
d) 注册 LoggingBehavior添加命令
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));
到ConfigureServices的正文Startup.cs 中的方法。
e) 如何运行示例命令和查询的示例:
await _mediator.Send(new EmptyCommand());
var result = await _mediator.Send(new EmptyQuery());
关于c# - 在 asp .net core 中为 MediatR 库的 Send 和 Publish 方法添加通用处理程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53895522/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack
我正在学习如何在我的Ruby代码中使用Module.prepend而不是alias_method_chain,我注意到有些人使用send调用它(example):ActionView::TemplateRenderer.send(:prepend,ActionViewTemplateRendererWithCurrentTemplate)而其他人直接调用它(example):ActionView::TemplateRenderer.prepend(ActionViewTemplateRendererWithCurrentTemplate)而且,虽然我还没有看到任何人使用这种风格,但我从
如何在ruby中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL
我正在玩HTML5视频并且在ERB中有以下片段:mp4视频从在我的开发环境中运行的服务器很好地流式传输到chrome。然而firefox显示带有海报图像的视频播放器,但带有一个大X。问题似乎是mongrel不确定ogv扩展的mime类型,并且只返回text/plain,如curl所示:$curl-Ihttp://0.0.0.0:3000/pr6.ogvHTTP/1.1200OKConnection:closeDate:Mon,19Apr201012:33:50GMTLast-Modified:Sun,18Apr201012:46:07GMTContent-Type:text/plain
我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha
如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:
C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.
我正在尝试学习Ruby词法分析器和解析器(whitequarkparser)以了解更多有关从Ruby脚本进一步生成机器代码的过程。在解析以下Ruby代码字符串时。defadd(a,b)returna+bendputsadd1,2它导致以下S表达式符号。s(:begin,s(:def,:add,s(:args,s(:arg,:a),s(:arg,:b)),s(:return,s(:send,s(:lvar,:a),:+,s(:lvar,:b)))),s(:send,nil,:puts,s(:send,nil,:add,s(:int,1),s(:int,3))))任何人都可以向我解释生成的
假设我有一个类A,里面有一些方法。假设stringmethodName是这些方法之一,我已经知道我想给它什么参数。它们在散列中{'param1'=>value1,'param2'=>value2}所以我有:params={'param1'=>value1,'param2'=>value2}a=A.new()a.send(methodName,value1,value2)#callmethodnamewithbothparams我希望能够通过传递我的哈希以某种方式调用该方法。这可能吗? 最佳答案 确保methodName是一个符号,而