.NET Framework 4.7.2 WinForms项目HttpClientFactory无法正常使用求助
问题:.NET 4.7.2 WinForms中使用HttpClientFactory触发空引用错误
我查遍了能找到的HttpClientFactory资料,试了几天都没解决,来求助。我想在.NET 4.7.2 WinForms项目里给REST API客户端实现HttpClientFactory,尝试了类型化客户端和命名客户端两种方式,但每次实例化都会触发空引用错误,以下是我的操作步骤:
类型化客户端实现
我创建了如下类:
Imports System.Net.Http Imports Microsoft.Extensions.Http Imports Microsoft.Extensions.DependencyInjection Public Class TypedCustomHTTPClient Public Property _Client() As HttpClient Public Sub New(ByVal httpClient As HttpClient) 'httpClient.BaseAddress = New Uri("https://api.google.com/") httpClient.DefaultRequestHeaders.Add("Accept", "application/json") httpClient.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample") _Client = httpClient End Sub End Class
注册客户端
在项目的Main子程序中,我注册了类型化客户端和命名客户端(不确定方式是否正确):
Imports Microsoft.Extensions.DependencyInjection Imports Microsoft.Extensions.Hosting Imports Microsoft.Extensions.Http Imports Polly Module MainModule Public Sub Main() Dim seviceColl As New ServiceCollection '--------注册命名HttpClient seviceColl.AddHttpClient("s2sfHTTPClient", Sub(c) 'c.BaseAddress = New Uri("https://api.google.com/") c.DefaultRequestHeaders.Add("Accept", "application/json") End Sub).AddPolicyHandler(PolHolder.httpRetryWithReauthorizationPolicy()) seviceColl.AddHttpClient("GitHub", Sub(httpClient) httpClient.BaseAddress = New Uri("https://api.github.com/") ' using Microsoft.Net.Http.Headers; ' GitHub API需要两个请求头 ''httpClient.DefaultRequestHeaders.Add(HeaderNames.Accept, "application/vnd.github.v3+json") ''httpClient.DefaultRequestHeaders.Add(HeaderNames.UserAgent, "HttpRequestsSample") End Sub) '注册类型化HttpClient seviceColl.AddHttpClient(Of TypedCustomHTTPClient)().SetHandlerLifetime(TimeSpan.FromMinutes(5)).AddPolicyHandler(PolHolder.httpRetryWithReauthorizationPolicy()) '设置生命周期为5分钟 '构建服务提供器 Dim serviceprovider = servicecoll.BuildServiceProvider ' Application.Run(New Form1()) ''//这里用你的主窗体 End Sub End Module
使用时出错
当我尝试使用类型化客户端或者通过CreateClient方法使用命名客户端时,在CreateClient行出现空引用错误:
Private Property _httpClientFactory As IHttpClientFactory Public Function TestQuery2(ByVal soqlQuery As String) As String Dim customclient = _httpClientFactory.CreateClient("s2sfHTTPClient") 'Using customclient._Client '= New HttpClient() ' Dim restRequest As String = InstanceUrl + API_ENDPOINT & "query/?q=" & soqlQuery Dim request = New HttpRequestMessage(HttpMethod.[Get], restRequest) request.Headers.Add("Authorization", "Bearer " & AuthToken) request.Headers.Accept.Add(New MediaTypeWithQualityHeaderValue("application/json")) request.Headers.Add("X-PrettyPrint", "1") Dim response = customclient.SendAsync(request).Result Return response.Content.ReadAsStringAsync().Result 'End Using End Function
请问我哪里操作错了?
解决方案
核心问题
你定义的_httpClientFactory只是一个私有属性,没有从服务容器中获取实例,所以它的值是Nothing(VB.NET的空引用),调用CreateClient自然会报错。
具体修复步骤
全局保存服务容器实例
在Main模块中,构建完服务提供器后,把它保存到全局可访问的变量中:Module MainModule Public Shared ServiceProvider As IServiceProvider Public Sub Main() Dim serviceColl As New ServiceCollection '... 你的HttpClient注册代码 ... ServiceProvider = serviceColl.BuildServiceProvider Application.Run(New Form1()) End Sub End Module注意:修正了你代码中
seviceColl和servicecoll的拼写不一致问题,避免潜在报错在窗体中获取IHttpClientFactory实例
在Form1的构造函数中,从全局服务容器获取IHttpClientFactory:Public Class Form1 Private _httpClientFactory As IHttpClientFactory Public Sub New() InitializeComponent() '从全局服务容器获取实例 _httpClientFactory = MainModule.ServiceProvider.GetService(Of IHttpClientFactory)() End Sub '你的TestQuery2方法放在这里 Public Function TestQuery2(ByVal soqlQuery As String) As String '现在_httpClientFactory不为空 Dim customclient = _httpClientFactory.CreateClient("s2sfHTTPClient") '... 剩余代码不变 ... End Function End Class更规范的依赖注入方式
如果你想严格遵循依赖注入规范,可以让Form1通过构造函数接收IHttpClientFactory,然后从服务容器解析窗体:'修改Main模块代码 Public Sub Main() Dim serviceColl As New ServiceCollection '... HttpClient注册代码 ... '注册Form1,声明它依赖IHttpClientFactory serviceColl.AddTransient(Of Form1)() ServiceProvider = serviceColl.BuildServiceProvider '从服务容器解析Form1,而非直接New Dim mainForm = ServiceProvider.GetService(Of Form1)() Application.Run(mainForm) End Module '修改Form1构造函数 Public Class Form1 Private _httpClientFactory As IHttpClientFactory '构造函数注入IHttpClientFactory Public Sub New(httpClientFactory As IHttpClientFactory) InitializeComponent() _httpClientFactory = httpClientFactory End Sub 'TestQuery2方法不变 End Class
额外优化建议
- 不要用
.Result阻塞异步方法,WinForms中建议使用Async/Await避免UI线程卡顿:Public Async Function TestQuery2(ByVal soqlQuery As String) As Task(Of String) Dim customclient = _httpClientFactory.CreateClient("s2sfHTTPClient") Dim restRequest As String = InstanceUrl + API_ENDPOINT & "query/?q=" & soqlQuery Dim request = New HttpRequestMessage(HttpMethod.[Get], restRequest) request.Headers.Add("Authorization", "Bearer " & AuthToken) request.Headers.Accept.Add(New MediaTypeWithQualityHeaderValue("application/json")) request.Headers.Add("X-PrettyPrint", "1") Dim response = Await customclient.SendAsync(request) Return Await response.Content.ReadAsStringAsync() End Function
内容的提问来源于stack exchange,提问作者MartinT
相关产品推荐
相关产品推荐

