![](/img/trans.png)
[英].NET Core 2.2 - Unable to get app configuration from Azure AppConfig
[英]Dynamically update .net core config from Azure App Configuration
What I am trying to do: I am attempting to setup Azure App Configuration with a .net core 2.1 mvc web application with a sentinel key in Azure App Configuration, with the goal of being able to change keys in azure, and none of the keys will在我的應用程序中更新,直到哨兵值發生變化。 理論上,這應該允許我安全地熱交換配置。
我的問題是:當我這樣做時,沒有 WatchAndReloadAll() 方法可用於觀察 IWebHostBuilder 上的哨兵,並且替代的 Refresh() 方法似乎不會刷新配置,因為它們是 state。
背景信息,以及我嘗試過的內容:上周我參加了 VS Live - San Diego,並觀看了有關 Azure 應用程序配置的演示。 我在嘗試讓應用程序刷新配置值時遇到了一些問題,因此我還參考了這個演示,描述了如何執行此操作。 相關部分大約在 10 分鍾后。但是,該方法在 IWebHostBuilder 上似乎不可用。
我正在參考的文檔:在官方文檔中沒有提及此方法,請參閱文檔快速入門 .net 內核和文檔動態配置 .net 內核
My Environment: Using dot net core 2.1 being run from Visual Studio Enterprise 2019, with the latest preview nuget package for Microsoft.Azure.AppConfiguration.AspNetCore 2.0.0-preview-010060003-1250
我的代碼:在演示中,他們通過 CreateWebHostBuilder(string[] args) 方法創建了一個 IWebHostBuilder,如下所示:
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>();
}
我也嘗試過這種方式,使用當前的文檔:
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>();
然后,在我的啟動 class 中:
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?}");
});
}
最后是我的設置配置 model:
public class Settings
{
public string BackgroundColor { get; set; }
public long FontSize { get; set; }
public string FontColor { get; set; }
public string Message { get; set; }
}
現在,在我的 controller 中,我拉出這些設置並將它們放入視圖包中以顯示在視圖上。
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();
}
}
顯示更改的簡單視圖:
<!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>
我可以讓它第一次拉下配置,但是,刷新功能似乎無法以任何方式工作。
在最后一個示例中,我希望配置在哨兵設置為任何新值時更新,或者至少在更改值 30 秒后更新值。 沒有等待時間更新值,只有完全關閉並重新啟動應用程序才會加載新配置。
更新:添加 app.UseAzureAppConfiguration(); 在啟動時的配置方法中,並在配置緩存上設置顯式超時修復了刷新方法在固定時間后刷新,但哨兵功能仍然不起作用,刷新方法上的 updateAll 標志也不起作用。
好的,經過多次測試和反復試驗,我讓它工作了。
我的問題是在配置方法上缺少 azure 服務。 這里有一些有趣的行為,因為它仍然會下拉設置,如果缺少它就不會更新。 因此,一旦將其放入並為每個文檔配置了適當的哨兵,它就可以與 updateAll 標志一起使用。 然而,這目前沒有記錄。
這是解決方案:
在 Program.cs 中:
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration.AzureAppConfiguration;
namespace ASPNetCoreApp
{
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
} // Main
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 =>
{
// 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);
// Set a timeout for the cache so that it will poll the azure config every X timespan.
refreshOptions.SetCacheExpiration(cacheExpirationTime: new System.TimeSpan(0, 0, 0, 15, 0));
});
});
})
.UseStartup<Startup>();
}
}
然后在 Startup.cs 中:
using ASPNetCoreApp.Models;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace ASPNetCoreApp
{
public class Startup
{
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)
{
// bind the config to our DI container for the settings we are pulling down from azure.
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);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
// Set the Azure middleware to handle configuration
// It will pull the config down without this, but will not refresh.
app.UseAzureAppConfiguration();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
設置 model 我將 azure 檢索到的數據綁定到:
namespace ASPNetCoreApp.Models
{
public class Settings
{
public string BackgroundColor { get; set; }
public long FontSize { get; set; }
public string FontColor { get; set; }
public string Message { get; set; }
}
}
一個通用的 home controller 配置被設置為 ViewBag 以傳遞給我們的視圖:
using ASPNetCoreApp.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using System.Diagnostics;
namespace ASPNetCoreApp.Controllers
{
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();
}
public IActionResult About()
{
ViewData["Message"] = "Your application description page.";
return View();
}
public IActionResult Contact()
{
ViewData["Message"] = "Your contact page.";
return View();
}
public IActionResult Privacy()
{
return View();
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
}
我們的觀點:
<!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>
希望這對其他人有幫助!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.