GraphQL.Client无返回结果但服务器已完成请求问题求助
问题分析与解决方案
核心问题:同步阻塞异步代码导致死锁
你的代码在ViewModel构造函数中使用RunAsync().GetAwaiter().GetResult()同步等待异步任务,这会引发死锁:
- MAUI的UI线程会被
GetResult()阻塞,等待异步任务完成 - 而
SendQueryAsync执行完成后,需要回到UI线程继续处理后续逻辑,却被阻塞的主线程卡住,最终形成循环等待,导致程序无限挂起。
同时你的GraphQL响应模型和查询结果不匹配,即使服务器返回数据,也无法正确反序列化,这会进一步掩盖问题。
分步解决方案
1. 重构ViewModel,移除构造函数中的同步阻塞
将异步初始化逻辑从构造函数中分离,改用异步方法调用:
public class ViewModel_L { public Document ErpDocument { get; set; } private static readonly string Url = "https://1eaa-98-103-130-98.ngrok-free.app"; private static string qlQuery = @"{ products(filter:{and: [{fac: {eq: ""Default""}}, {fpartno: {eq: ""WF201W""}}, {frev: {eq: ""000""}} ]}) { parts : items { id1 : fpartno id2 : frev name : fdescript } } }"; // 构造函数仅做基础初始化 public ViewModel_L() { ErpDocument = new Document(); // 提前初始化避免空引用 } // 异步初始化方法 public async Task InitializeAsync() { var graphQLOptions = new GraphQLHttpClientOptions { EndPoint = new Uri($"{Url}/graphql", UriKind.Absolute), Timeout = TimeSpan.FromSeconds(10) // 添加超时,避免无限等待 }; // 使用using自动释放客户端资源 using var graphQLHttpClient = new GraphQLHttpClient(graphQLOptions, new NewtonsoftJsonSerializer()); var productRequest = new GraphQLRequest { Query = qlQuery }; try { var graphQLResponse = await graphQLHttpClient.SendQueryAsync<RootObject>(productRequest); Debug.Print("查询完成,开始解析结果"); if (graphQLResponse.Data?.Products?.Parts != null) { var firstDoc = graphQLResponse.Data.Products.Parts.FirstOrDefault(); if (firstDoc != null) { ErpDocument.Id = $"{firstDoc.id1}:{firstDoc.id2}"; ErpDocument.Name = firstDoc.name; ErpDocument.Type = "Part"; ErpDocument.TypeShort = ErpDocument.Type[..1]; ErpDocument.Onhand = 0; ErpDocument.Color = MauiProgram.colorPart; } } else { Debug.WriteLine("未找到匹配的零件"); } } catch (Exception ex) { Debug.Print($"查询出错: {ex.Message}"); } } // 修正响应模型,严格匹配查询结构 public class RootObject { public Products Products { get; set; } } public class Products { [JsonPropertyName("parts")] // 匹配查询中的别名 public getDocument[] Parts { get; set; } } public class getDocument { [JsonPropertyName("id1")] public string id1 { get; set; } [JsonPropertyName("id2")] public string id2 { get; set; } [JsonPropertyName("name")] public string name { get; set; } } // 其余类(Document、Onhand、Location)保持不变 }
2. 在UI层异步调用初始化方法
在页面的代码后台中,异步初始化ViewModel:
protected override async void OnAppearing() { base.OnAppearing(); var viewModel = new ViewModel_L(); await viewModel.InitializeAsync(); BindingContext = viewModel; }
3. 额外优化点
- 移除静态字段
erpDoc,改用实例属性ErpDocument,避免线程安全问题 - 给GraphQL请求添加超时时间,防止因网络问题无限等待
- 使用
JsonPropertyName特性明确指定属性与查询字段的映射,避免反序列化失败
内容的提问来源于stack exchange,提问作者BumpaRoy
相关产品推荐
相关产品推荐

