You need to enable JavaScript to run this app. Xamarin.Forms 无法从服务类异步方法获取返回值到MainPage实现数据过滤
优惠活动
大模型
产品
解决方案
定价
更多

Xamarin.Forms 无法从服务类异步方法获取返回值到MainPage实现数据过滤

核心问题定位
  • 调用await myCourse.getCourses()时未接收方法返回值,异步执行完成后的返回对象被直接丢弃,这是拿不到数据的最直接原因
  • 调用时机不合理:MainPage构造函数执行时就触发CheckCourseComplete(),此时用户尚未输入任何内容,校验逻辑没有可匹配的依据
  • 异步方法误用:CheckCourseComplete使用async void签名,这类方法无法被其他代码安全等待,执行中抛出的异常会直接导致应用崩溃
符合单一职责原则的实现方案

整体逻辑严格拆分职责边界,不改动原有CourseService的核心定位:

  • CourseService 仅承担「API请求、JSON反序列化」的纯数据获取职责,不加入任何业务校验、用户交互逻辑
  • 独立的校验方法单独承担「拉取全量课程数据、匹配用户输入的Id、触发页面跳转/错误提示」的逻辑,和服务层完全解耦

调整后的代码实现

优化后的CourseService(不改变原有职责)

public class CourseService : ICourseService
{
    // 静态复用HttpClient,避免每次请求新建实例造成的Socket泄漏
    private static readonly HttpClient client = new HttpClient();
    string Base_Url = "https://www.test.com/api/TheCourse";
    
    public async Task<ObservableCollection<Course>> getCourses()
    {
        try
        {
            HttpResponseMessage responseMessage = await client.GetAsync(Base_Url);
            if (responseMessage.StatusCode == System.Net.HttpStatusCode.OK)
            {
                var result = await responseMessage.Content.ReadAsStringAsync();
                var deserializedCourses = JsonConvert.DeserializeObject<ObservableCollection<Course>>(result);
                return deserializedCourses;
            }
            return null;
        }
        catch (Exception)
        {
            throw;
        }
    }
}

调整后的MainPage逻辑

namespace CourseMobile
{
    public partial class MainPage : ContentPage
    {
        private string _getEntryText;
        // 页面内持有服务实例,避免每次校验都新建对象
        private readonly ICourseService _courseService;

        public MainPage()
        {
            InitializeComponent();
            _courseService = new CourseService();
            BindingContext = new CourseViewModel();
            // 移除构造函数里提前调用CheckCourseComplete的逻辑
        }

        public string GetEntryText 
        {
            get => _getEntryText;
            set => _getEntryText = value;
        }

        // 按钮点击事件保留async void签名,符合Xamarin事件处理规范
        public async void OnOkGetCourseButton(object sender, EventArgs e)
        {
            var inputtedCourseNumber = GetEntryText?.Trim();
            if (string.IsNullOrEmpty(inputtedCourseNumber))
            {
                await DisplayAlert("", "Please enter your Course number", "OK");
                return;
            }
            // 拿到有效用户输入后,再触发独立校验逻辑
            await CheckCourseComplete(inputtedCourseNumber);
        }

        void Entry_TextChanged(object sender, TextChangedEventArgs e)
        {
            GetEntryText = e.NewTextValue;
        }

        // 校验方法改为async Task签名,支持异步等待,规避async void的崩溃风险
        public async Task CheckCourseComplete(string userInputCourseId)
        {
            // 关键修复:接收getCourses的返回值,不丢弃数据
            var allCourses = await _courseService.getCourses();
            
            // 接口返回空值的兜底处理
            if (allCourses == null || allCourses.Count == 0)
            {
                await DisplayAlert("Error", "Failed to load course data, please try later", "OK");
                return;
            }

            // 类型转换兜底:根据Course.Id的实际类型适配用户输入
            // 示例中假设Course.Id为int类型,可根据实际模型调整
            if (!int.TryParse(userInputCourseId, out int inputId))
            {
                await DisplayAlert("Error", "Please enter a valid numeric course number", "OK");
                return;
            }

            // 匹配对应Id的课程条目
            var matchedCourse = allCourses.FirstOrDefault(c => c.Id == inputId);

            if (matchedCourse != null)
            {
                // 匹配成功:将课程对象传递到详情页
                await Navigation.PushAsync(new CourseDetailPage(matchedCourse));
            }
            else
            {
                // 匹配失败:弹出提示
                await DisplayAlert("Notice", "The course number you entered does not exist", "OK");
            }
        }
    }
}
方案说明
  • 所有用户输入校验、数据匹配、页面交互的逻辑全部集中在CheckCourseComplete独立方法中,没有侵入CourseService的实现,完全满足单一职责的设计要求
  • 解决了之前调用异步方法丢弃返回值的问题,修正了不合理的调用时机,规避了async void导致的应用崩溃风险
  • 增加了必要的空值、类型转换兜底,避免因为输入格式不对、接口返回异常导致的逻辑错误

内容的提问来源于stack exchange,提问作者Alice

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.27 23:24:04