应用配置 .NET 客户端库支持按需更新配置,而不会导致应用程序重启。 应用程序可以配置为使用以下两种方法中的一种或两种来检测应用配置更改。
轮询模型:这是使用轮询检测配置更改的默认行为。 设置的刷新间隔过后,下一次调用
TryRefreshAsync
或RefreshAsync
向服务器发送请求以检查配置是否已更改,并在需要时拉取更新的配置。推送模型:这将使用应用配置事件检测配置更改。 设置应用配置以将键值更改事件发送到 Azure 事件网格后,应用程序可以使用这些事件来优化保持配置更新所需的请求总数。 应用程序可以选择直接从事件网格订阅这些应用程序,也可以通过 Webhook、Azure 函数或服务总线主题等 受支持的事件处理程序 之一进行订阅。
本教程演示如何在代码中使用推送刷新实现动态配置更新。 它基于本教程中引入的应用。 在继续之前,请完成教程:先 在 .NET 应用中使用动态配置 。
你可以使用任何代码编辑器执行本教程中的步骤。 Visual Studio Code 是 Windows、macOS 和 Linux 平台上提供的一个卓越选项。
本教程中,您将学习如何:
- 设置订阅以将配置更改事件从应用配置发送到服务总线主题
- 配置您的 .NET 应用程序,以便根据应用配置中的更改来更新其配置。
- 在应用程序中使用最新配置。
- 教程: 在 .NET 应用中使用动态配置
- NuGet 包
Microsoft.Extensions.Configuration.AzureAppConfiguration
版本 5.0.0 或更高版本
本教程使用事件网格的服务总线集成来简化对不希望持续轮询应用配置的应用程序的配置更改的检测。 Azure 服务总线 SDK 提供了一个 API,用于注册消息处理程序,该处理程序可用于在应用配置中检测到更改时更新配置。 按照快速入门:使用 Azure 门户创建服务总线主题和订阅中的步骤来创建服务总线命名空间、主题和订阅。
创建资源后,添加以下环境变量。 这些代码将用于注册事件处理程序,以便在应用程序代码中更改配置。
密钥 | 价值 |
---|---|
服务总线连接字符串 | 服务总线命名空间的连接字符串 |
ServiceBusTopic | 服务总线主题的名称 |
ServiceBusSubscription | 服务总线订阅的名称 |
在 Azure 门户中打开应用配置资源,然后在窗格中单击
+ Event Subscription
Events
。输入
Event Subscription
和System Topic
的名称。选择
Endpoint Type
作为Service Bus Topic
,然后选择服务总线主题,再点击Confirm Selection
。单击
Create
以创建事件订阅。在窗格中单击
Event Subscriptions
Events
,验证是否已成功创建订阅。
备注
订阅配置更改时,可以使用一个或多个筛选器来减少发送到应用程序的事件数。 可以将这些筛选器配置为 事件网格订阅筛选器 或服务 总线订阅筛选器。 例如,订阅筛选器可用于仅订阅与特定字符串开头的键相关的更改事件。
打开 Program.cs ,使用以下代码更新文件。
using Azure.Messaging.EventGrid;
using Azure.Messaging.ServiceBus;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.AzureAppConfiguration;
using Microsoft.Extensions.Configuration.AzureAppConfiguration.Extensions;
using System;
using System.Threading.Tasks;
namespace TestConsole
{
class Program
{
private const string AppConfigurationConnectionStringEnvVarName = "AppConfigurationConnectionString";
// e.g. Endpoint=https://{store_name}.azconfig.io;Id={id};Secret={secret}
private const string ServiceBusConnectionStringEnvVarName = "ServiceBusConnectionString";
// e.g. Endpoint=sb://{service_bus_name}.servicebus.chinacloudapi.cn/;SharedAccessKeyName={key_name};SharedAccessKey={key}
private const string ServiceBusTopicEnvVarName = "ServiceBusTopic";
private const string ServiceBusSubscriptionEnvVarName = "ServiceBusSubscription";
private static IConfigurationRefresher _refresher = null;
static async Task Main(string[] args)
{
string appConfigurationConnectionString = Environment.GetEnvironmentVariable(AppConfigurationConnectionStringEnvVarName);
IConfiguration configuration = new ConfigurationBuilder()
.AddAzureAppConfiguration(options =>
{
options.Connect(appConfigurationConnectionString);
// Load the key-value with key "TestApp:Settings:Message" and no label
options.Select("TestApp:Settings:Message");
// Reload configuration if any selected key-values have changed.
options.ConfigureRefresh(refresh =>
refresh
.RegisterAll()
// Important: Reduce poll frequency
.SetRefreshInterval(TimeSpan.FromDays(1))
);
_refresher = options.GetRefresher();
}).Build();
await RegisterRefreshEventHandler();
var message = configuration["TestApp:Settings:Message"];
Console.WriteLine($"Initial value: {configuration["TestApp:Settings:Message"]}");
while (true)
{
await _refresher.TryRefreshAsync();
if (configuration["TestApp:Settings:Message"] != message)
{
Console.WriteLine($"New value: {configuration["TestApp:Settings:Message"]}");
message = configuration["TestApp:Settings:Message"];
}
await Task.Delay(TimeSpan.FromSeconds(1));
}
}
private static async Task RegisterRefreshEventHandler()
{
string serviceBusConnectionString = Environment.GetEnvironmentVariable(ServiceBusConnectionStringEnvVarName);
string serviceBusTopic = Environment.GetEnvironmentVariable(ServiceBusTopicEnvVarName);
string serviceBusSubscription = Environment.GetEnvironmentVariable(ServiceBusSubscriptionEnvVarName);
ServiceBusClient serviceBusClient = new ServiceBusClient(serviceBusConnectionString);
ServiceBusProcessor serviceBusProcessor = serviceBusClient.CreateProcessor(serviceBusTopic, serviceBusSubscription);
serviceBusProcessor.ProcessMessageAsync += (processMessageEventArgs) =>
{
// Build EventGridEvent from notification message
EventGridEvent eventGridEvent = EventGridEvent.Parse(BinaryData.FromBytes(processMessageEventArgs.Message.Body));
// Create PushNotification from eventGridEvent
eventGridEvent.TryCreatePushNotification(out PushNotification pushNotification);
// Prompt Configuration Refresh based on the PushNotification
_refresher.ProcessPushNotification(pushNotification);
return Task.CompletedTask;
};
serviceBusProcessor.ProcessErrorAsync += (exceptionargs) =>
{
Console.WriteLine($"{exceptionargs.Exception}");
return Task.CompletedTask;
};
await serviceBusProcessor.StartProcessingAsync();
}
}
}
该方法 ProcessPushNotification
将刷新间隔重置为短暂的随机延迟。 这导致以后需调用 RefreshAsync
或 TryRefreshAsync
来根据应用程序配置重新验证已缓存值,并在必要时进行更新。 在此示例中,注册以监视所有所选键值(TestApp:Settings:Message)的更改,刷新间隔为一天。 这意味着,在上次检查后的一天内,将不会对应用程序配置发出任何请求。 通过调用 ProcessPushNotification
应用程序,将在接下来几秒钟内将请求发送到应用配置。 您的应用程序将在App Configuration
存储发生变更后不久加载新的配置值,而不必频繁检查更新。 如果应用程序出于任何原因错过更改通知,它仍将每天检查一次配置更改。
如果您有多个应用程序实例或微服务采用推送模型连接到同一应用配置中心,则刷新间隔的短随机延迟会非常有用。 如果不出现此延迟,应用程序的所有实例都可以在收到更改通知后立即同时向应用配置存储发送请求。 这可能会导致应用程序配置服务对存储区形成限制。 默认情况下,刷新间隔延迟设置为介于 0 到最多 30 秒之间的随机数,但可以通过可选参数 maxDelay
将最大值更改为 ProcessPushNotification
该方法。
该方法 ProcessPushNotification
采用一个 PushNotification
对象,其中包含有关应用配置中哪些更改触发推送通知的信息。 在以下配置刷新中,有助于确保所有配置更改在触发事件之前都已加载。
SetDirty
方法无法保证触发推送通知的更改会加载到即时配置刷新中。 如果您使用 SetDirty
方法来进行推送模型,我们建议改用 ProcessPushNotification
方法。
设置名为 AppConfigurationConnectionString 的环境变量,并将其设置为应用配置存储的访问密钥。
如果使用 Linux,请运行以下命令:
export AppConfigurationConnectionString='<connection-string-of-your-app-configuration-store>'
运行以下命令以生成控制台应用:
dotnet build
生成成功完成后,请运行以下命令以在本地运行应用:
dotnet run
登录到 Azure 门户。 选择 “所有资源”,然后选择在快速入门中创建的应用配置存储实例。
选择 配置资源管理器,并更新以下键的值:
密钥 价值 测试应用:设置:消息 Azure 应用配置中的数据 - 已更新 等待片刻,让事件得到处理。 你将看到更新的配置。
如果不想继续使用本文中创建的资源,请删除此处创建的资源组以避免产生费用。
重要
删除资源组的操作不可逆。 将永久删除资源组以及其中的所有资源。 请确保不要意外删除错误的资源组或资源。 如果在包含要保留的其他资源的资源组中创建了本文的资源,请从相应的窗格中单独删除每个资源,而不是删除该资源组。
- 登录到 Azure 门户,然后选择“资源组”。
- 在按名称筛选框中,输入资源组的名称。
- 在结果列表中,选择资源组名称以查看概述。
- 选择“删除资源组”。
- 系统会要求确认是否删除资源组。 重新键入资源组的名称进行确认,然后选择“删除”。
片刻之后,将会删除该资源组及其所有资源。
在本教程中,使 .NET 应用能够从应用配置动态刷新配置设置。 若要了解如何使用 Azure 托管标识来简化对应用程序配置的访问,请继续学习下一篇教程。