asp.net-mvc – ICommandHandler / IQueryHandler with async /
EDITH说(tl; dr)
我去了一个建议的解决方案的变体;保持所有ICommandHandler和IQueryHandlers可能是异步的,并在同步情况下返回已解决的任务.不过,我不想在任何地方使用Task.FromResult(…),所以为了方便起见我定义了一个扩展方法: public static class TaskExtensions { public static Task<TResult> AsTaskResult<TResult>(this TResult result) { // Or TaskEx.FromResult if you're targeting .NET4.0 // with the Microsoft.BCL.Async package return Task.FromResult(result); } } // Usage in code ... using TaskExtensions; class MySynchronousQueryHandler : IQueryHandler<MyQuery,bool> { public Task<bool> Handle(MyQuery query) { return true.AsTaskResult(); } } class MyAsynchronousQueryHandler : IQueryHandler<MyQuery,bool> { public async Task<bool> Handle(MyQuery query) { return await this.callAWebserviceToReturnTheResult(); } } 可惜C#不是Haskell …而是8-).真的闻起来像Arrows的应用程序.无论如何,希望这有助于任何人.现在我原来的问题:-) 介绍 你好! 对于一个项目,我正在C#(.NET4.5,C#5.0,ASP.NET MVC4)中设计应用程序架构.有了这个问题,我希望得到一些意见,我偶然试图融入异步/等待.注意:这是相当长的一个:-) 我的解决方案结构如下所示: > MyCompany.Contract(命令/查询和通用接口) 我阅读了可维护的架构和命令查询分离,发现这些帖子非常有用: > Meanwhile on the query side of my architecture 到目前为止,我已经围绕着ICommandHandler / IQueryHandler概念和依赖注入(我正在使用SimpleInjector – 它真的很简单). 给定方法 上面的文章的方法建议使用POCO作为命令/查询,并将这些调用器作为以下处理程序接口的实现进行描述: interface IQueryHandler<TQuery,TResult> { TResult Handle(TQuery query); } interface ICommandHandler<TCommand> { void Handle(TCommand command); } 在MVC控制器中,您可以使用以下内容: class AuthenticateCommand { // The token to use for authentication public string Token { get; set; } public string SomeResultingSessionId { get; set; } } class AuthenticateController : Controller { private readonly ICommandHandler<AuthenticateCommand> authenticateUser; public AuthenticateController(ICommandHandler<AuthenticateCommand> authenticateUser) { // Injected via DI container this.authenticateUser = authenticateUser; } public ActionResult Index(string externalToken) { var command = new AuthenticateCommand { Token = externalToken }; this.authenticateUser.Handle(command); var sessionId = command.SomeResultingSessionId; // Do some fancy thing with our new found knowledge } } 我对这种方法的一些看法: >在纯CQS中,只有查询应该返回值,而命令应该是唯一的命令.实际上,命令返回值更方便,而不是发出命令,并且稍后对命令应该首先返回的内容(例如数据库ID等)进行查询.这就是为什么the author suggested将返回值放入命令POCO中. 当然,你可以将MVC处理程序标记为异步,这就是这个问题. 命令返回值 我考虑了给定的方法,并对接口进行了更改以解决问题1.和2.因为我添加了一个具有显式结果类型的ICommandHandler,就像IQueryHandler一样.这仍然违反了CQS,但是至少很明显的是,这些命令返回某种价值,其附加的好处是不必用result属性来混淆命令对象: interface ICommandHandler<TCommand,TResult> { TResult Handle(TCommand command); } 自然可以说,当你有相同的命令和查询接口为什么麻烦?但是我认为这是不同的命名,只是看起来更清洁我的眼睛. 我的初步解决方案 然后我想到了第三个问题,我的一些命令/查询处理程序需要是异步的(例如,发布WebRequest到另一个Web服务进行身份验证),而其他人则没有.所以我认为最好是从头开始设计我的处理程序以进行异步/等待 – 这甚至对于MVC处理程序来说,即使是事实上同步的处理程序: interface IQueryHandler<TQuery,TResult> { Task<TResult> Handle(TQuery query); } interface ICommandHandler<TCommand> { Task Handle(TCommand command); } interface ICommandHandler<TCommand,TResult> { Task<TResult> Handle(TCommand command); } class AuthenticateCommand { // The token to use for authentication public string Token { get; set; } // No more return properties ... } AuthenticateController: class AuthenticateController : Controller { private readonly ICommandHandler<AuthenticateCommand,string> authenticateUser; public AuthenticateController(ICommandHandler<AuthenticateCommand,string> authenticateUser) { // Injected via DI container this.authenticateUser = authenticateUser; } public async Task<ActionResult> Index(string externalToken) { var command = new AuthenticateCommand { Token = externalToken }; // It's pretty obvious that the command handler returns something var sessionId = await this.authenticateUser.Handle(command); // Do some fancy thing with our new found knowledge } } 虽然这解决了我的问题 – 明显的返回值,但是所有的处理程序都可以是异步的 – 它伤害了我的大脑将异步放在一个不是异步的东西上,因为它是异常的.我看到有几个缺点: >处理程序接口不像我想要的那样整齐 – Task< ...>事情对我的眼睛是非常冗长的,一见钟情的事实,我只想从一个查询/命令返回的东西 现在我没有看到最好的解决方案…我很失落. 任何人有类似的问题和优雅的解决方案我没有想到? 解决方法
异步等待不要与传统的OOP完美结合.我有一个关于这个主题的博客系列;你可能会发现
post on async interfaces特别有用(尽管我没有覆盖任何你还没有发现的东西).
异步周围的设计问题与IDisposable周围的设计问题非常相似;将IDisposable添加到界面是一个突破性的变化,因此您需要知道任何可能的实现可能是一次性的(实现细节).异步存在并行问题;您需要知道任何可能的实现可能是异步的(实现细节). 由于这些原因,我将接口上的任务返回方法视为“可能异步”方法,就像从IDisposable继承的接口意味着“可能拥有资源”. 我知道的最好的方法是: >定义任何可能与异步签名异步的方法(返回任务/任务< T>). 这种方法几乎正是你已经在做的.对于纯粹的功能语言,可能存在一个更理想的解决方案,但是我没有看到C#. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- asp.net-mvc – asp.net mvc中HttpUnauthorizedResult上的默
- asp.net – 使用冗长的服务器进程取消asynch回发
- asp.net – 代码后面的根运算符(“?”)地址的相对路径
- asp.net – ASP MVC – 创建目录路径而不是文件路径的Bundl
- asp.net-mvc – 将.html文件渲染为ASP.NET MVC中的视图
- asp.netcore 3.0 Docker Nginx(震惊,原来docker是这样的!
- asp.net-mvc-3 – MVC3:不将属性映射到DB列的属性
- asp.net – 网络负载平衡方案的会话状态
- asp.net-mvc – 流畅的验证自定义验证规则
- Singleton vs Cache ASP.NET