ASP.NET Core 6 как получить доступ к конфигурации во время установки

В более ранних версиях у нас был класс Startup.cs, и мы получали объект конфигурации, как показано ниже, в файле запуска.

      public class Startup
{
    private readonly IHostEnvironment environment;
    private readonly IConfiguration config;

    public Startup(IConfiguration configuration, IHostEnvironment environment)
    {
        this.config = configuration;
        this.environment = environment;
    }

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

    
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 
    { ... }

}

Теперь в .NET 6 (с Visual Studio 2022) мы не видим класс Startup.cs, он полностью удален. Итак, как нам получить эти объекты, такие как Configuration (IConfiguration) и Hosting Environment (IHostEnvironment)

Как нам получить эти объекты, скажем, прочитать конфигурацию из appsettngs? В настоящее время файл Program.cs выглядит так.

      using Festify.Database;
using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();

builder.Services.AddDbContext<FestifyContext>();


////////////////////////////////////////////////
// The following is Giving me error as Configuration 
// object is not avaible, I dont know how to inject this here.
////////////////////////////////////////////////


builder.Services.AddDbContext<FestifyContext>(opt =>
    opt.UseSqlServer(
        Configuration.GetConnectionString("Festify")));


var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

Я хочу прочитать конфигурацию из файла appsettings.

12 ответов

Решение

WebApplicationBuilder вернулся WebApplication.CreateBuilder(args) разоблачает а также характеристики:

      var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
...
ConfigurationManager configuration = builder.Configuration;
IWebHostEnvironment environment = builder.Environment;

WebApplication вернулся WebApplicationBuilder.Build() также обнажает Configuration а также Environment:

      var app = builder.Build();
IConfiguration configuration = app.Configuration;
IWebHostEnvironment environment = app.Environment;

Также ознакомьтесь с по руководствоммиграции и примерами кода .

В Program.cs, создается WebApplicationBuilder, как показано ниже.

      var builder = WebApplication.CreateBuilder(args);

Как только мы создадим билдер, конфигурация будет доступна.

Предположим, у вас есть значение по умолчанию. Приведенный ниже пример кода вернет настройку уровня журнала конфигурации по умолчанию из файла конфигурации JSON.

      builder.Configuration["Logging:LogLevel:Default"] // returns "Warning"

После запуска приложения вы можете получить доступ к параметрам конфигурации с помощью внедрения зависимостей в другие классы вашего приложения.

      public MyClass(IConfiguration configuration)
{
   var logLevel = configuration["Logging:LogLevel:Default"];
}

Хорошая функция, которую стоит рассмотреть, чтобы создать класс, который представляет ваши настройки, а затем привязать конфигурацию к экземпляру этого типа класса. Например, предположим, что вы создаете новый класс с именем MyAppSettingsс той же структурой, что и ваша appSettings.json, вы можете сделать следующее:

      var myAppSettings = builder.Configuration.Get<MyAppSettings>();
string logLevel = myAppSettings.Logging.LogLevel.Default;

.NET 6 уже предоставляет объект Builder в Program.cs

      var builder = WebApplication.CreateBuilder(args);

Просто используйте этот построитель для доступа к конфигурации и среде в качестве примера, чтобы получить ConnectionString из app.settings.cs следующим образом:

      builder.Services.AddDbContext<DataContext>( options =>
{
  options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnectiion"));
});

Я знаю, что вопрос изначально задаетASPNetCoreно если вам случится сделать то же самое для рабочей службы и приземлиться здесь, как я, надеюсь, этот ответ поможет вам.

Пользователь рабочей службыIHostBuilderвместоIWebApplicationBuilderи это не предоставляет свойство Configuration, но вы можете принять экземпляр IHostBuilderContext в метод ConfigureServices, который предоставляет экземпляр Configuration.

      IHost host = Host.CreateDefaultBuilder(args)
    .ConfigureServices((context, services) =>
    {
         var settings = context.Configuration.Get<Settings>();
    })
    .Build();

