【问题标题】:VssHttpMessageHandler and HttpMessageHandler poolingVssHttpMessageHandler 和 HttpMessageHandler 池化
【发布时间】:2020-11-19 16:37:44
【问题描述】:

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

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

但是,这并不总是有效,因为当处理程序被重用时,会引发异常:

System.InvalidOperationException 在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw 处理: 在 System.Net.Http.SocketsHttpHandler.CheckDisposedOrStarted(System.Net.Http,版本=4.2.2.0,文化=中性,PublicKeyToken=b03f5f7f11d50a3a) 在 Microsoft.VisualStudio.Services.Common.VssHttpMessageHandler.ApplySettings(Microsoft.VisualStudio.Services.Common,版本=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 

【问题讨论】:

  • 您可以参考答案中的示例。由于我无法根据您的代码重现此问题,您能否分享更多示例代码和重现此问题的步骤?另一方面,您可以直接将参数分配给 vssconnection 以进行连接。docs.microsoft.com/en-us/azure/devops/integrate/get-started/…
  • 我已经用复制更新了我的消息。问题是重用池提供的 HttpMessageHandler 时。
  • 嗨@Nathanael Marchand。感谢你的信息。我可以重现这个问题。根据我的测试,如果我删除handlerFactory.CreateHandler(),它将成功构建。能否请您尝试一下,看看它是否可以做出一些改变。
  • 是的,我知道我可以让 sdk 创建处理程序,但它可能会导致套接字耗尽。这就是为什么我想使用 aspnetcore/dotnetcore 带来的池化改进(参见docs.microsoft.com/en-us/aspnet/core/fundamentals/…

标签: c# .net-core azure-devops


【解决方案1】:

我使用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);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-09-10
    • 2016-05-14
    • 2015-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-20
    • 2018-07-11
    相关资源
    最近更新 更多