在ConfigureServices中注入依赖项

时间:2017-09-26 14:44:05

标签: c# asp.net-mvc dependency-injection asp.net-core asp.net-core-2.0

在我的ASP.Net Core应用程序中,我需要在ConfigureServices方法中注入一些依赖项(在我的例子中是一个存储库)。

问题是该方法不允许使用多个参数来注入依赖项。该怎么办?

这是我的代码

public void ConfigureServices(IServiceCollection services)
{
    services.AddOptions();

    // ... 
    services.AddSingleton<ITableRepositories, TableClientOperationsService>();

    // Add framework services.
    services.AddOpenIdConnect(options =>
    {
        // options.ClientId = ...
        options.Events = new OpenIdConnectEvents
        {
            OnTicketReceived = async context =>
            {
                var user = (ClaimsIdentity)context.Principal.Identity;
                if (user.IsAuthenticated)
                {
                    // ... 
                    // vvv 
                    // HERE, I need the ITableRepositories repository; 
                    // vvv
                    var myUser = await repository.GetAsync<Connection>(userId);
                    // ... 
                }
                return;
            }
        };
    });
}

如何在此处注入依赖项?

编辑:

遵循克里斯的想法(吼叫),这似乎有效:

public class Startup
{
    // private repository, used in ConfigureServices, initialized in Startup
    ITableRepositories repository;

    public Startup(IHostingEnvironment env)
    {
        var builder = new ConfigurationBuilder()
        // ... etc etc
        Configuration = builder.Build();

        // init repository here
        this.repository = new TableClientOperationsService();
    }

2 个答案:

答案 0 :(得分:7)

您可以通过当前上下文的HttpContext.RequestServices访问服务容器。

public void ConfigureServices(IServiceCollection services) {
    services.AddOptions();

    // ... 
    services.AddSingleton<ITableRepositories, TableClientOperationsService>();

    // Add framework services.
    services.AddOpenIdConnect(options => {
        // options.ClientId = ...
        options.Events = new OpenIdConnectEvents {
            OnTicketReceived = async context => {
                var user = (ClaimsIdentity)context.Principal.Identity;
                if (user.IsAuthenticated) {
                    // ... 

                    // get the ITableRepositories repository
                    var repository = context.HttpContext.RequestServices.GetService<ITableRepositories>();
                    var myUser = await repository.GetAsync<Connection>(userId);

                    // ... 
                }
                return;
            }
        };
    });
}

从技术上讲,您不需要访问ConfigureServices中的依赖项,因为内联表达式可以被提取到自己的函数中。

public void ConfigureServices(IServiceCollection services) {
    services.AddOptions();

    // ... 
    services.AddSingleton<ITableRepositories, TableClientOperationsService>();

    // Add framework services.
    services.AddOpenIdConnect(options => {
        // options.ClientId = ...
        options.Events = new OpenIdConnectEvents {
            OnTicketReceived = TicketReceived
        };
    });
}

private async Task TicketReceived(TicketReceivedContext context) {
    var user = (ClaimsIdentity)context.Principal.Identity;
    if (user.IsAuthenticated) {
        // ... 

        // get the ITableRepositories repository
        var repository = context.HttpContext.RequestServices.GetService<ITableRepositories>();
        var myUser = await repository.GetAsync<Connection>(userId);

        // ... 
    }
    return;
}

答案 1 :(得分:1)

嗯,你不能。但是,您可以使用StartUp构造函数来设置可在ConfigureServices中使用的一个或多个属性。例如:

public StartUp(IHostingEnvironment env)
{
    ...

    FooInstance = new Foo();
}

public IFoo FooInstance { get; }

public void ConfigureServices(IServiceCollection services)
{
    // you can now use `Foo` here, without injecting it.
}

编辑(基于添加到问题的代码)

在这个特定的场景中,特别是因为这是一个单例,你可以简单地手动创建一个实例,然后绑定到该实例而不是泛型类型。例如:

var repository = new TableClientOperationsService();
services.AddSingleton<ITableRepositories>(repository);

然后,您可以直接在下面的代码中直接使用此变量:

var myUser = await repository.GetAsync<Connection>(userId);