//.NET6 Program.cs -(для получения свойств конфигурации приложения)

      var builder = WebApplication.CreateBuilder(args);

builder.Configuration.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
builder.Configuration.AddJsonFile($"appsettings.Dev.json", optional: true);
builder.Configuration.AddEnvironmentVariables();

// projectwide instances
  public IConfiguration _configuration;
        public AccountsAPIController(IConfiguration configuration)
        {
            _configuration = configuration;
        }

// _configuration.GetConnectionString("DefaultConnection");

Это сработало для меня ---

      // Read in from JSON file
builder.Services.Configure<ConnectionKeys>(builder.Configuration.GetSection("ConnectionKeys"));

Все, что вам нужно, это добавить «строитель». перед вашей конфигурацией

Нравиться:

      builder.Services.AddDbContext<FestifyContext>(opt =>opt.UseSqlServer(builder.Configuration.GetConnectionString("Festify")));

Это немного отличается от предыдущих ответов, и я включаю это, так как просматривал что-то подобное.

В твоей Program.csвы также можете сгруппировать код в методе и вызвать его, чтобы он меньше работал или группировал похожие вещи. Я не буду помещать весь код; не буду приводить полный список usingдирективы здесь, но достаточно, чтобы продемонстрировать технику, и я пропущу некоторый код метода. Этого недостаточно или даже, возможно, слишком много для вашего решения, и вам потребуется индивидуальная настройка.

      using AutoMapper;
using MicroKnights.Log4NetHelper;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
...
//all your using directives
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;

//a variable to hold configuration
IConfiguration Configuration;

var builder = WebApplication.CreateBuilder(args);
Configuration = builder.Configuration;

// call some methods
ConfigureAuth(builder.Services);
ConfigureRedis(builder.Services);
ConfigureSession(builder.Services);
ConfigureMvc(builder.Services);
ConfigureServices(builder.Services);

var app = builder.Build();
ConfigureMiddleWare(app);
app.Run();
// we are done with the main part, now the methods

void ConfigureMvc(IServiceCollection services)
{
    builder.Services.AddMvc(config =>
    {
        var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
        config.Filters.Add(new AuthorizeFilter(policy));
    })
    .AddRazorPagesOptions(options => { options.Conventions.AddPageRoute("/Home/Login", ""); })
    .AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
        options.JsonSerializerOptions.PropertyNamingPolicy = null;
    });
}

void ConfigureSession(IServiceCollection services)
{
    builder.Services.AddSession(options =>
    {
        options.Cookie.Name = "mygreatsite_session";
        options.IdleTimeout = TimeSpan.FromMinutes(60);
    });
}

void ConfigureRedis(IServiceCollection services)
{
    var redisConfig = new RedisOptions();
    Configuration.GetSection(RedisOptions.RedisConfig).Bind(redisConfig);
    services.AddStackExchangeRedisCache(options =>
    {
        options.Configuration = redisConfig.ConnectionString;
        options.InstanceName = "mygreatsite_";
    });
    services.AddDataProtection()
        .SetApplicationName("MyGreatSite.Website")
        .PersistKeysToStackExchangeRedis(ConnectionMultiplexer.Connect(redisConfig.ConnectionString), "DataProtection-Keys");
}

void ConfigureMiddleWare(WebApplication app)
{
    if (builder.Environment.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseBrowserLink();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }

    app.UseRouting();
    app.UseCors("default");
    app.UseCookiePolicy();
    app.UseAuthentication();
    app.UseAuthorization();
    app.UseSession();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute().RequireAuthorization();
        endpoints.MapControllerRoute(
            name: "Default",
            pattern: "{controller=Home}/{action=Login}"
        );
    });
}

У меня работали следующие коды:

Программа.cs:

      var builder = WebApplication.CreateBuilder(args);
