asp.net-mvc – ICommandHandler / IQueryHandler with async / a
|
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 – 本地化路由
- asp.net – 指定的CGI应用程序遇到错误,服务器终止进程
- asp.net-mvc – 当ModelState为InValid时调用的Ajax.BeginF
- asp.net-mvc-3 – 不能使用NuGet PagedList ASP.NET MVC#查
- asp.net-mvc – Html.Raw()在ASP.NET MVC Razor视图
- 在ASP.NET应用程序中使用Ajax更新面板的优点和缺点
- asp.net – 如何在运行时设置ObjectDataSource选择参数
- asp.net-mvc – 使用IIS7.5将网站中的URL绑定到另一个网站控
- asp.net – ‘WebForm_DoPostBackWithOptions’在IE11预览中
- asp.net-mvc-3 – URL路径参数用例
