洋葱架构 - 接口中的 DTO

Onion Architecture - DTOs in interfaces

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

根据我从 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);
    }
}

问题

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

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 接口的一部分,但我不确定这是否是正确的方法。从我发现的开源项目中,我看到 none 他们在域层中使用 DTO,人们似乎在说 DTO 通常是一个应用程序问题,但我可能只是想得太多了。也许我已经用我目前的方式采取了错误的方法?

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

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