我如何手动解析一个类型使用ASP。NET核心MVC内置依赖注入框架?

设置容器非常简单:

public void ConfigureServices(IServiceCollection services)
{
    // ...

    services.AddTransient<ISomeService, SomeConcreteService>();
}

但是如何在不执行注入的情况下解析ISomeService呢?例如,我想这样做:

ISomeService service = services.Resolve<ISomeService>();

在IServiceCollection中没有这样的方法。


当前回答

您可以使用IApplicationBuilder实例以这种方式注入依赖项

public void Configure(IApplicationBuilder app)
{
    //---------- Your code

    using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
    {
        var resultLogic = serviceScope.ServiceProvider.GetService<IResultLogic>();
        resultLogic.YourMethod();
    }

    //---------- Your code
}

其他回答

您可以使用IApplicationBuilder实例以这种方式注入依赖项

public void Configure(IApplicationBuilder app)
{
    //---------- Your code

    using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
    {
        var resultLogic = serviceScope.ServiceProvider.GetService<IResultLogic>();
        resultLogic.YourMethod();
    }

    //---------- Your code
}

您可以通过这种方式在诸如AuthorizeAttribute之类的属性中注入依赖项

var someservice = (ISomeService)context.HttpContext.RequestServices.GetService(typeof(ISomeService));
public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<ISelfServiceConfigLoad, SelfServiceConfigLoader>();
    var sp = services.BuildServiceProvider();
    var configservice = sp.GetServices<ISelfServiceConfigLoad>();
    services.AddSingleton<IExtractor, ConfigExtractor>( sp =>
    {
        var con = sp.GetRequiredService<ISelfServiceConfigLoad>();
        var config = con.Load();
        return new ConfigExtractor(config.Result);
    });
    services.AddSingleton<IProcessor<EventMessage>, SelfServiceProcessor>();          
    services.AddTransient<ISolrPush, SolrDataPush>();
    services.AddSingleton<IAPICaller<string, string>, ApiRestCaller<string, string>>();
    services.AddSingleton<IDataRetriever<SelfServiceApiRequest, IDictionary<string, object>>, SelfServiceDataRetriever>();
}
public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    services.AddDbContext<ConfigurationRepository>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("SqlConnectionString")));

    services.AddScoped<IConfigurationBL, ConfigurationBL>();
    services.AddScoped<IConfigurationRepository, ConfigurationRepository>();
}

我知道这是一个老问题,但我很惊讶,一个相当明显和恶心的黑客没有在这里。

您可以利用定义自己的ctor函数的能力,在定义服务时从服务中获取必要的值……显然,每次请求服务时都会运行此服务,除非您在利用ctor的第一个构造中显式地删除/清除并重新添加此服务的定义。

这种方法的优点是不需要您在服务配置期间构建或使用服务树。您仍然在定义如何配置服务。

public void ConfigureServices(IServiceCollection services)
{
    //Prey this doesn't get GC'd or promote to a static class var
    string? somevalue = null;

    services.AddSingleton<IServiceINeedToUse, ServiceINeedToUse>(scope => {
         //create service you need
         var service = new ServiceINeedToUse(scope.GetService<IDependantService>())
         //get the values you need
         somevalue = somevalue ?? service.MyDirtyHack();
         //return the instance
         return service;
    });
    services.AddTransient<IOtherService, OtherService>(scope => {
         //Explicitly ensuring the ctor function above is called, and also showcasing why this is an anti-pattern.
         scope.GetService<IServiceINeedToUse>();
         //TODO: Clean up both the IServiceINeedToUse and IOtherService configuration here, then somehow rebuild the service tree.
         //Wow!
         return new OtherService(somevalue);
    });
}

修复这个模式的方法是让OtherService显式依赖于IServiceINeedToUse,而不是隐式依赖于它或它的方法的返回值…或者以其他方式显式地解决依赖关系。