【问题标题】:Onion Architecture - DTOs in interfacesOnion Architecture - 接口中的 DTO
【发布时间】:2020-07-19 00:02:47
【问题描述】:

我是 Onion Architecture 的新手,正在尝试将其应用到 ASP.NET 项目中。我目前正在实现 ASP.NET Identity,并希望使用其 UserManager 类来存储用户。

根据我对 Onion Architecture 的理解,我应该在域层中创建一个接口,用于包装UserManager

public interface IUserManager
{
    public Task CreateAsync(string username, string password);
}

然后在基础架构层中,我将实现我自己的 UserManager,它包装了 ASP.NET 标识 UserManager

using Microsoft.AspNetCore.Identity;

public class MyUserManager : IUserManager
{
    private readonly UserManager<IdentityUser> _userManager;
    
    public UserManager(UserManager<IdentityUser> userManager)
    {
        _userManager = userManager;
    }

    public async Task CreateAsync(string username, string password)
    {
        var user = new IdentityUser { UserName = username }; 
        await _userManager.CreateAsync(user, password);
    }
}

问题

我的问题是我还想从UserManager.CreateAsync(...) 返回可能的错误,而不是使用void 返回类型。看起来像这样:

public class IdentityResult
{
    public bool Succeeded { get; set; }
    public IEnumerable<string> Errors { get; set; } // Some Error type instead of a string would be better
}

我必须在域层中定义这个 DTO,因为它们必须是 IUserManager 接口的一部分,但我不确定这是否是正确的方法。从我发现的开源项目中,我没有看到他们在域层中使用 DTO,人们似乎在说 DTO 通常是一个应用程序问题,但我可能只是想多了。也许我现在的做法已经采取了错误的方法?

【问题讨论】:

    标签: asp.net-identity domain-driven-design onion-architecture


    【解决方案1】:

    从软件架构的角度来看,接口不仅是实际的 interface 定义(即您的 IUserManager),而且是两个组件之间契约的一部分,例如函数的输入和输出 DTO以及实现可能抛出的异常并且调用者必须能够捕获。

    在 .NET 中,您可以在同一个项目中定义所有这些,以便在必要时将其作为包分发。在洋葱架构中,从技术上讲,这些是核心的一部分,但这并不意味着需要在单个项目中定义整个核心。如果您将核心实现与合约分开,您可以分发合约而不分发实现。

    【讨论】:

    • 您对 DTO 的解释很有道理,谢谢。所以你还要说的是我应该定义接口的实现可能作为域的一部分抛出的异常?我会认为这取决于实现可能会引发什么样的异常。假设我有函数GetUserById(int id),我不想在域中定义像FileNotFoundException 这样的东西,但也许在域中定义UserNotFoundException 是有意义的(当然都是假设的),虽然我也可以把它留给实现。
    • 例外情况经常被忽视。考虑为您的接口提供 XML 文档。对于像 GetUserById 这样的方法,您将记录它的作用以及它在工作时返回的内容。但是您还需要提供有关如果用户不存在会发生什么的信息。你会返回null吗?你会返回一个带有错误 NotFound 的错误枚举属性的 Result 吗?或者你会抛出一个 NotFoundException 吗?如果抛出异常,则必须指定哪个异常,并确保该异常的使用者具有对它的引用。
    • 你不会指定你的方法可以抛出的每一个异常,比如网络错误、内存不足等等。您将仅记录和发布属于您的界面语言的部分。
    • 我确实是这么理解的。将例外作为合同的一部分(C#interface)是不可能的,但通过 XML 文档提供例外就足够了。感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-18
    • 2023-01-20
    • 1970-01-01
    • 1970-01-01
    • 2013-06-01
    • 2021-11-09
    • 1970-01-01
    相关资源
    最近更新 更多