c# - services - Risoluzione di istanze con ASP.NET Core DI




register services.net core (4)

In questo modo è possibile iniettare dipendenze in attributi come AuthorizeAttribute

var someservice = (ISomeService)context.HttpContext.RequestServices.GetService(typeof(ISomeService));

Come risolvere manualmente un tipo utilizzando il framework di iniezione delle dipendenze integrato ASP.NET Core MVC?

La configurazione del contenitore è abbastanza semplice:

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

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

Ma come posso risolvere ISomeService senza eseguire l'iniezione? Ad esempio, voglio fare questo:

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

Non esistono tali metodi in IServiceCollection .


L'interfaccia IServiceCollection viene utilizzata per la creazione di un contenitore di iniezione delle dipendenze. Una volta completata, viene composta in un'istanza IServiceProvider che è possibile utilizzare per risolvere i servizi. È possibile iniettare un IServiceProvider in qualsiasi classe. Le classi IApplicationBuilder e HttpContext possono fornire anche il fornitore di servizi, rispettivamente tramite le proprietà ApplicationServices o RequestServices .

IServiceProvider definisce un GetService(Type type) per risolvere un servizio:

var service = (IFooService)serviceProvider.GetService(typeof(IFooService));

Esistono anche diversi metodi di estensione della convenienza, come serviceProvider.GetService<IFooService>() (aggiungi un using per Microsoft.Extensions.DependencyInjection ).

Risoluzione dei servizi all'interno della classe di avvio

Iniezione di dipendenze

Il runtime può iniettare servizi nel costruttore della classe Startup , come IHostingEnvironment , IConfiguration e IServiceProvider . Si noti che questo fornitore di servizi è un'istanza creata dal livello di hosting e contiene solo i servizi per l'avvio di un'applicazione.

I servizi possono anche essere iniettati nel metodo Configure() . È possibile aggiungere un elenco arbitrario di parametri dopo il parametro IApplicationBuilder . Puoi anche iniettare i tuoi servizi che sono registrati nel metodo ConfigureServices() qui, saranno risolti dal fornitore di servizi applicativi piuttosto che dal fornitore di servizi di hosting .

public void Configure(IApplicationBuilder app, IFooService fooService)
{
   // ...
}

Il metodo ConfigureServices() tuttavia non consente l'iniezione di servizi, accetta solo un argomento IServiceCollection . Questo è il metodo in cui si configura il contenitore di iniezione della dipendenza dell'applicazione. Qui puoi usare i servizi iniettati nel costruttore della startup. Per esempio:

public Startup(IConfiguration configuration)
{
    Configuration = configuration;
}

public IConfiguration Configuration { get; }

public void ConfigureServices(IServiceCollection services)
{
    // Use Configuration here
}

Risolvere dipendenze manualmente

Se si desidera risolvere manualmente i servizi, è possibile consentire al runtime di iniettare un'istanza IServiceProvider nel costruttore o utilizzare ApplicationServices forniti da IApplicationBuilder nel metodo Configure() :

public Startup(IServiceProvider serviceProvider)
{
    var hostingEnv = serviceProvider.GetService<IHostingEnvironment>();
}

o

public void Configure(IApplicationBuilder app)
{
    var serviceProvider = app.ApplicationServices;
    var hostingEnv = serviceProvider.GetService<IHostingEnvironment>();
}

Tuttavia, se è necessario risolvere i servizi nel metodo ConfigureServices() , è necessario un approccio diverso. È possibile creare un IServiceProvider intermedio da un'istanza IServiceCollection che contiene i servizi registrati fino ad allora:

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<IFooService, FooService>();

    // Build the intermediate service provider
    var sp = services.BuildServiceProvider();
    var fooService = sp.GetService<IFooService>();
}

Per questo è necessario il pacchetto Microsoft.Extensions.DependencyInjection .

Notare che:
Generalmente non dovresti risolvere i servizi all'interno del metodo ConfigureServices() , poiché in realtà questo è il luogo in cui stai configurando i servizi dell'applicazione. A volte hai solo bisogno di accedere ad alcune IOptions<MyOptions> . È possibile ottenere ciò vincolando i valori IConfiguration a un'istanza di MyOptions (che è essenzialmente ciò che fa il framework delle opzioni):

public void ConfigureServices(IServiceCollection services)
{
    var myOptions = new MyOptions();
    Configuration.GetSection("SomeSection").Bind(myOptions);
}

I servizi di risoluzione manuale (aka Service Locator) in generale sono noti come anti-pattern . Sebbene abbia i suoi casi d'uso (per framework e / o livelli di infrastruttura), dovresti evitarlo il più possibile.


Se generi un'applicazione con un modello avrai qualcosa del genere nella classe Startup :

public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddApplicationInsightsTelemetry(Configuration);

    services.AddMvc();
}

È quindi possibile aggiungere dipendenze lì, ad esempio:

services.AddTransient<ITestService, TestService>();

Se vuoi accedere a ITestService sul tuo controller puoi aggiungere IServiceProvider sul costruttore e verrà iniettato:

public HomeController(IServiceProvider serviceProvider)

Quindi puoi risolvere il servizio che hai aggiunto:

var service = serviceProvider.GetService<ITestService>();

Nota che per usare la versione generica devi includere lo spazio dei nomi con le estensioni:

using Microsoft.Extensions.DependencyInjection;

ITestService.cs

public interface ITestService
{
    int GenerateRandom();
}

TestService.cs

public class TestService : ITestService
{
    public int GenerateRandom()
    {
        return 4;
    }
}

Startup.cs (ConfigureServices)

public void ConfigureServices(IServiceCollection services)
{
    services.AddApplicationInsightsTelemetry(Configuration);
    services.AddMvc();

    services.AddTransient<ITestService, TestService>();
}

HomeController.cs

using Microsoft.Extensions.DependencyInjection;

namespace Core.Controllers
{
    public class HomeController : Controller
    {
        public HomeController(IServiceProvider serviceProvider)
        {
            var service = serviceProvider.GetService<ITestService>();
            int rnd = service.GenerateRandom();
        }

Se hai solo bisogno di risolvere una dipendenza allo scopo di passarla al costruttore di un'altra dipendenza che stai registrando, puoi farlo.

Supponiamo che tu abbia un servizio che include una stringa e un ISomeService.

public class AnotherService : IAnotherService
{
    public AnotherService(ISomeService someService, string serviceUrl)
    {
        ...
    }
}

Quando vai a registrarlo in Startup.cs, dovrai farlo:

services.AddScoped<IAnotherService>(ctx => 
      new AnotherService(ctx.GetService<ISomeService>(), "https://someservice.com/")
);




asp.net-core-mvc