web-dev-qa-db-fra.com

ASP.Net Core MVC Dependency Injection ne fonctionne pas

J'essaie d'injecter une interface dans mon HomeController et j'obtiens cette erreur:

InvalidOperationException: impossible de résoudre le service pour le type "Microsoft.Extensions.Configuration.IConfiguration" lors de la tentative d'activation

Ma classe de démarrage est la suivante:

public Startup(IApplicationEnvironment appEnv)
{
    var builder = new ConfigurationBuilder()
        .SetBasePath(appEnv.ApplicationBasePath)
        .AddEnvironmentVariables()
        .AddJsonFile("appsettings.json");
    Configuration = builder.Build();
}

public IConfigurationRoot Configuration { get; set; }

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

    services.AddEntityFramework()
        .AddSqlServer()
        .AddDbContext<ApplicationDbContext>(options => options
            .UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));

    services.AddIdentity<ApplicationUser, IdentityRole>()
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddDefaultTokenProviders();

    services.AddMvc();
    services.AddSingleton(provider => Configuration);

    // Add application services.
    services.AddTransient<IEmailSender, AuthMessageSender>();
    services.AddTransient<ISmsSender, AuthMessageSender>();
}

public void Configure(
    IApplicationBuilder app, 
    IHostingEnvironment env, 
    ILoggerFactory loggerFactory)
{
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();

    app.UseApplicationInsightsRequestTelemetry();

    if (env.IsDevelopment())
    {
        app.UseBrowserLink();
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");

        try
        {
            using (var serviceScope = app.ApplicationServices
                .GetRequiredService<IServiceScopeFactory>()
                .CreateScope())
            {
                serviceScope.ServiceProvider
                        .GetService<ApplicationDbContext>()
                        .Database.Migrate();
            }
        }
        catch { }
    }

    app.UseIISPlatformHandler(options => options.AuthenticationDescriptions.Clear());

    app.UseApplicationInsightsExceptionTelemetry();
    app.UseStaticFiles();
    app.UseIdentity();

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });

    app.Run((async (context) =>
    {
        await context.Response.WriteAsync("Error");
    }));
}

et mon constructeur HomeController est:

public HomeController(IConfiguration configuration, IEmailSender mailService)
{
    _mailService = mailService;
    _to = configuration["emailAddress.Support"];
}

Veuillez me dire où je me trompe.

Microsoft.Extensions.DependencyInjection.ServiceLookup.Service.PopulateCallSites (fournisseur ServiceProvider, ISet`1 callSiteChain, paramètres ParameterInfo [], paramètres booléens throwIfCallSiteNotFound)

20
JamTay317

Essayez de l'injecter en tant que IConfigurationRoot au lieu de IConfiguration:

 public HomeController(IConfigurationRoot configuration
    , IEmailSender mailService)
{
    _mailService = mailService;
    _to = configuration["emailAddress.Support"];
}

Dans ce cas, la ligne

services.AddSingleton(provider => Configuration);

est équivalent à

services.AddSingleton<IConfigurationRoot>(provider => Configuration);

car la propriété Configuration sur la classe est déclarée comme telle, et l'injection se fera en faisant correspondre le type sous lequel elle a été enregistrée. Nous pouvons reproduire cela assez facilement, ce qui pourrait le rendre plus clair:

public interface IParent { }

public interface IChild : IParent { }

public class ConfigurationTester : IChild { }
public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddMvc();

    IChild example = new ConfigurationTester();
    services.AddSingleton(provider => example);
}
public class HomeController : Controller
{
    public HomeController(IParent configuration)
    {
        // this will blow up
    }
}

Toutefois

Comme stephen.vakil l'a mentionné dans les commentaires, il serait préférable de charger votre fichier de configuration dans une classe, puis d'injecter cette classe dans les contrôleurs si nécessaire. Cela ressemblerait à quelque chose comme ceci:

services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));

Vous pouvez récupérer ces configurations avec l'interface IOptions:

public HomeController(IOptions<AppSettings> appSettings)
32
Will Ray

Dans Core 2.0, il est recommandé d'utiliser IConfiguration au lieu de IConfigurationRoot

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

public IConfiguration Configuration { get; }

de https://docs.Microsoft.com/en-us/aspnet/core/migration/1x-to-2x/#add-configuration-providers

9
Michael Freidgeim

Lorsque vous déplacez un projet de .Net Core 1.x vers 2.0, changez tout IConfigurationRoot en IConfiguration

2
Christian Esqueda