asp.net core 프로필 로드 과정 에 대한 깊이 있 는 이해

14295 단어 core프로필로드
머리말
설정 파일 에서 프로그램 이 실 행 될 때 없어 서 는 안 되 거나 없어 서 는 안 되 는 역할 을 합 니 다.일반적으로 visual studio 를 사용 하여 프로젝트 를 만 드 는 과정 에서 프로젝트 프로필 은 프로젝트 루트 디 렉 터 리 에 자동 으로 생 성 됩 니 다.예 를 들 어 apptsettings.json 또는 널리 사용 되 는appsettings.{env.EnvironmentName}.json;프로필 입 니 다.
입구 로 서 코드 를 업데이트 하지 않 는 상황 에서 프로그램 에 관여 하고 조정 할 수 있 습 니 다.그러면 로 딩 과정 에 대한 전면적 인 이해 가 필요 합 니 다.
기본 프로필 을 언제 불 러 왔 습 니까?
Program.cs 파일 에서 다음 코드 를 보십시오.

 public class Program
 {
  public static void Main(string[] args)
  {
   CreateWebHostBuilder(args).Build().Run();
  }

  public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
   WebHost.CreateDefaultBuilder(args)
    .UseStartup<Startup>();
 }
WebHost.CreateDefaultBuilder프로그램 집합Microsoft.AspNetCore.dll 에 있 습 니 다.프로그램 이 실 행 될 때WebHost.CreateDefaultBuilder(args) Create Default Builder 방법 내부 에 기본 설정 파일 을 불 러 왔 습 니 다.
코드 는 다음 과 같다.

public static IWebHostBuilder CreateDefaultBuilder(string[] args)
  {
   var builder = new WebHostBuilder();

   if (string.IsNullOrEmpty(builder.GetSetting(WebHostDefaults.ContentRootKey)))
   {
    builder.UseContentRoot(Directory.GetCurrentDirectory());
   }
   if (args != null)
   {
    builder.UseConfiguration(new ConfigurationBuilder().AddCommandLine(args).Build());
   }

   builder.UseKestrel((builderContext, options) =>
    {
     options.Configure(builderContext.Configuration.GetSection("Kestrel"));
    })
    .ConfigureAppConfiguration((hostingContext, config) =>
    {
     var env = hostingContext.HostingEnvironment;

     config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
       .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);

     if (env.IsDevelopment())
     {
      var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
      if (appAssembly != null)
      {
       config.AddUserSecrets(appAssembly, optional: true);
      }
     }

     config.AddEnvironmentVariables();

     if (args != null)
     {
      config.AddCommandLine(args);
     }
    })
    .ConfigureLogging((hostingContext, logging) =>
    {
     logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
     logging.AddConsole();
     logging.AddDebug();
     logging.AddEventSourceLogger();
    })
    .ConfigureServices((hostingContext, services) =>
    {
     // Fallback
     services.PostConfigure<HostFilteringOptions>(options =>
     {
      if (options.AllowedHosts == null || options.AllowedHosts.Count == 0)
      {
       // "AllowedHosts": "localhost;127.0.0.1;[::1]"
       var hosts = hostingContext.Configuration["AllowedHosts"]?.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
       // Fall back to "*" to disable.
       options.AllowedHosts = (hosts?.Length > 0 ? hosts : new[] { "*" });
      }
     });
     // Change notification
     services.AddSingleton<IOptionsChangeTokenSource<HostFilteringOptions>>(
      new ConfigurationChangeTokenSource<HostFilteringOptions>(hostingContext.Configuration));

     services.AddTransient<IStartupFilter, HostFilteringStartupFilter>();
    })
    .UseIIS()
    .UseIISIntegration()
    .UseDefaultServiceProvider((context, options) =>
    {
     options.ValidateScopes = context.HostingEnvironment.IsDevelopment();
    });

   return builder;
  }
이 를 통 해 알 수 있 듯 이 Create Default Builder 내부 에 서 는 IConfigurationBuilder 를 사 용 했 고 기본 설정 파일 의 이름 을 적 었 습 니 다.

