ASP.Net Core MVC Injection не работает

Я пытаюсь ввести интерфейс в свой HomeController, и я получаю эту ошибку.

InvalidOperationException: не удается разрешить службу для типа "Microsoft.Extensions.Configuration.IConfiguration" при попытке активировать

Мой начальный файл выглядит следующим образом

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

    public IConfigurationRoot Configuration { get; set; }

    // This method gets called by the runtime. Use this method to add services to the container.
    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>();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    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");

            // For more details on creating database during deployment see http://go.microsoft.com/fwlink/?LinkID=615859
            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();

        // To configure external authentication please see http://go.microsoft.com/fwlink/?LinkID=532715

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

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

и конструктор моего домашнего контроллера:

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

скажите, пожалуйста, где я ошибаюсь.

Microsoft.Extensions.DependencyInjection.ServiceLookup.Service.PopulateCallSites(поставщик ServiceProvider, ISet`1 callSiteChain, ParameterInfo [], Boolean throwIfCallSiteNotFound)

Ответ 1

Попробуйте ввести его как IConfigurationRoot вместо IConfiguration:

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

В этом случае линия

services.AddSingleton(provider => Configuration);

эквивалентно

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

потому что свойство Configuration в классе объявляется как таковое, и инъекция будет выполняться путем сопоставления любого типа, который был зарегистрирован как. Мы можем воспроизвести это довольно легко, что может сделать его более ясным:

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

Однако

Как указано в комментариях stephen.vakil, было бы лучше загрузить файл конфигурации в класс, а затем при необходимости добавить этот класс в контроллеры. Это будет выглядеть примерно так:

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

Вы можете захватить эти конфигурации с помощью интерфейса IOptions:

public HomeController(IOptions<AppSettings> appSettings)

Ответ 3

При перемещении проекта из .Net Core 1.x в 2.0 измените все IConfigurationRoot на IConfiguration