ASP.NET Core에서 ConfigureServices 내 인스턴스를 확인하는 방법


100

Startup IOptions<AppSettings>ConfigureServices메서드에서 의 인스턴스를 해결할 수 있습니까? 일반적으로 IServiceProvider인스턴스를 초기화 하는 데 사용할 수 있지만 서비스를 등록 할 때이 단계에서 사용할 수 없습니다.

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<AppSettings>(
        configuration.GetConfigurationSection(nameof(AppSettings)));

    // How can I resolve IOptions<AppSettings> here?
}

답변:


151

에 대한 BuildServiceProvider()방법을 사용하여 서비스 공급자를 구축 할 수 있습니다 IServiceCollection.

public void ConfigureService(IServiceCollection services)
{
    // Configure the services
    services.AddTransient<IFooService, FooServiceImpl>();
    services.Configure<AppSettings>(configuration.GetSection(nameof(AppSettings)));

    // Build an intermediate service provider
    var sp = services.BuildServiceProvider();

    // Resolve the services from the service provider
    var fooService = sp.GetService<IFooService>();
    var options = sp.GetService<IOptions<AppSettings>>();
}

Microsoft.Extensions.DependencyInjection이를위한 패키지 가 필요합니다 .


에서 일부 옵션을 바인딩해야하는 ConfigureServices경우 다음 Bind메서드 를 사용할 수도 있습니다 .

var appSettings = new AppSettings();
configuration.GetSection(nameof(AppSettings)).Bind(appSettings);

이 기능은 Microsoft.Extensions.Configuration.Binder패키지를 통해 사용할 수 있습니다 .


애플리케이션의 다른 부분에서이 서비스를 해결해야하는 경우 어떻게합니까? ConfigureServices ()에서 모두 완료되지 않았을까요?
Ray

1
@Ray 그런 다음 생성자 주입과 같은 기본 종속성 주입 메커니즘을 사용할 수 있습니다. 이 질문은 특히 ConfigureServices메서드 내부의 서비스 해결에 관한 것입니다.
Henk Mollema

@pcdev 그렇게 할 때 NULL을 얻은 다음 인스턴스를 해결하려고 시도합니다. 먼저 서비스를 추가해야합니다.
IngoB

@IngoB 예, 죄송합니다. 해당 댓글이 잘못되었으며 삭제해야합니다. 댓글을 작성했을 때 무슨 일이 벌어지고 있는지 제대로 이해하지 못했습니다. 이전에 업데이트 한 답변을 참조하십시오 . 좀 더 조사를했고 이제 더 잘 이해했습니다.
pcdev

14
이는 서비스를 추가하는 메서드에 구현 팩토리 오버로드가없는 경우 (예 : here ) 에서 유용 할 수 있지만 , 사용 BuildServiceProvider하면 ConfigureServices단일 서비스의 추가 복사본이 생성 되는 것과 같은 애플리케이션 코드에서 사용 하면 경고가 발생합니다. 만들어진. 여기 Ehsan Mirsaeedi의 대답 은 이와 같은 경우에 가장 이상적인 솔루션입니다.
네오

65

다른 서비스에 종속 된 클래스를 인스턴스화하는 가장 좋은 방법 은 IServiceProvider 를 제공 하는 Add XXX 오버로드를 사용하는 것입니다 . 이렇게하면 중간 서비스 공급자를 인스턴스화 할 필요가 없습니다.

다음 샘플은 AddSingleton / AddTransient 메서드 에서이 오버로드를 사용하는 방법을 보여줍니다 .

services.AddSingleton(serviceProvider =>
{
    var options = serviceProvider.GetService<IOptions<AppSettings>>();
    var foo = new Foo(options);
    return foo ;
});


services.AddTransient(serviceProvider =>
{
    var options = serviceProvider.GetService<IOptions<AppSettings>>();
    var bar = new Bar(options);
    return bar;
});

16
.Net Core 3 이상에 대해 허용되는 답변 대신이 솔루션을 사용하십시오!
Joshit

7
@Joshit 나는 이것이 모든 시나리오에서 받아 들여지는 대답에 대한 실행 가능한 대체인지 ​​확신하지 못합니다. IServiceProvider는 예를 들어 AddSingleton, AddScoped, AddTransient에 사용할 수 있습니다. 그러나이 오버로드를 제공하지 않는 다른 많은 Add 메서드 (예 : AddCors, AddAuthentication, AddAuthorization)가 있습니다.
Jpsy

