VssHttpMessageHandler and HttpMessageHandler pooling



我目前正在使用C#的Azure Devops客户端库。出于许多原因(例如避免端口耗尽或可测试性(,我想使用dotnetcore提供的IHttpMessageHandlerFactory为我的VssConnection提供处理程序。目前,我使用这个:

var vssHttpMessageHandler = new VssHttpMessageHandler(new VssBasicCredential(string.Empty, options.Pat), VssClientHttpRequestSettings.Default.Clone(), _httpMessageHandlerFactory.CreateHandler(HttpClientName));

然而,这并不总是有效的,因为当处理程序被重用时,会抛出一个异常:

System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw处理的System.InvalidOperationException:位于System.Net.Http.SocketsHttpHandler.CheckDisposedOrStarted(System.Net.HHttp,版本=4.2.2.0,区域性=中性,PublicKeyToken=b03f5f7f11d50a3a(位于Microsoft.VisualStudio.Services.Common.VssHttpMessageHandler.ApplySettings(Microsoft.VisualStudio.Services.MCommon,Version=16.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a(

事实上,在构造VssHttpMessageHandler时,会将新的设置应用于HttpMessageHandler。然而,此设置不支持在其使用开始后进行修改(设置时,其所有属性都调用CheckDisposedOrStarted(。

我能做些什么来实现我想要做的事情?

编辑:这是我的代码的复制

var azureDevopsUri = "https://dev.azure.com/mycollection";
var pat = "mypathere";
var services = new ServiceCollection();
services.AddHttpClient();
services.AddTransient(s =>
{
var handlerFactory = s.GetRequiredService<IHttpMessageHandlerFactory>();    
var vssHandler = new VssHttpMessageHandler(
new VssBasicCredential(string.Empty, pat),
VssClientHttpRequestSettings.Default.Clone(),
handlerFactory.CreateHandler());
return new VssConnection(
new Uri(azureDevopsUri),
vssHandler,
new DelegatingHandler[] { });
});
var provider = services.BuildServiceProvider();
using(var scope = provider.CreateScope())
{
var connection = scope.ServiceProvider.GetRequiredService<VssConnection>();
var client = await connection.GetClientAsync<ProjectCollectionHttpClient>();
await client.GetProjectCollections();
}
using (var scope = provider.CreateScope())
{
var connection = scope.ServiceProvider.GetRequiredService<VssConnection>(); // <-- Exception thrown here
var client = await connection.GetClientAsync<ProjectCollectionHttpClient>();
await client.GetProjectCollections();
}

正如您所看到的,当我将VssConnection配置为非单例时(这是我目前正在使用的解决方法(,第二次创建实例时,我会抛出异常,因为用于池化的IHttpMessageHandlerFactory可能已经使用过了。

异常详细信息:

This instance has already started one or more requests. Properties can only be modified before sending the first request. 
at System.Net.Http.SocketsHttpHandler.CheckDisposedOrStarted()
at System.Net.Http.HttpClientHandler.set_AllowAutoRedirect(Boolean value)
at Microsoft.VisualStudio.Services.Common.VssHttpMessageHandler.ApplySettings(HttpMessageHandler handler, ICredentials defaultCredentials, VssHttpRequestSettings settings)
at UserQuery.<>c__DisplayClass4_0.<Main>b__0(IServiceProvider s), line 9
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitDisposeCache(ServiceCallSite transientCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
at UserQuery.Main(), line 31 

我使用VssHttpMessageHandler进行了测试,但无法重现此问题。

我想分享C#示例:

var azureDevopsUri = "https://dev.azure.com/org";
var pat = "PAT";
var services = new ServiceCollection();
services.AddHttpClient();
services.AddTransient(s =>
{
var handlerFactory = s.GetRequiredService<IHttpMessageHandlerFactory>();
var vssHandler = new VssHttpMessageHandler(
new VssBasicCredential(string.Empty, pat),
VssClientHttpRequestSettings.Default.Clone());
return new VssConnection(
new Uri(azureDevopsUri),
vssHandler,
new DelegatingHandler[] { });
});
var provider = services.BuildServiceProvider();
using (var scope = provider.CreateScope())
{
var connection = scope.ServiceProvider.GetRequiredService<VssConnection>();
var client = await connection.GetClientAsync<ProjectCollectionHttpClient>();
await client.GetProjectCollections();
}
using (var scope = provider.CreateScope())
{
var connection = scope.ServiceProvider.GetRequiredService<VssConnection>(); // <-- Exception thrown here
var client = await connection.GetClientAsync<ProjectCollectionHttpClient>();
await client.GetProjectCollections();
}

注意:软件包:Microsoft.TeamFoundationServer.Client:16.143.2。

在包中,VssHttpMessageHandler定义:

public VssHttpMessageHandler(VssCredentials credentials, VssHttpRequestSettings settings, HttpMessageHandler innerHandler);

最新更新