public static IWebHostBuilder CreateDefaultBuilder(string[] args)
  {
   var builder = new WebHostBuilder();

   if (string.IsNullOrEmpty(builder.GetSetting(WebHostDefaults.ContentRootKey)))
   {
    builder.UseContentRoot(Directory.GetCurrentDirectory());
   }
   if (args != null)
   {
    builder.UseConfiguration(new ConfigurationBuilder().AddCommandLine(args).Build());
   }

   builder.UseKestrel((builderContext, options) =>
    {
     options.Configure(builderContext.Configuration.GetSection("Kestrel"));
    })
    .ConfigureAppConfiguration((hostingContext, config) =>
    {
     var env = hostingContext.HostingEnvironment;

     config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
       .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);

     if (env.IsDevelopment())
     {
      var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
      if (appAssembly != null)
      {
       config.AddUserSecrets(appAssembly, optional: true);
      }
     }

     config.AddEnvironmentVariables();

     if (args != null)
     {
      config.AddCommandLine(args);
     }
    })
    .ConfigureLogging((hostingContext, logging) =>
    {
     logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
     logging.AddConsole();
     logging.AddDebug();
     logging.AddEventSourceLogger();
    })
    .ConfigureServices((hostingContext, services) =>
    {
     // Fallback
     services.PostConfigure<HostFilteringOptions>(options =>
     {
      if (options.AllowedHosts == null || options.AllowedHosts.Count == 0)
      {
       // "AllowedHosts": "localhost;127.0.0.1;[::1]"
       var hosts = hostingContext.Configuration["AllowedHosts"]?.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
       // Fall back to "*" to disable.
       options.AllowedHosts = (hosts?.Length > 0 ? hosts : new[] { "*" });
      }
     });
     // Change notification
     services.AddSingleton<IOptionsChangeTokenSource<HostFilteringOptions>>(
      new ConfigurationChangeTokenSource<HostFilteringOptions>(hostingContext.Configuration));

     services.AddTransient<IStartupFilter, HostFilteringStartupFilter>();
    })
    .UseIIS()
    .UseIISIntegration()
    .UseDefaultServiceProvider((context, options) =>
    {
     options.ValidateScopes = context.HostingEnvironment.IsDevelopment();
    });

   return builder;
  }
상기 코드 때문에,우 리 는 응용 프로그램 루트 디 렉 터 리 에서appsettings.json appsettings.{env.EnvironmentName}.json 이런 형식의 기본 프로필 이름 을 사용 할 수 있 습 니 다
또한,Main 방법 으로 기본 설정 파일 을 Build 방법 으로 호출 하 였 습 니 다.

 public static void Main(string[] args)
  {
   CreateWebHostBuilder(args).Build().Run();
  }
