You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 01:52:25