gpt4 book ai didi

c# - 如何在 WinForms 客户端应用程序中使用命令模式?

转载 作者:太空狗 更新时间:2023-10-30 01:32:00 24 4
gpt4 key购买 nike

背景

我正在构建一个两层 C# .net 应用程序:

  1. 第 1 层:使用 MVP(模型- View -呈现器)设计模式的 Winforms 客户端应用程序。
  2. 第 2 层:位于 Entity Framework 和 SQL Server 之上的 WebAPI RESTful 服务。

如果您想了解我正在构建的应用程序的更多详细信息,我给出的解释可能过于详尽了 here .

当前发展

目前,我正在开发 Winforms 客户端。特别是,我正在尝试在此客户端中充分实现命令模式。我有幸偶然发现this优秀的博客文章,概述了可靠的命令架构。为了补充该帖子,作者 followed up通过解释他如何将查询与命令分开。阅读这些博客后,很明显我的第 2 层(Web API 服务)将从实现这两个方面受益匪浅。通用实现具有出色的灵 active 、可测试性和可扩展性。

问题

我不太清楚的是我如何在 winforms 客户端(第 1 层)上实现这些模式。查询和命令在这里继续被认为是分开的吗?考虑一个基本操作,例如登录尝试。那是查询还是命令?最终,您需要从 Web 服务返回数据(服务器上的用户信息),所以这会让我认为这是一个查询。另一种情况呢,比如请求创建一个新用户。我知道您会创建一个命令对象来存储用户信息并将其发送到服务。命令应该是即发即弃的,但是您不想从服务那里得到命令成功的某种确认吗?此外,如果命令处理程序返回 void,您将如何告诉演示者用户创建请求是否成功?

归根结底,对于任何给定的 UI 任务(比如用户创建请求),最终是否会得到一个基于 winforms 客户端的查询/命令,以及一个 web api 服务版本的在那一端处理请求的命令/查询?

最佳答案

Do queries and commands continue to be considered separate here?

是的,通常您会触发一个命令,如果您需要在执行此操作后更新 UI,您将执行查询以获取新信息。举个例子可以清楚地说明这一点。

假设您要为某个区域分配一个特定的守卫。命令(只是一个 DTO )需要的唯一信息是 Id guard 和Id该地区的。相关CommandHandler将执行所有任务来处理这个,例如将那个守卫从另一个区域移走,将他记为不可用等。

现在您的 UI 会想要显示更改。用户界面可能有某种列表,其中包含所有守卫及其分配的区域。此列表将由一个 GetActiveGuardsAndAreaQuery 填充。这将返回 List<GuardWithAreaInformationDto> .这DTO可能包含有关所有 guard 的各种信息。从命令返回此信息并不是完全分离关注点,因为原子命令处理可以很好地用于类似但略有不同的 UI,这将需要对 UI 信息进行略有不同的更新。

such as a login attempt. Is that a query or a command?

IMO 登录尝试都不是。这是一个横切关注点,是数据隐藏在安全连接后面的实现细节。然而,应用程序不应该关心这个细节。考虑与另一个客户一起使用该应用程序,您可以在其中托管 WebApi 服务 Active Directory您可以使用的域 Windows Authentication .在那种情况下,用户只需登录到他的机器,安全性由客户端和服务器操作系统在通信时处理。

使用您所指的模式可以使用 AuthenticateToWebApiServiceCommandHandlerDecorator 很好地完成此操作这通过以模态形式询问用户、从配置文件中读取它或其他任何方式来确保它们是服务于服务的登录凭据。

检查凭据是否有效可以通过执行一种标准 Query 来完成您的应用程序总是需要诸如 CheckIfUpdateIsAvailableQuery .如果查询成功,则登录尝试成功,否则失败。

if a command handler returns void, how would you tell the presenter whether or not the user creation request was successful?

虽然看起来 void不返回任何东西这不是真的。因为如果它没有因某些异常而失败(并明确显示出了什么问题!),它就一定成功了。

follow up 中在提到的博客文章中,@dotnetjunkie 描述了一种从命令返回信息的方法,但要注意文章顶部添加的评论。

总而言之,从失败的命令中抛出明确的异常。您可以添加一个额外的抽象客户端层来很好地处理这个问题。您可以注入(inject) IPromptableCommandHandler,而不是直接将 commandhandler 注入(inject)到不同的演示者中。它在编译时只有一个开放的通用实现:

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());

}

At the end of the day, for any given UI task (say the user creation request), does it end up that you end up having a winforms client based query/command, as well as a web api service version of the command/query which handles the request on that end?

不!

客户端你应该创建一个单一的开放通用CommandHandlerProxy唯一的任务是将命令 dto 传递给 WebApi 服务。

对于服务端架构,您应该阅读另一篇后续文章:Writing Highly Maintainable WCF Services它描述了一个服务器端架构来很好地处理这个问题。链接的项目还包含 WebApi 的实现!

关于c# - 如何在 WinForms 客户端应用程序中使用命令模式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38670725/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com