Startup.cs 에서 주 입 된 방식 으로 기본 설정 파일 대상 IConfigurationRoot/IConfiguration,코드 세 션 을 얻 을 수 있 습 니 다.

 public class Startup
 {
  public Startup(IConfiguration configuration)
  {
   Configuration = configuration;
  }
빌 드 방법 을 실행 할 때 방법 내부 에 기본 설정 파일 대상 을 ServiceCollection,코드 세 션 에 추가 하 였 기 때 문 입 니 다.

 var services = new ServiceCollection();
 services.AddSingleton(_options);
 services.AddSingleton<IHostingEnvironment>(_hostingEnvironment);
 services.AddSingleton<Extensions.Hosting.IHostingEnvironment>(_hostingEnvironment);
 services.AddSingleton(_context);

 var builder = new ConfigurationBuilder()
    .SetBasePath(_hostingEnvironment.ContentRootPath)
    .AddConfiguration(_config);

 _configureAppConfigurationBuilder?.Invoke(_context, builder);

 var configuration = builder.Build();
 services.AddSingleton<IConfiguration>(configuration);
 _context.Configuration = configuration;
이 코드 는 Startup.cs 파일 에서 ServiceCollection 대상 을 사용 하여 업무 시스템 의 사용자 정의 대상 을 서비스 컨 텍스트 에 추가 하여 후속 인터페이스 주입 에 편리 하 게 사용 할 수 있 기 때문에 매우 익숙 합 니 다.
AddJSonFile 방법의 사용
일반적으로 저 희 는 기본 프로필 을 사용 하여 개발 하거나 apptsettings.{env.Environment Name}.json 의 파일 이름 방식 으로 개발/테스트/제품 환경 을 구분 하고 환경 변수 에 따라 서로 다른 프로필 을 불 러 옵 니 다.그러나 이렇게 되면 또 다른 관리 상의 문제,제품 환경의 배치 파라미터 와 개발 환경 을 가 져 왔 다.
환경 변 수 를 사용 하여 설정 파일 의 로드 를 제어 하면 암호 유출 등 위험 을 초래 할 수 있 습 니 다.물론 제품 환경 에서 수 동 으로 이 파일 을 만 들 수 있 지만,이렇게 되면 발표 절차 가 매우 번 거 로 워 지고,조금 이라도 누락 된 파일 은 덮어 쓸 수 있다.
AddJSonFile 로 제품 환경 설정 을 불 러 오 는 것 을 추천 합 니 다.코드 는 다음 과 같 습 니 다.

 public Startup(IConfiguration configuration, IHostingEnvironment env)
  {
   Configuration = AddCustomizedJsonFile(env).Build();

  }

  public ConfigurationBuilder AddCustomizedJsonFile(IHostingEnvironment env)
  {
   var build = new ConfigurationBuilder();
   build.SetBasePath(env.ContentRootPath).AddJsonFile("appsettings.json", true, true);
   if (env.IsProduction())
   {
    build.AddJsonFile(Path.Combine("/data/sites/config", "appsettings.json"), true, true);
   }
   return build;
  }
AddCustomizedJSonFile 방법 을 통 해 ConfigurationBuilder 대상 을 만 들 고 시스템 의 기본 ConfigurationBuilder 대상 을 덮어 씁 니 다.방법 내부 에서 개발 환경의 프로필 을 기본적으로 불 러 옵 니 다.제품 모드 에서 디 렉 터 리/data/sites/config/appstettings.json 파일 을 추가 로 불 러 옵 니 다.
프로필 충돌 문 제 를 걱정 하지 않 습 니 다.같은 키 의 내용 은 나중에 추 가 된 프로필 로 덮어 씁 니 다.
프로필 변경
AddJSonFile 을 호출 할 때,우 리 는 이 방법 이 모두 5 개의 과부하 방법 이 있 는 것 을 보 았 다.
그 중 하 나 는 4 개의 인 자 를 포함 하고 코드 는 다음 과 같다.

 public static IConfigurationBuilder AddJsonFile(this IConfigurationBuilder builder, IFileProvider provider, string path, bool optional, bool reloadOnChange)
  {
   if (builder == null)
   {
    throw new ArgumentNullException(nameof(builder));
   }
   if (string.IsNullOrEmpty(path))
   {
    throw new ArgumentException(Resources.Error_InvalidFilePath, nameof(path));
   }

   return builder.AddJsonFile(s =>
   {
    s.FileProvider = provider;
    s.Path = path;
    s.Optional = optional;
    s.ReloadOnChange = reloadOnChange;
    s.ResolveFileProvider();
   });
  }
이 방법 에서 하나의 매개 변수 bool reloadOnChange 가 있 습 니 다.매개 변수 설명 을 통 해 알 수 있 듯 이 이 값 은 파일 이 변동 할 때 다시 불 러 올 지 여 부 를 표시 합 니 다.기본 값 은 false 입 니 다.일반적으로 설정 파일 을 수 동 으로 불 러 옵 니 다.즉,AddJSonFile 방법 을 호출 할 때 이 매개 변 수 를 true 로 설정 하 는 것 을 권장 합 니 다.
그러면.net core 는 이 매개 변수 reloadOnChange 를 통 해 파일 의 변동 을 감시 하고 언제 다시 불 러 오 는 지 확인 할 수 있 습 니 다.아래 코드 를 보 세 요.

  public IConfigurationRoot Build()
  {
   var providers = new List<IConfigurationProvider>();
   foreach (var source in Sources)
   {
    var provider = source.Build(this);
    providers.Add(provider);
   }
   return new ConfigurationRoot(providers);
  }
우리 가.build 방법 을 실행 할 때 방법 내부 의 마지막 줄 코드 는 AddJSonFile 방법의 매개 변 수 를 이용 하여 ConfigurationRoot 대상 을 만 들 고 되 돌려 주 었 습 니 다.
ConfigurationRoot 의 구조 방법 에서

  public ConfigurationRoot(IList<IConfigurationProvider> providers)
  {
   if (providers == null)
   {
    throw new ArgumentNullException(nameof(providers));
   }

   _providers = providers;
   foreach (var p in providers)
   {
    p.Load();
    ChangeToken.OnChange(() => p.GetReloadToken(), () => RaiseChanged());
   }
  }
방법 내부 에서 AddJSonFile 방법 으로 추 가 된 프로필 을 한 번 에 읽 고 각 프로필 에 감청 기 ChangeToken 을 따로 할당 하 며 현재 파일 읽 기 대상 IConfigurationProvider.GetReloadToken 방법 을 감청 기 에 연결 하 는 것 을 보 았 습 니 다.
파일 이 변동 이 생 겼 을 때 모니터 는 통 지 를 받 고 이 파일 에 대해 원자 작업 을 수행 합 니 다.

 private void RaiseChanged()
  {
   var previousToken = Interlocked.Exchange(ref _changeToken, new ConfigurationReloadToken());
   previousToken.OnReload();
  }
AddJSonFile 방법 내부 에 JSonConfigurationSource 를 사 용 했 기 때문에 Build 의 재 부팅 방법 은 JSonConfigurationProvider 읽 기 대상 을 구성 하여 코드 를 봅 니 다.

  public override IConfigurationProvider Build(IConfigurationBuilder builder)
  {
   EnsureDefaults(builder);
   return new JsonConfigurationProvider(this);
  }
JSonConfigurationProvider 에서 FileConfigurationProvider 클래스 를 계승 합 니 다.이 클래스 는 프로그램 집합Microsoft.Extensions.Configuration.Json.dll에 있 습 니 다.
FileConfigurationProvider 의 구조 방법 에서 모니터 가 프로필 을 다시 불 러 오 는 과정 을 실현 하 였 습 니 다.

  public FileConfigurationProvider(FileConfigurationSource source)
  {
   if (source == null)
   {
    throw new ArgumentNullException(nameof(source));
   }
   Source = source;

   if (Source.ReloadOnChange && Source.FileProvider != null)
   {
    ChangeToken.OnChange(
     () => Source.FileProvider.Watch(Source.Path),
     () => {
      Thread.Sleep(Source.ReloadDelay);
      Load(reload: true);
     });
   }
  }
주의해 야 할 것 은 이 감청 기 는 파일 변동 통 지 를 받 은 후 가장 먼저 설정 파일 을 다시 불 러 오 는 것 이 아니 라 방법 내부 에서 볼 수 있 습 니 다.여기Thread.Sleep(Source.ReloadDelay) 가 있 습 니 다.ReloadDelay 의 기본 값 은 250 ms 입 니 다.이 속성 은 다음 과 같 습 니 다.
  • 기다 리 는 밀리초 수 를 다시 불 러 오 거나 설정 한 다음'Load'방법 을 사용 합 니 다.파일 을 완전히 쓰기 전에 다시 불 러 오 는 것 을 피 하 는 데 도움 이 됩 니 다.기본 값 250
  • 저 희 는 이 값 을 사용자 정의 할 수 있 습 니 다.만약 에 업무 가 파일 변동 에 대한 수요 가 그리 절박 하지 않 으 면 이 값 을 큰 시간 으로 설정 할 수 있 습 니 다.일반적인 상황 에서 저 희 는 그렇게 하 는 것 을 권장 하지 않 습 니 다
  • 결어
    이상 은 asp.netcore 에서 파일 을 불 러 오 는 내부 실행 과정 입 니 다.기본 프로필 을 어떻게 불 러 오 는 지,기본 프로필 을 시스템 에 어떻게 주입 하 는 지,서로 다른 환경 에서 사용자 정의 프로필 을 불 러 오 는 과정 도 배 웠 습 니 다.그러나 프로필 이 바 뀌 었 을 때 시스템 내 부 는 어떻게 프로필 을 메모리 에 다시 불 러 옵 니까?

    좋은 웹페이지 즐겨찾기