1
@Jpsy 당신은 관련없는 것들을 섞습니다. AddCors, AddAuthentication 등은 다양한 기본 미들웨어를 연결하기 위해 등록 방식 아래에서 호출하는 도우미입니다. AddTransient, AddSingleton, AddScoped는 세 가지 등록입니다 (일반적으로 사용되는 세 가지 수명 포함)
Fab

모든 경우에 적용되는 것은 아닙니다. 솔루션에 대한 내 대답 을 참조하십시오 .
Ian Kemp

7

모든 버전의 ASP.NET Core에서 이를 달성하는 가장 간단하고 정확한 방법 은 IConfigureOptions<TOptions>인터페이스 를 구현하는 것 입니다. 이것은 .NET Core 1.0 이후로 존재했지만 Just Work ™를 만드는 방법에 대해 아는 사람은 거의없는 것 같습니다.

예를 들어 애플리케이션의 다른 서비스 중 하나에 종속성이있는 커스텀 모델 유효성 검사기를 추가하려고합니다. 처음에는 불가능 해 보입니다.에 IMyServiceDependency대한 액세스 권한이 없기 때문에 해결할 방법 이 없습니다 IServiceProvider.

public class MyModelValidatorProvider : IModelValidatorProvider
{
    public MyModelValidatorProvider(IMyServiceDependency dependency)
    {
        ...
    }
}

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers(options =>
    {
        options.ModelValidatorProviders.Add(new MyModelValidatorProvider(??????));
    });
}

그러나의 "마법" IConfigureOptions<TOptions>은이를 매우 쉽게 만듭니다.

public class MyMvcOptions : IConfigureOptions<MvcOptions>
{
    private IMyServiceDependency _dependency;

    public MyMvcOptions(IMyServiceDependency dependency)
        => _dependency = dependency;

    public void Configure(MvcOptions options)
    {
        options.ModelValidatorProviders.Add(new MyModelValidatorProvider(_dependency));
    }
}

public void ConfigureServices(IServiceCollection services)
{
    // or scoped, or transient
    services.AddSingleton<IConfigureOptions<MvcOptions>, MyMvcOptions>();
    services.AddControllers();
}

기본적으로 Add***(***Options)델리게이트에서 수행 한 모든 설정 ConfigureServices은 이제 IConfigureOptions<TOptions>클래스의Configure 메서드 . 그런 다음 다른 서비스를 등록 할 때와 같은 방법으로 옵션을 등록하면됩니다.

자세한 내용과 이것이 뒤에서 어떻게 작동하는지에 대한 정보 는 항상 탁월한 Andrew Locke을 소개 합니다.


1

다음과 같은 것을 찾고 있습니까? 코드에서 내 의견을 볼 수 있습니다.

// this call would new-up `AppSettings` type
services.Configure<AppSettings>(appSettings =>
{
    // bind the newed-up type with the data from the configuration section
    ConfigurationBinder.Bind(appSettings, Configuration.GetConfigurationSection(nameof(AppSettings)));

    // modify these settings if you want to
});

// your updated app settings should be available through DI now

-1

똑같은 모양이지만 Autofac을 사용할 때도 다른 사람들을 돕고 싶습니다.

ILifetimeScope (즉, 현재 범위의 컨테이너)를 얻으려면 서비스를 해결하는 데 사용할 수있는 ILifetimeScope 인스턴스를 반환 할 app.ApplicationServices.GetAutofacRoot()메서드 를 호출해야 Configure(IApplicationBuilder app)합니다.

public void Configure(IApplicationBuilder app)
    {
        //app middleware registrations 
        //...
        //

        ILifetimeScope autofacRoot = app.ApplicationServices.GetAutofacRoot();
        var repository = autofacRoot.Resolve<IRepository>();
    }

1
이 답변은 AutoFac에 너무 구체적이며이 질문의 범위에 포함되지 않습니다.
Pure.Krome

나는 autofac 접두사 로이 질문을 인터넷 검색하여 여기에 왔지만 불행히도 특정 주제를 찾지 못했습니다. 따라서이 문제로 고군분투하는이 질문에 올 사람도 답을 찾을 수 있기를 기대합니다.
단순히 좋은
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.