.net核心注入和解析服务 [英] .net core injecting and resolving services

查看:90
本文介绍了.net核心注入和解析服务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试.net核心Web API.我创建了一个静态方法来注册我的控制器,如下所示:

public static class RegistrationExtensions
{
    public static void RegisterApplicationServices(this IServiceCollection services, IServiceProvider serviceProvider)
    {
        services.RegisterSingletons();
        services.RegisterRequests();
        services.RegisterTransient(serviceProvider);
    }

    public static void RegisterSingletons(this IServiceCollection services)
    {
        services.AddSingleton<Configuration>();
    }

    public static void RegisterRequests(this IServiceCollection services)
    {
        services.AddScoped<ISettingsService, SettingsService>();
    }

    public static void RegisterTransient(this IServiceCollection services, IServiceProvider serviceProvider)
    {
        var config = serviceProvider.GetService<Configuration>();
        services.AddDbContext<InteractiveChoicesContext>(m => m.UseSqlServer(config.ConnectionString));
    }
}

如您所见,我想解析我的 Configuration 类,其中包含我的 ConnectionString ,该类已传递到 DbContext 中. 确实要解决配置,我试图使用注入到 RegisterApplicationServices 方法中的 IServiceProvider .

要调用此方法,我将 Startup 类的 ConfigureServices 更改为此:

public void ConfigureServices(IServiceCollection services, IServiceProvider serviceProvider)
{
    services.AddMvc();
    services.RegisterApplicationServices(serviceProvider);
}

但是当我运行我的应用程序时,出现错误:

ConfigureServices方法必须为无参数,或者仅采用IServiceCollection类型的一个参数.

错误很明显.我的问题是:如何在我的 RegisterTransient 方法中解析 Configuration 类?

解决方案

实际上,AddDbContext的重载需要一个Action<IServiceProvider, DbContextOptionsBuilder>.这应该正是您要寻找的.

例如:

services.AddDbContext<InteractiveChoicesContext>((provider, options) =>
{
    var config = provider.GetService<Configuration>();
    options.UseSqlServer(config.ConnectionString);
});

我已经用v2,v3和v5对此进行了测试.包括EF Core 2.0.0中指定的有关此重载的文档,以备后代和相关性之用.

//
// Summary:
//     Registers the given context as a service in the 
//     Microsoft.Extensions.DependencyInjection.IServiceCollection.
//     You use this method when using dependency injection in your application, such
//     as with ASP.NET. For more information on setting up dependency injection, see
//     http://go.microsoft.com/fwlink/?LinkId=526890.
//     This overload has an optionsAction that provides the applications 
//     System.IServiceProvider.
//     This is useful if you want to setup Entity Framework to resolve its internal
//     services from the primary application service provider. By default, we recommend
//     using the other overload, which allows Entity Framework to create and maintain
//     its own System.IServiceProvider for internal Entity Framework services.
//
// Parameters:
//   serviceCollection:
//     The Microsoft.Extensions.DependencyInjection.IServiceCollection to add services
//     to.
//
//   optionsAction:
//     An optional action to configure the Microsoft.EntityFrameworkCore.DbContextOptions
//     for the context. This provides an alternative to performing configuration of
//     the context by overriding the Microsoft.EntityFrameworkCore.DbContext
//     .OnConfiguring(Microsoft.EntityFrameworkCore.DbContextOptionsBuilder)
//     
//     method in your derived context.
//     If an action is supplied here, the 
//     Microsoft.EntityFrameworkCore.DbContext
//     .OnConfiguring(Microsoft.EntityFrameworkCore.DbContextOptionsBuilder)
//     method will still be run if it has been overridden on the 
//     derived context. Microsoft.EntityFrameworkCore.DbContext
//     .OnConfiguring(Microsoft.EntityFrameworkCore.DbContextOptionsBuilder)
//     configuration will be applied in addition to configuration performed here.
//     In order for the options to be passed into your context, you need 
//     to expose a constructor on your context that takes 
//     Microsoft.EntityFrameworkCore.DbContextOptions`1
//     and passes it to the base constructor of 
//     Microsoft.EntityFrameworkCore.DbContext.
//
//   contextLifetime:
//     The lifetime with which to register the DbContext 
//   service in the container.
//
//   optionsLifetime:
//     The lifetime with which to register the DbContextOptions
//     service in the container.
//
// Type parameters:
//   TContext:
//     The type of context to be registered.
//
// Returns:
//     The same service collection so that multiple calls can be chained.
public static IServiceCollection AddDbContext<TContext>(
    [NotNullAttribute] this IServiceCollection serviceCollection, 
    [CanBeNullAttribute] Action<IServiceProvider, DbContextOptionsBuilder> optionsAction, 
    ServiceLifetime contextLifetime = ServiceLifetime.Scoped, 
    ServiceLifetime optionsLifetime = ServiceLifetime.Scoped
) where TContext : DbContext;

