3

我对任何类型的 .NET Web 开发都很陌生(到目前为止,我主要使用 Winforms 和服务。)我已经开始与其他两个开发人员一起开发现有的 MVC3 项目。我在概念上熟悉 MVC,并试图了解它在这个项目中的使用方式。

我们有一个 AccountDto 类来表示 Accounts。每个Entity都有一个Response类被另一个类继承,即AccountResponse:

public class Response
{
    [DataMember]
    public bool IsSuccess{get;set;}

    [DataMember]
    public string DisplayMessage { get; set; }

    [DataMember]
    public string DetailedMessage { get; set; }

    [DataMember]
    public ErrorType ErrorType { get; set; }

    public Response(){
        this.IsSuccess=true;
        this.ErrorType = ErrorType.None;
    }
}

public partial class AccountResponse : Response
{
    [DataMember]
    public IList<AccountDto> AccountList { get; set; }
}

有一个 AccountService 将向控制器返回一个 AccountResponse,其中包含 AccountDto 对象的列表:

public AccountResponse GetAccountByAccountId(Int64 accountId)
{
    _logger.Info("Executing GetAccountByAccountId()");
    AccountResponse response = new AccountResponse();

    try
    {
        Account item = AccountPersistence.GetAccountByAccountId(accountId);
        AccountDto dto = Mapper.Map<AccountDto>(item);

        response.AccountList = new List<AccountDto>() { dto };
        response.IsSuccess = true;
    }
    catch (Exception ex)
    {
        response.IsSuccess = false;
        response.ErrorType = ErrorType.GeneralFault;
        response.DetailedMessage = ex.ExceptionMessageBuilder();
        response.DisplayMessage = "System Failure: Failed to get Account by AccountId";
        _logger.Error(ex);
    }
    return response;
}

有人告诉我 Response 的实现是为了能够处理成功/失败消息。因此,在控制器中,有如下代码(如果发生故障,不会发生任何特殊情况):

public ActionResult ToBeCalled(int id)
{
    AccountDto dto = null;
    var response = _accountService.GetAccountByAccountId(Convert.ToInt64(id));
    if (response.IsSuccess)
    {
        dto = response.AccountList[0];
        return View(dto);
    }
    return View(dto);
}

尽管我不确定将在哪里使用成功/错误消息,但这对我来说很有意义。但是,他们现在想从在视图中使用 DTO 切换到使用响应,因此必须在视图中处理成功/失败:

public ActionResult ToBeCalled(int id)
{
    var response = _accountService.GetAccountByAccountId(Convert.ToInt64(id));
    return View(response);
}

这对我来说似乎是 - 而不是针对作为模型的 DTO 进行编码,我必须为每个页面执行以下操作:

@{
    if (Model.IsSuccess)
    {
        var account = Model.AccountList.FirstOrDefault();

        if (account != null)
        {
            @Html.HiddenFor(x => account.AccountNumber)
        }
}

控制器的 ActionResult / HttpPost 方法还必须从这些 Response 对象中解析 DTO。这对我来说似乎是一种反模式。这样的做法正常吗?

抱歉,如果这太长了,如果它属于 Code Review 或其他站点,请迁移。

4

2 回答 2

4

我同意你的观点,这将是一种反模式。视图应该是非常无知的,尤其是像这样的逻辑。

如果成功和失败之间的区别只是 UI 的一小部分,我可以理解为什么这很诱人,但想象一下,如果这种情况发生了变化。视图几乎没有能力(没有不必要的部分嵌套)切换到完全不同的视图。它无法发出重定向或其他错误代码。如果您决定更改您的 UI,您可能需要返回并再次重写您的控制器。

如果将逻辑移动到视图背后的原因是response.IsSuccess从 Controller 中删除逻辑(老实说,这对我来说似乎很好;它与经典几乎相同),您可以考虑另一种方法:将您的类Model.IsValid重构为Response继承自ActionResult。然后你可以将该逻辑移动到ExecuteResult()方法中,它将与你的控制器分开。

于 2012-07-30T17:44:38.040 回答
1

只需使用 coalesce 运算符,您就可以摆脱一大堆杂乱无章的东西(比如那个奇怪的 Response 基类(如果它继续存在,则应该标记为抽象))并避免空值检查。

public ActionResult ToBeCalled(int id)
{
    var response = _accountService.GetAccountByAccountId(id) ??
        new AccountResponse();
    return View(response);
}

更好的是,将该逻辑迁移到您的服务类中,以便它保证对象的返回(当没有支持实体时,存储库这样做不一定有意义,但它适用于服务)。

无论哪种方式,您都不需要在视图中包含难看的空检查或 if/else 逻辑。将尽可能多的逻辑移到可以测试的地方,你会更快乐。

于 2012-07-30T17:51:44.157 回答