升级 Azure Function .Net 8 后无法调试代码
请在下面找到我的 Program.cs 和 Startup.cs。 我读了文档,它说在 dotnet 隔离模型中,不需要 starup.cs。无法理解那么我该如何处理我的依赖注入。
这是我的Program.cs
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults()
.ConfigureServices(services =>
{
services.AddApplicationInsightsTelemetryWorkerService();
services.ConfigureFunctionsApplicationInsights();
})
.ConfigureFunctionsWebApplication()
.Build();
host.Run();
这是我的 Startup.cs 文件
class Startup : FunctionsStartup
{
private IConfiguration _configuration;
public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
{
var cred = new ClientSecretCredential(Settings.TenantId, Settings.ClientId, Settings.ClientSecret);
if (!string.IsNullOrEmpty(Settings.SecondaryAppConfigConnection))
{
builder.ConfigurationBuilder.AddAzureAppConfiguration(options =>
{
options.Connect(Settings.SecondaryAppConfigConnection)
.ConfigureKeyVault(kv => kv.SetCredential(cred))
.Select(KeyFilter.Any, LabelFilter.Null)
.Select(KeyFilter.Any, Settings.Environment);
}, true).AddAzureAppConfiguration(options =>
{
options.Connect(Settings.AppConfigConnection)
.ConfigureKeyVault(kv => kv.SetCredential(cred))
.Select(KeyFilter.Any, LabelFilter.Null)
.Select(KeyFilter.Any, Settings.Environment);
}, true);
}
else
{
builder.ConfigurationBuilder.AddAzureAppConfiguration(options =>
{
options.Connect(Settings.AppConfigConnection)
.ConfigureKeyVault(kv => kv.SetCredential(cred))
.Select(KeyFilter.Any, LabelFilter.Null)
.Select(KeyFilter.Any, Settings.Environment);
});
}
_configuration = builder.ConfigurationBuilder.Build();
}
public override void Configure(IFunctionsHostBuilder builder)
{
var settings = new GatewayFunctionSettingProvider(_configuration);
var connectionString = settings.GetConnectionString();
Endpoint.Utilities.Logging.LoggerHelpers.ConfigureSerilogForAzureFunctions(settings);
builder.Services.AddAzureAppConfiguration();
builder.Services.AddScoped<ICacheDataAdapter>(s => new RedisCacheDataAdapter(_configuration["RedisHost"]));
builder.Services.AddSingleton<ICertificateManager>(s => new CertificateManager(settings, new RedisCacheDataAdapter(_configuration["RedisHost"])));
builder.Services.AddSingleton<IMassTransitRequest<MonitorUserIdPoolRequest>>(s => new MassTransitRequest<MonitorUserIdPoolRequest>());
builder.Services.AddSingleton(s => settings);
builder.Services.AddSingleton<CoreSettingsProvider>(s => settings);
builder.Services.AddSingleton<SettingsProvider>(s => settings);
builder.Services.AddSingleton<IConnectionMultiplexer>(s => ConnectionMultiplexer.Connect(settings.RedisHost));
builder.Services.AddScoped<IHiLoDataAdapter>(s => new HiLoDataAdapter(connectionString, settings.UserIdHiLoCapacity));
builder.Services.AddScoped<IUserIdGenerationService, UserIdGenerationService>();
builder.Services.AddMassTransitForAzureFunctions(cfg =>{}, "AzureWebJobsServiceBus");
builder.Services.AddSingleton(Bus.Factory.CreateUsingAzureServiceBus(x => x.Host(settings.AzureWebJobsServiceBus)));
builder.Services.AddLogging();
builder.Services.AddSingleton(x => new BlobServiceClient(connectionString));
builder.Services.AddFunctionsWorkerDefaults();
SettingsProvider.RegisterCurrentProvider(() => settings);
}
}
本地设置.json
{
"IsEncrypted": false,
"Values": {
"FUNCTIONS_EXTENSION_VERSION": "~4",
"FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
}
}
主机.json
{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
}
}
},
"functionTimeout": "00:30:00"
}
这里是具有HTTP和定时器功能的函数代码
public class EmailAlertOnPasswordExpiration
{
private readonly ISendEndpointProvider sendEndpointProvider;
private GatewayFunctionSettingProvider settings;
public EmailAlertOnPasswordExpiration(ISendEndpointProvider SendEndpointProvider,
GatewayFunctionSettingProvider settings)
{
this.sendEndpointProvider = SendEndpointProvider;
this.settings = settings;
}
[Function("EmailAlertOnPasswordExpiration")]
public async Task Run([TimerTrigger("%EmailAlertOnPasswordExpirationTrigger%")]
TimerInfo myTimer, ILogger log)
{
log.LogInformation($"EmailAlertOnPasswordExpire Timer trigger function executed
at: {DateTime.Now}");
await PasswordExpiryUserList(log);
}
[Function("EmailAlertOnPasswordExpirationGet")]
public async Task<IActionResult> EmailAlertOnPasswordExpirationGet(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = "Email-Alert")] HttpRequest req,
ILogger log)
{
log.LogInformation($"EmailAlertOnPasswordExpire GET trigger function executed at: {DateTime.Now}");
await PasswordExpiryUserList(log);
return new OkObjectResult("OK");
}
public async Task PasswordExpiryUserList(ILogger log)
{
var nodeNameProvider = new NodeNameProvider(settings.GetConnectionString());
var nodes = nodeNameProvider.GetNodes();
string query = "select u.UserName,u.FirstName, u.LastName,u.Id from [dbo].[Credential] c inner join dbo.[User] u on c.UserId = u.Id WHERE CONVERT(date, c.ExpiresOn) = CONVERT(DATE, DATEADD(day, 7, getdate())) and u.Active = 1 ";
using (SqlConnection connection = new SqlConnection(settings.GetConnectionString()))
{
connection.Open();
DataTable table = new DataTable();
using (var da = new SqlDataAdapter(query, connection))
{
da.Fill(table);
if (table.Rows.Count > 0)
{
log.LogInformation($"After execute query table has " + table.Rows.Count + " rows");
List<Endpoint.Contracts.UserData> userList = new List<Endpoint.Contracts.UserData>();
userList = (from DataRow dr in table.Rows
select new Endpoint.Contracts.UserData()
{
UserName = dr["UserName"].ToString(),
FirstName = dr["FirstName"].ToString(),
LastName = dr["LastName"].ToString(),
UserId = dr["Id"].ToString()
}).ToList();
UserDataMessage userMessage = new UserDataMessage
{
UserInfoData = userList
};
if (userMessage != null | userMessage.UserInfoData.Count > 0)
{
log.LogInformation($"UserList count is" + userMessage.UserInfoData.Count);
foreach (var nodeName in nodes)
{
try
{
var uri = new Uri($"queue:NodeWorker-{nodeName}");
var endpoint = await sendEndpointProvider.GetSendEndpoint(uri);
await endpoint.Send(userMessage, ctx =>
{
ctx.TimeToLive = TimeSpan.FromMinutes(1);
});
}
catch (Exception ex)
{
log.LogInformation($"Error posting Password Expiry Email Alert info to {nodeName}", ex);
}
}
}
else
{
log.LogInformation($"UserList is null");
}
}
else
{
log.LogInformation($"DataTable is null");
}
}
}
}
}
请指导我如何调试代码?没有收到错误。当我运行 HTTP 函数时
因此,dotnet 隔离模型中的变化是,这些函数现在在隔离的容器中运行,其中 HostBuilder 函数定义了您将要使用的大部分依赖项以及其他与主机相关的配置。我也必须不断尝试和犯错才能使其正常工作,但总而言之,在 Program.cs 中:
var host = HostBuilder()
.ConfigureFunctionWorkerDefaults()
.ConfigureServices((hostContext, services) =>
{
// Put your dependency injections here, for example
var keyVaultUrl = new Uri(Environment.GetEnvironmentVariable("ConnectionURL")!);
services.AddAzureClients(clientBuilder =>
{
clientBuilder.UseCredentials(new DefaultAzureCredential());
clientBuilder.AddSecretClient(keyVault);
}
})
您现在设置了一个天蓝色的秘密客户端依赖项,将其注入到一个函数中(例如 HTTP 触发器),转到函数类并将依赖项添加到您的类构造函数中,在您的示例中:
public EmailAlertOnPasswordExpiration(... , SecretClient secretClient)
{
// Use the secret client as an injected dependency
}
现在调试有点困难,因为您需要设置本地开发环境才能访问此资源,或者在 local-settings.json 中创建本地设置以获得一些虚拟数据或与虚拟 Azure 的连接资源(我希望我明白了问题的要点)。