ASP.NET Core'da ConfigureServices İçinde Örnek Çözümleme


116

Bunun bir örneğini çözmek mümkün mü IOptions<AppSettings>dan ConfigureServicesdevreye alma yöntemiyle? Normalde IServiceProviderörnekleri başlatmak için kullanabilirsiniz , ancak hizmetleri kaydederken bu aşamada buna sahip değilsiniz.

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

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

Yanıtlar:


166

Aşağıdaki BuildServiceProvider()yöntemi kullanarak bir servis sağlayıcı oluşturabilirsiniz 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>>();
}

Bunun için Microsoft.Extensions.DependencyInjectionpakete ihtiyacınız var .


Yalnızca bazı seçenekleri bağlamanız gerektiğinde ConfigureServices, Bindyöntemi de kullanabilirsiniz :

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

Bu işlevsellik Microsoft.Extensions.Configuration.Binderpakette mevcuttur .


Ya bu hizmeti uygulamanın başka bir bölümünde çözmeniz gerekirse? Eminim hepsi ConfigureServices () içinde yapılmamaktadır, değil mi?
Ray

2
@Ray sonra yapıcı enjeksiyonu gibi varsayılan bağımlılık enjeksiyon mekanizmalarını kullanabilirsiniz. Bu soru özellikle ConfigureServicesyöntem içindeki hizmetlerin çözümlenmesi ile ilgilidir .
Henk Mollema

@pcdev Bunu yaptığınızda NULL alırsınız ve ardından örneği çözmeye çalışırsınız. Önce hizmeti eklemelisiniz.
IngoB

17
Bu, bir hizmeti ekleme yönteminin bir uygulama fabrikası aşırı yüklemesine sahip olmadığı durumlarda (örn., Burada ) faydalı olabilirken, BuildServiceProvideruygulama kodunda kullanıldığında ConfigureServices, tekli hizmetlerin ek bir kopyasının oluşmasına neden olduğu gibi bir uyarıya neden olur. oluşturuldu. Ehsan Mirsaeedi'nin buradaki cevabı , bu gibi durumlar için en ideal çözümdür.
Neo

1
Bu cevap, sanki herhangi bir singleton kaydı varmış gibi yanlıştır, birkaç kez singleton oluşturulmasına neden olabilir. @ ehsan-mirsaeedi cevabı daha iyidir ve kabul edilen cevap olmalıdır.
Fab

78

Diğer hizmetlere bağlı sınıfları başlatmanın en iyi yolu , size IServiceProvider'ı sağlayan Add XXX aşırı yüklemesini kullanmaktır . Bu şekilde, bir ara hizmet sağlayıcısının örneğini oluşturmanıza gerek kalmaz.

Aşağıdaki örnekler, bu aşırı yüklemeyi AddSingleton / AddTransient yöntemlerinde nasıl kullanabileceğinizi gösterir .

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;
});

20
Net Core 3 veya üstü için kabul edilen cevap yerine bu çözümü kullanın!
Joshit

12
@Joshit Bunun tüm senaryolarda kabul edilen cevap için uygun bir yedek olduğundan pek emin değilim. IServiceProvider, yani AddSingleton, AddScoped, AddTransient için kullanılabilir. Ancak bu aşırı yüklemeyi sağlamayan başka birçok Add yöntemi vardır, örneğin AddCors, AddAuthentication, AddAuthorization.
Jpsy

1
@Jpsy Sen ilgisiz şeyleri karıştırıyorsun. AddCors, AddAuthentication ve benzerleri, çeşitli temel ara yazılımları bağlamak için kayıt yöntemlerinin altında çağrı yapan yardımcılardır. AddTransient, AddSingleton, AddScoped üç kayıttır (yaygın olarak kullanılan üç yaşam süresiyle)
Fab

Bu tüm durumları kapsamaz. Bakınız Cevabıma yapan bir çözüm.
Ian Kemp

13

ASP.NET Core'un tüm sürümlerinde bunu başarmanın en basit ve en doğru yolu IConfigureOptions<TOptions>arabirimi uygulamaktır . Bu, .NET Core 1.0'dan beri var olmasına rağmen, pek az kişinin bunun işleri nasıl Just Work ™ yaptığını bildiği görülüyor .

Örnek olarak, uygulamanızın diğer hizmetlerinden birine bağımlı olan özel bir model doğrulayıcı eklemek istiyorsunuz. Başlangıçta imkansız görünüyor - çözmenin bir yolu yok IMyServiceDependencyçünkü şunlara erişiminiz yok IServiceProvider:

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

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

Ama "büyüsü" IConfigureOptions<TOptions>bunu çok kolaylaştırıyor:

public class ConfigureMvcOptions : 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)
{
    services.AddControllers();

    ...

    // or scoped, or transient, as necessary for your service
    services.AddSingleton<IConfigureOptions<MvcOptions>, ConfigureMvcOptions>();
}

Esasen, Add***(***Options)temsilcilerde yapacağınız herhangi bir kurulum ConfigureServicesartık IConfigureOptions<TOptions>sınıfınızınConfigure yöntemine . Daha sonra, diğer herhangi bir hizmeti kaydettiğiniz gibi seçenekleri de kaydedersiniz ve gidin!

Daha fazla ayrıntı ve bunun perde arkasında nasıl çalıştığı hakkında bilgi için sizi her zaman mükemmel olan Andrew Lock'a yönlendiriyorum .


Ya diğer kitaplığın uzantı yöntemlerini çağırırken okumak için yalnızca bir yapılandırma nesnesine ihtiyacınız varsa? Diğer hizmetleri kaydederken sağladığınız değerleri bilgilendirmek için yapılandırmayı oluşturmanın / çözümlemenin herhangi bir yolu var mı?
Alexander Trauzzi

@AlexanderTrauzzi IConfiguration'ı ConfigureServices'e aktarır - IOC bunu sağlayacaktır.
Chazt3n

Bir uzantı yönteminde olacağı düşünülürse, bir kütüphane yazarı olarak bunun etrafında herhangi bir yol var mı?
Alexander Trauzzi

@AlexanderTrauzzi Neyi başarmaya çalıştığınızı detaylandıran bir soru sormanızı öneririm.
Ian Kemp

1

Aşağıdaki gibi bir şey mi arıyorsunuz? Koddaki yorumlarıma bakabilirsiniz:

// 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

Aynı şeye bakan ancak Autofac kullanırken de yardım etmek ister.

ILifetimeScope'u (yani mevcut kapsamın kapsayıcısı) almak istiyorsanız app.ApplicationServices.GetAutofacRoot(), Configure(IApplicationBuilder app)bu şekilde yöntemi çağırmanız gerekir, hizmetleri çözmek için kullanabileceğiniz ILifetimeScope örneğini döndürür.

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

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

2
Bu yanıt, bu sorunun kapsamında olmayan AutoFac'e çok özeldir.
Pure.Krome

Buraya bu soruyu autofac öneki ile araştırarak geldim ve maalesef belirli bir konu bulamadım. Bu nedenle, bu sorunla mücadele ederek bu soruya gelecek olanların da bir cevap bulmasını bekliyorum.
basitçe iyi
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.