将Xamarin项目升级到MAUI后调用HttpClient.GetAsync触发NullReferenceException
近期将Xamarin项目升级到MAUI后,调用HttpClient的Get请求时触发NullReferenceException,无法定位根因。已确认HttpClient初始化逻辑,调用方式如下(配图),异常信息如下(配图)。以下是创建HttpClient的控制器基类代码:
public BaseControllerService() { //GetUrl(); AuthorisationRetry = Policy .HandleResult<HttpResponseMessage>(resp => resp.StatusCode == HttpStatusCode.Unauthorized) .RetryAsync(1, async (_, retryCount) => { var answer = await CallRefreshToken(); if (answer is {IsSuccess: true}) return; await _caching.DeleteTokensAsync(); await Shell.Current.Navigation.PopToRootAsync(); await Shell.Current.GoToAsync("//LoginPage"); }); var test = AppSettings.Url.Value; _cookieContainer = new CookieContainer(); var handler = new HttpClientHandler {CookieContainer = _cookieContainer}; _httpClient = new HttpClient(handler) { BaseAddress = new Uri(AppSettings.Url.Value ?? throw new NullReferenceException("AppSettings Url is null")) }; SetHeaders(); } protected async void SetHeaders() { _httpClient.DefaultRequestHeaders.Clear(); var temp = await _caching.GetUserTokenAsync(); if (!string.IsNullOrEmpty(temp)) _httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {temp}"); }
排查方向及修复方案
async void方法引发的异步初始化问题
构造函数中调用async void的SetHeaders,会导致构造函数执行完毕后,SetHeaders内的异步操作仍在后台运行。如果此时立即发起HTTP请求,可能出现_httpClient的请求头尚未设置完成,甚至因异步操作未完成引发未捕获的NullReferenceException。
修复:将SetHeaders改为返回async Task,并通过异步工厂模式初始化BaseControllerService(比如在DI注册时使用AddScoped(async sp => ...)),确保SetHeaders执行完成后再使用_httpClient。_caching字段未初始化
代码中多次调用_caching的方法,但构造函数内未看到该字段的初始化逻辑。如果_caching为null,调用_caching.GetUserTokenAsync()或_caching.DeleteTokensAsync()会直接抛出NullReferenceException。
修复:检查_caching的依赖注入或实例化逻辑,确保在构造函数执行完毕前_caching已被正确初始化。Shell.Current在构造阶段可能为null
MAUI应用启动初期,Shell.Current可能尚未完成初始化,此时在构造函数的重试策略中直接调用Shell.Current.Navigation会引发NullReferenceException。
修复:避免在构造函数中直接依赖Shell.Current,可通过注入INavigation接口,或在重试逻辑中先判断Shell.Current是否为null再执行导航操作:if (Shell.Current != null) { await Shell.Current.Navigation.PopToRootAsync(); await Shell.Current.GoToAsync("//LoginPage"); }AppSettings.Url的空值判断遗漏
代码中var test = AppSettings.Url.Value这一行,如果AppSettings.Url本身为null,会直接抛出NullReferenceException,而非你自定义的异常信息。
修复:先判断AppSettings.Url是否为null,再获取Value:var urlValue = AppSettings.Url?.Value ?? throw new NullReferenceException("AppSettings Url is null"); var test = urlValue; _httpClient = new HttpClient(handler) { BaseAddress = new Uri(urlValue) };
内容的提问来源于stack exchange,提问作者Jonas Van mullem

