我在 Azure Functions 应用程序(.NET 8,隔离工作线程模型)中有一组 HTTP 触发的函数,它们使用 Dataverse ServiceClient (v1.1.17) 与 Dynamics 365 集成。我遇到的问题是,当我发送多个请求时,底层的
HttpClient
会意外被处理。
起初我以为这个问题与
ServiceClient
的生命周期有关。但是,我通过将其注册为作用域和单例来测试它,但没有区别。我尝试创建一个新实例并在每次使用后将其丢弃。我什至尝试了在 GitHub 存储库CdsWeb中找到的一个“技巧”,它包装客户端并创建可重用的实例副本。
我已经在全新的最小 API 中运行了相同的代码,并且运行得很好。在循环内的控制台应用程序中运行它也是如此。当使用 k6(100 个 VU,持续 20 秒)对其进行负载测试时,会导致 1 次完成迭代和 99 次中断迭代。然而,当以最小的 API 实现时,会导致 100 次完成迭代和 0 次中断迭代。
在 Azure 中运行该函数(基于消耗)会产生相同的错误。它还定期产生
TaskCanceledException
。
这是最低限度的测试:
var query = new QueryExpression(entityName: "contact")
{
TopCount = 1,
ColumnSet = new ColumnSet("contactid", "firstname")
};
// serviceClient injected as a singleton. Access token is cached in memory and reused.
var results = await serviceClient.RetrieveMultipleAsync(query);
var contactEntity = results.Entities.SingleOrDefault();
这就是 ServiceClient 的设置方式:
// Adding it to servicecollection
services.AddSingleton<IOrganizationServiceAsync, ServiceClient>(provider =>
{
var appSettings = provider.GetRequiredService<IOptions<AppSettings>>();
var cache = provider.GetRequiredService<IMemoryCache>();
var managedIdentity = new DefaultAzureCredential(new DefaultAzureCredentialOptions
{
// Using Managed Identity running in Azure
ManagedIdentityClientId = appSettings.Value.ManagedIdentityClientId,
ExcludeManagedIdentityCredential = false,
// Using Visual Studio/VS Code credentials for local devlopment
ExcludeVisualStudioCredential = false,
ExcludeVisualStudioCodeCredential = false
});
var environment = appSettings.Value.DataverseInstanceUrl;
return new ServiceClient(
tokenProviderFunction: f => GetToken(environment, managedIdentity, cache),
instanceUrl: new Uri(environment),
useUniqueInstance: true);
});
// Getting access token and caching it for 50 minutes
async static Task<string> GetToken(string environment, DefaultAzureCredential credential, IMemoryCache cache)
{
var accessToken = await cache.GetOrCreateAsync(environment, async (cacheEntry) =>
{
cacheEntry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(50);
var token = await credential.GetTokenAsync(new TokenRequestContext([$"{environment}/.default"]));
return token;
});
return accessToken.Token;
}
NuGet 包
Microsoft.PowerPlatform.Dataverse.Client
版本 1.1.17 基于 .NET 6.0 构建。需要注意的是,它依赖于程序集 System.Text.Json Version 7.0.0.0
,它是 .NET 7 的一部分。但是,.NET 7 在 Azure Functions 服务器上不可用。请参阅 GitHub 上的讨论 和 Power Apps 社区论坛。
一个简单的修复方法是将 Azure Function 项目基于 .NET 6 并使用 NuGet 包 Microsoft.PowerPlatform.Dataverse.Client
版本 1.1.14 而不是最新版本。微软计划在今年年底添加 .NET 8 支持。