I am trying my hand at .net core web api. I have created a static method for registering my controllers like this:

public static class RegistrationExtensions
{
    public static void RegisterApplicationServices(this IServiceCollection services, IServiceProvider serviceProvider)
    {
        services.RegisterSingletons();
        services.RegisterRequests();
        services.RegisterTransient(serviceProvider);
    }

    public static void RegisterSingletons(this IServiceCollection services)
    {
        services.AddSingleton<Configuration>();
    }

    public static void RegisterRequests(this IServiceCollection services)
    {
        services.AddScoped<ISettingsService, SettingsService>();
    }

    public static void RegisterTransient(this IServiceCollection services, IServiceProvider serviceProvider)
    {
        var config = serviceProvider.GetService<Configuration>();
        services.AddDbContext<InteractiveChoicesContext>(m => m.UseSqlServer(config.ConnectionString));
    }
}

As you can see, I want to resolve my Configuration class which contains my ConnectionString, which I pass into the DbContext. Do resolve the Configuration I was trying to use IServiceProvider which is injected into the RegisterApplicationServices method.

To invoke this method, I changed the Startup class's ConfigureServices to this:

public void ConfigureServices(IServiceCollection services, IServiceProvider serviceProvider)
{
    services.AddMvc();
    services.RegisterApplicationServices(serviceProvider);
}

But when I run my application, I get an error:

The ConfigureServices method must either be parameterless or take only one parameter of type IServiceCollection.

The error is obvious. My question is: How can I resolve the Configuration class in my RegisterTransient method?

解决方案

There is actually an overload of AddDbContext that takes an Action<IServiceProvider, DbContextOptionsBuilder>. This should be exactly what you are looking for.

Ex:

services.AddDbContext<InteractiveChoicesContext>((provider, options) =>
{
    var config = provider.GetService<Configuration>();
    options.UseSqlServer(config.ConnectionString);
});

I have tested this with v2, v3, and v5. The documentation for this overload, as specified in EF Core 2.0.0 is included verbatim for posterity and relevance

//
// Summary:
//     Registers the given context as a service in the 
//     Microsoft.Extensions.DependencyInjection.IServiceCollection.
//     You use this method when using dependency injection in your application, such
//     as with ASP.NET. For more information on setting up dependency injection, see
//     http://go.microsoft.com/fwlink/?LinkId=526890.
//     This overload has an optionsAction that provides the applications 
//     System.IServiceProvider.
//     This is useful if you want to setup Entity Framework to resolve its internal
//     services from the primary application service provider. By default, we recommend
//     using the other overload, which allows Entity Framework to create and maintain
//     its own System.IServiceProvider for internal Entity Framework services.
//
// Parameters:
//   serviceCollection:
//     The Microsoft.Extensions.DependencyInjection.IServiceCollection to add services
//     to.
//
//   optionsAction:
//     An optional action to configure the Microsoft.EntityFrameworkCore.DbContextOptions
//     for the context. This provides an alternative to performing configuration of
//     the context by overriding the Microsoft.EntityFrameworkCore.DbContext
//     .OnConfiguring(Microsoft.EntityFrameworkCore.DbContextOptionsBuilder)
//     
//     method in your derived context.
//     If an action is supplied here, the 
//     Microsoft.EntityFrameworkCore.DbContext
//     .OnConfiguring(Microsoft.EntityFrameworkCore.DbContextOptionsBuilder)
//     method will still be run if it has been overridden on the 
//     derived context. Microsoft.EntityFrameworkCore.DbContext
//     .OnConfiguring(Microsoft.EntityFrameworkCore.DbContextOptionsBuilder)
//     configuration will be applied in addition to configuration performed here.
//     In order for the options to be passed into your context, you need 
//     to expose a constructor on your context that takes 
//     Microsoft.EntityFrameworkCore.DbContextOptions`1
//     and passes it to the base constructor of 
//     Microsoft.EntityFrameworkCore.DbContext.
//
//   contextLifetime:
//     The lifetime with which to register the DbContext 
//   service in the container.
//
//   optionsLifetime:
//     The lifetime with which to register the DbContextOptions
//     service in the container.
//
// Type parameters:
//   TContext:
//     The type of context to be registered.
//
// Returns:
//     The same service collection so that multiple calls can be chained.
public static IServiceCollection AddDbContext<TContext>(
    [NotNullAttribute] this IServiceCollection serviceCollection, 
    [CanBeNullAttribute] Action<IServiceProvider, DbContextOptionsBuilder> optionsAction, 
    ServiceLifetime contextLifetime = ServiceLifetime.Scoped, 
    ServiceLifetime optionsLifetime = ServiceLifetime.Scoped
) where TContext : DbContext;

这篇关于.net核心注入和解析服务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