And*_*rew 5 .net c# winforms simple-injector asp.net-web-api
背景
我正在构建一个两层的 C# .net 应用程序:
如果您想了解我正在构建的应用程序的更多详细信息,我在这里给出的解释可能过于彻底。
当前发展
目前,我正在 Winforms 客户端上工作。特别是,我正在尝试在此客户端中散列命令模式的适当实现。我有幸偶然发现了这篇出色的博客文章,其中概述了一个可靠的命令架构。为了补充那篇文章,作者接着解释了他如何将查询与命令分开。阅读这些博客后,很明显我的第 2 层(Web api 服务)将从实现这两个中受益匪浅。通用实现允许极好的灵活性、可测试性和可扩展性。
题
我不太清楚的是我如何在 winforms 客户端(第 1 层)上实现这些模式。此处是否继续将查询和命令视为分开的?考虑一个基本操作,例如登录尝试。这是查询还是命令?最终,您需要从 Web 服务返回数据(服务器上的用户信息),因此我认为这是一个查询。另一种情况如何,例如创建新用户的请求。我知道您将创建一个命令对象来存储用户信息并将其发送给服务。命令应该是即发即忘,但您是否不想从服务中获得某种命令是否成功的确认?此外,如果命令处理程序返回 void,
归根结底,对于任何给定的 UI 任务(比如用户创建请求),是否最终会得到一个基于 winforms 客户端的查询/命令,以及命令/查询的 web api 服务版本哪个处理那方面的请求?
查询和命令在这里仍然被视为分开吗?
是的,通常您会触发命令,如果执行此操作后需要更新 UI,您将执行查询以获取新信息。一个例子可以清楚地说明这一点。
假设您将向某个区域分配特定的警卫。指挥部(只是一个DTO)需要的唯一信息是Id守卫的信息和Id区域的信息。相关人员CommandHandler将执行所有任务来处理此问题,例如将该警卫从另一个区域移走,将其标记为不可用等。
现在您的 UI 想要显示更改。用户界面可能有某种列表,其中包含所有警卫及其分配的区域。该列表将由一个GetActiveGuardsAndAreaQuery将返回List<GuardWithAreaInformationDto>. 这DTO可能包含有关所有警卫的各种信息。从命令返回此信息并不是一个干净的关注点分离,因为原子命令处理可以很好地从类似但略有不同的 UI 中使用,这将需要对 UI 信息进行稍微不同的更新。
例如登录尝试。这是查询还是命令?
IMO 登录尝试都不是。这是一个交叉问题,是数据隐藏在安全连接后面的实现细节。然而,应用程序不应该关心这个细节。考虑与另一个客户一起使用该应用程序,您可以在其中托管 WebApi 服务以及Active Directory可以使用的域Windows Authentication。在这种情况下,用户只需登录到他的机器,安全性由客户端和服务器操作系统在通信时处理。
通过您所指的模式,可以使用 a 很好地完成此操作,AuthenticateToWebApiServiceCommandHandlerDecorator通过以模式形式询问用户、从配置文件中读取它或其他方式,确保它们是为服务提供服务的登录凭据。
检查凭证是否有效可以通过执行应用程序始终需要的一种标准来完成,Query例如CheckIfUpdateIsAvailableQuery。如果查询成功,则登录尝试成功,否则登录失败。
如果命令处理程序返回 void,您如何告诉演示者用户创建请求是否成功?
虽然看起来void没有返回任何东西,但事实并非如此。因为如果它没有因某些异常而失败(并明确指出出了什么问题!),那么它一定已经成功了。
在后续行动中中,@dotnetjunkie 描述了一种从命令返回信息的方法,但请注意帖子顶部添加的评论。
总而言之,从失败的命令中抛出明确的异常。您可以在客户端添加一个额外的抽象层来很好地处理这个问题。您可以注入一个IPromptableCommandHandler在编译时只有一个开放通用实现的命令处理程序,而不是直接将命令处理程序注入到不同的呈现器中:
public interface IPromptableCommandHandler<TCommand>
{
void Handle(TCommand command, Action succesAction);
}
public class PromptableCommandHandler<TCommand> : IPromptableCommandHandler<TCommand>
{
private readonly ICommandHandler<TCommand> commandHandler;
public PromptableCommandHandler(ICommandHandler<TCommand> commandHandler)
{
this.commandHandler = commandHandler;
}
public void Handle(TCommand command, Action succesAction)
{
try
{
this.commandHandler.Handle(command);
succesAction.Invoke();
}
catch (Exception)
{
MessageBox.Show("An error occured, please try again.");
// possible other actions like logging
}
}
}
// use as:
public void SetGuardActive(Guid guardId)
{
this.promptableCommandHandler.Handle(new SetGuardActiveCommand(guardId),() =>
this.RefreshGuardsList());
}
Run Code Online (Sandbox Code Playgroud)
归根结底,对于任何给定的 UI 任务(例如用户创建请求),您最终是否会拥有一个基于 winforms 客户端的查询/命令,以及该命令/查询的 Web api 服务版本哪个处理那一端的请求?
不!
客户端您应该创建一个开放通用CommandHandlerProxy,其唯一任务是将命令 dto 传递到 WebApi 服务。
对于服务端架构,您应该阅读另一篇后续文章:编写高度可维护的 WCF 服务,它描述了服务器端架构来很好地处理这个问题。链接的项目还包含 WebApi 的实现!
| 归档时间: |
|
| 查看次数: |
2006 次 |
| 最近记录: |