Co próbuję zrobić: próbuję skonfigurować konfigurację aplikacji Azure za pomocą aplikacji sieci web .net core 2.1 mvc z kluczem wartownika w konfiguracji aplikacji Azure, aby móc zmieniać klucze w kolorze lazurowym i żaden z kluczy będzie aktualizować w moich aplikacjach, dopóki wartość wartownika nie ulegnie zmianie. Teoretycznie powinno to pozwolić mi na bezpieczne konfiguracje wymiany podczas pracy.
Mój problem polega na tym: kiedy to robię, nie ma dostępnej metody WatchAndReloadAll () do obserwowania wartownika na IWebHostBuilder, a alternatywne metody Refresh () nie wydają się odświeżać konfiguracji w jej stanie.
Informacje podstawowe i to, czego próbowałem: W ubiegłym tygodniu uczestniczyłem w VS Live - San Diego i oglądałem prezentację konfiguracji aplikacji Azure. Miałem pewne problemy z próbą nakłonienia aplikacji do odświeżenia wartości konfiguracji podczas jej zaimplementowania, więc odwołałem się również do tego demo, opisując, jak to zrobić. Odpowiednia sekcja trwa około 10 minut. Jednak ta metoda nie wydaje się być dostępna w IWebHostBuilder.
Dokumentacja, do której się odwołuję: W oficjalnej dokumentacji nie ma odniesienia do tej metody, patrz dokument Szybki start .net core i doc. Konfiguracja dynamiczna .net core
Moje środowisko: używanie dot net core 2.1 z Visual Studio Enterprise 2019 z najnowszym pakietem nuget podglądu dla Microsoft.Azure.AppConfiguration.AspNetCore 2.0.0-Preview-010060003-1250
Mój kod: W wersji demo utworzyli IWebHostBuilder za pomocą metody CreateWebHostBuilder (string [] args) w następujący sposób:
public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
return WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
var settings = config.Build();
config.AddAzureAppConfiguration(options =>
{
options.Connect(settings["ConnectionStrings:AzureConfiguration"])
.Use(keyFilter: "TestApp:*")
.WatchAndReloadAll(key: "TestApp:Sentinel", pollInterval: TimeSpan.FromSeconds(5));
});
})
.UseStartup<Startup>();
}
Próbowałem również w ten sposób, korzystając z bieżącej dokumentacji:
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
var settings = config.Build();
config.AddAzureAppConfiguration(options =>
{
// fetch connection string from local config. Could use KeyVault, or Secrets as well.
options.Connect(settings["ConnectionStrings:AzureConfiguration"])
// filter configs so we are only searching against configs that meet this pattern
.Use(keyFilter: "WebApp:*")
.ConfigureRefresh(refreshOptions =>
{
// In theory, when this value changes, on the next refresh operation, the config will update all modified configs since it was last refreshed.
refreshOptions.Register("WebApp:Sentinel", true);
refreshOptions.Register("WebApp:Settings:BackgroundColor", false);
refreshOptions.Register("WebApp:Settings:FontColor", false);
refreshOptions.Register("WebApp:Settings:FontSize", false);
refreshOptions.Register("WebApp:Settings:Message", false);
});
});
})
.UseStartup<Startup>();
Następnie w mojej klasie startowej:
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<Settings>(Configuration.GetSection("WebApp:Settings"));
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseAzureAppConfiguration();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
i wreszcie mój model konfiguracji ustawień:
public class Settings
{
public string BackgroundColor { get; set; }
public long FontSize { get; set; }
public string FontColor { get; set; }
public string Message { get; set; }
}
Teraz w moim kontrolerze wyciągam te ustawienia i wrzucam je do torby widokowej, która będzie wyświetlana w widoku.
public class HomeController : Controller
{
private readonly Settings _Settings;
public HomeController(IOptionsSnapshot<Settings> settings)
{
_Settings = settings.Value;
}
public IActionResult Index()
{
ViewData["BackgroundColor"] = _Settings.BackgroundColor;
ViewData["FontSize"] = _Settings.FontSize;
ViewData["FontColor"] = _Settings.FontColor;
ViewData["Message"] = _Settings.Message;
return View();
}
}
Prosty widok do wyświetlenia zmian:
<!DOCTYPE html>
<html lang="en">
<style>
body {
background-color: @ViewData["BackgroundColor"]
}
h1 {
color: @ViewData["FontColor"];
font-size: @ViewData["FontSize"];
}
</style>
<head>
<title>Index View</title>
</head>
<body>
<h1>@ViewData["Message"]</h1>
</body>
</html>
Mogę go pobrać po raz pierwszy, ale funkcja odświeżania nie działa w żaden sposób.
W ostatnim przykładzie spodziewałem się, że konfiguracje zaktualizują się, gdy wartownik zostanie ustawiony na dowolną nową wartość, lub przynajmniej zaktualizuje wartość 30 sekund po jej zmianie. Brak czasu oczekiwania aktualizuje wartości, a tylko pełne zamknięcie i ponowne uruchomienie aplikacji ładuje nową konfigurację.
Aktualizacja: dodawanie aplikacji UseAzureAppConfiguration (); w metodzie config podczas uruchamiania i ustawienie jawnego limitu czasu w pamięci podręcznej dla konfiguracji poprawiło odświeżanie metody odświeżania po ustalonym czasie, ale funkcja wartownika nadal nie działa, podobnie jak flaga updateAll w metodzie odświeżania.
ConfigureServices
metodzie w startuop.cs, na przykład services.Configure<LogSettings>(configuration.GetSection("LogSettings"));