在 ASP.NET 核心中为服务和存储库层使用依赖注入的正确方法?

Correct way to use dependency injection in ASP.NET Core for service and repository layers?

刚刚在ASP.NET Core RC1学习了依赖注入系统。我有一个控制器(下面的代码)。 选项1(注释掉的那一行)我以前用过。 选项 2 需要在每个控制器中重复并且不是首选。

public class UserRegisterController : Controller
{
    private readonly IUserRegisterService _userRegisterService;
    private readonly UserManager<ApplicationUser> _userManager;
    public UserRegisterController(
        UserManager<ApplicationUser> userManager, 
        IOptions<WebAppSettings> settings,
        IUserRegisterService userRegisterService)
    {
        _userManager = userManager;
        // Option 2
        _userRegisterService = userRegisterService;
        // Option 1
        //_userRegisterService = 
        //    new UserRegisterService(
        //        new ActiveDirectoryRepository(settings.Value.ContainerDomain));
    }
}

internal class UserRegisterService : IUserRegisterService
{
    private readonly IActiveDirectoryRepository _repoAd;

    internal UserRegisterService(IActiveDirectoryRepository repoAd)
    {
       _repoAd = repoAd;
    } 
}

internal class ActiveDirectoryRepository : IActiveDirectoryRepository
{
    private readonly string _container;

    public ActiveDirectoryRepository(string container)
    {
        _container = container;
    }
}

Startup.cs\Configure\ConfigureServices 中我们有以下内容。

选项 1:

services.AddTransient<Admin.Interfaces.IActiveDirectoryRepository, 
                      Admin.Repositories.ActiveDirectoryRepository>();
services.AddTransient<Admin.Interfaces.IUserRegisterService, 
                      Admin.Services.UserRegisterService>();

选项 2:

services.AddTransient<Admin.Interfaces.IActiveDirectoryRepository, 
                      Admin.Repositories.ActiveDirectoryRepository>();
services.AddTransient<Admin.Interfaces.IUserRegisterService, 
                      Admin.Services.UserRegisterService>(provider =>
                          new UserRegisterService(
                              new ActiveDirectoryRepository(
                                  Configuration["ContainerDomain"])));

选项 2 是首选实施方式吗?我想避免使用第三方库进行依赖注入。我认为对于我的需要,标准方法 ASP.NET Core DI 应该足够了。

我的偏好是设置如下:

public class UserRegisterController : Controller
{
    private readonly UserManager<ApplicationUser> _userManager;
    private IUserRegisterService _userRegisterService;

    public UserRegisterController(
        UserManager<ApplicationUser> userManager,
        IOptions<WebAppSettings> settings,
        IUserRegisterService userRegisterService)
    {
        _userManager = userManager;
        _userRegisterService = userRegisterService;

    }

    //...
}

internal class UserRegisterService : IUserRegisterService
{
    private readonly IActiveDirectoryRepository _repoAd;

    public UserRegisterService(IActiveDirectoryRepository repoAd)
    {
        _repoAd = repoAd;
    }

}

internal class ActiveDirectoryRepository : IActiveDirectoryRepository
{
    private readonly string _container;

    public ActiveDirectoryRepository(IOptions<WebAppSettings> settings)
    {
        _container = settings.Value.ContainerDomain;
    }

}

public class WebAppSettings
{
    public string ContainerDomain { get; set; }

}

 public void ConfigureServices(IServiceCollection services)
    {
        services.AddOptions();
        services.Configure<WebAppSettings>(Configuration);

        // Add framework services.
        services.AddMvc();

        services.AddTransient<IActiveDirectoryRepository, ActiveDirectoryRepository>();
        services.AddTransient<IUserRegisterService, UserRegisterService>();
    }

这样,只要您解析 IUserRegisterService,您的 IUserRegisterService 就会自动注入 IActiveDirectoryService。 IActiveDirectoryService 会自动注入您的 WebAppsettings,它可以在其中获取其配置值。如果一切都像这样预先连接,那么您只需要请求将 IUserRegisterService 的实例注入到您的控制器中。

Is option 2 more preferable?

没有!我们应该使用选项 1 的 ConfigureServices,但我们会解决您遇到的问题。对于 DI,如果您发现自己试图使用 new 关键字——停下来,深呼吸并重新评估您要达到的目标。

你应该自始至终使用依赖注入,要么全有要么全无。与其让 ActiveDirectoryRepository .ctor 接受 string 作为参数,不如让它接受 IOptions<WebAppSettings> 作为参数。这是标准 ASP.NET Core 依赖注入的一部分,是首选。


让我们回顾一下您最终会得到什么...

首先,ActiveDirectoryRepository 如上所述。 _container 变量根据需要从设置中设置。

internal class ActiveDirectoryRepository : IActiveDirectoryRepository
{
    private readonly string _container;

    public ActiveDirectoryRepository(IOptions<WebAppSettings> settings)
    {
        _container = settings.Value.ContainerDomain;
    }
}

接下来,UserRegisterService 实现可以与您现在拥有的完全一样。

internal class UserRegisterService : IUserRegisterService
{
    private readonly IActiveDirectoryRepository _repoAd;

    internal UserRegisterService(IActiveDirectoryRepository repoAd)
    {
        _repoAd = repoAd;
    }
}

最后,你的UserRegisterController简化如下:

public class UserRegisterController : Controller
{
    private readonly IUserRegisterService _userRegisterService;
    private readonly UserManager<ApplicationUser> _userManager;

    public UserRegisterController(
        UserManager<ApplicationUser> userManager,
        IUserRegisterService userRegisterService)
    {
        _userManager = userManager;
        _userRegisterService = userRegisterService;    
    }
}

注意,我们不再需要这里的 IOptions<WebAppSettings> 了吗?这是一件好事,因为这些选项仅用于与此控制器无关的特定内容。