string connString = builder.Configuration.GetConnectionString("conStr");
ConnectionString = connString;

...

partial class Program
{
    public static string? ConnectionString { get; private set; }
}

calling class:
string cnStr = Program.ConnectionString;

Если вы определили токен в файле appsetting.json, вы можете определить этот токен json в программе cs следующим образом:

appsettting.json:

        "AppSettings": {
    "Token": "token"
  },

программа cs:

      var key = Encoding.ASCII.GetBytes(builder.Configuration.GetSection("Appsettings:Token").Value);

Альтернатива: действительно ли мне нужен DI, когда дело доходит до настроек?

Особенно, когда мне нужны эти настройки из переменных среды, что часто бывает в контейнерных средах, и, возможно, чтобы избежать утечки секретов в файлах json.

Тогда просто создайте статический класс, например:

      public static class SettingsService
{

    private static Settings _settings = null;

    public static Settings Settings
    {
        get
        {
            if (_settings == null)
            {
                _settings = new Settings()
                {
                    hostmail = Environment.GetEnvironmentVariable("hostmail") ?? "",
                    hostmailuser = Environment.GetEnvironmentVariable("hostmailuser") ?? "",
                    hostmailpass = Environment.GetEnvironmentVariable("hostmailpass") ?? "",
                    hostmailport = int.Parse(Environment.GetEnvironmentVariable("hostmailport") ?? "993"),
                    LogLevel = Enum.Parse<LogLevel>(Environment.GetEnvironmentVariable("LogLevel") ?? "Information"),
                    natsurl = Environment.GetEnvironmentVariable("natsurl") ?? "nats://localhost:4200",
                    natsnkeypubkey = Environment.GetEnvironmentVariable("natsnkeypubkey") ?? "",
                    natsnkeypath = Environment.GetEnvironmentVariable("natsnkeypath") ?? "",
                    roles = (Environment.GetEnvironmentVariable("roles") ?? "").Split(';'),
                    poolsize = int.Parse(Environment.GetEnvironmentVariable("poolsize") ?? "10"),
                    tmpfolder = Environment.GetEnvironmentVariable("tmpfolder") ?? "temp",
                    fontsfolder = Environment.GetEnvironmentVariable("fontsfolder") ?? "fonts"
                };

            }
            return _settings;
        }
    }
}

и файл program.cs типа:

      
var sets = SettingsService.Settings;

IHost host = Host.CreateDefaultBuilder(args).ConfigureAppSettings()
    .ConfigureServices(services =>
    {
        if (sets.serverrole == "inboxsignaler")
        {
            services.AddHostedService<InboxSignaler>();
        }
        services.AddNats(options =>
          {
              options.Url = sets.natsurl;
              options.SetNkey(sets.natsnkeypubkey, sets.natsnkeypath);
          });
    })
    .Build();

await host.RunAsync();

мои 2 цента...

Я решил эту проблему простым способом:

В Program.cs:

      using SomeAppName.Startup;

    WebApplication.CreateBuilder(args)
        .RegisterServices()
        .Build()
        .SetupMiddleware()
        .Run();

Следующий:

      public static WebApplicationBuilder RegisterServices(this WebApplicationBuilder builder)
 {
      BuildConfiguration(builder.Environment);
      //// Any code
 }

Окончательно:

      private static IConfiguration BuildConfiguration(IHostEnvironment env)
        {
            var configurationBuilder = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("./Configuration/appsettings.json", optional: false, reloadOnChange: true)
                .AddJsonFile("./Configuration/appsettings.other.json", optional: false, reloadOnChange: true)
                .AddJsonFile($"./Configuration/appsettings.{env.EnvironmentName}.json", optional: true)
                .AddJsonFile($"./Configuration/appsettings.other.{env.EnvironmentName}.json", optional: true)
                .AddEnvironmentVariables();

            Configuration = configurationBuilder.Build();
            return Configuration;
        }
Другие вопросы по тегам