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

.NET MAUI Blazor Hybrid安卓Release构建登录异常排查求助

.NET MAUI Blazor Hybrid Android Release构建登录未捕获异常问题

在.NET MAUI Blazor Hybrid应用中,点击登录按钮调用TryToLogin方法时出现未捕获错误,即使添加了try-catch块也未触发捕获。此问题仅出现在Android Release构建中,Android Debug构建一切正常。

相关代码

private class LoginService
{
    public async Task<User> TryToGetUser(UsersRepository usersRepository, string login, string password)
    {
        try
        {
            var users = await usersRepository.GetAllUsers();
            if (users == null || users.Length == 0) return null;

            foreach (var user in users)
            {
                if (user.login == login || user.email == login)
                {
                    var pasHash = password.GetSHA256Hash();
                    if (user.password == pasHash)
                    {
                        return user;
                    }
                }
            }

        }
        catch (Exception ex)
        {
            await App.Current.MainPage.DisplayAlert("Ошибка", $"Ошибка: {ex}", "Ок");
            return null;
        }
        return null;
    }
}

private async Task TryToLogin()
{

    if (string.IsNullOrWhiteSpace(login))
    {
        await App.Current.MainPage.DisplayAlert("Ошибка", "Пожалуйста введите свой логин или email в поле, что бы продолжить", "Ок");
        return;
    }

    if (string.IsNullOrWhiteSpace(password) || password.Length < Constants.minPassLength)
    {
        await App.Current.MainPage.DisplayAlert("Ошибка", $"Пожалуйста введите свой пароль в поле, что бы продолжить, минимальное количество символов {Constants.minPassLength}", "Ок");
        return;
    }

    isLoading = true;

    LoginService service = new LoginService();

    User currentUser = await Task.Run(async () =>
    {
        return await service.TryToGetUser(usersRepository, login, password);
    });

    if (currentUser == null)
    {
        isLoading = false;
        await App.Current.MainPage.DisplayAlert("Ошибка", "Пользователь с таким логином и паролем не найден, попробуйте проверить регистры", "Ок");
        return;
    }

    userHandler.Save(currentUser);

    await SecureStorage.SetAsync("login", login);
    await SecureStorage.SetAsync("password", password);

    navigationManager.NavigateTo("/home");
}

可能的问题原因

  • Release代码优化吞掉异常:Release模式下编译器启用代码优化,可能修改异常抛出路径,导致局部try-catch无法捕获。异步代码中的异常尤其容易受优化影响。
  • Task.Run的异常处理漏洞:用Task.Run包裹异步方法时,线程调度或上下文切换可能导致内层try-catch无法覆盖所有异常场景,外层又未添加捕获逻辑。
  • App.Current.MainPage为空:Release构建初始化顺序可能与Debug不同,导致App.Current.MainPage为null,此时DisplayAlert调用会抛出二次异常,掩盖原始错误。
  • SHA256哈希方法的平台差异:password.GetSHA256Hash()扩展方法在Release模式下可能因编码、依赖缺失等问题抛出异常,而Debug模式下无此问题。
  • 数据访问层异常:UsersRepository.GetAllUsers()在Release模式下可能出现数据库连接失败、权限不足或序列化错误,这些异常因优化被隐藏。

调试Release构建的方法

  • 启用Release调试符号:在项目属性的Release配置中,将Debug symbols设置为Portable或Full,然后用Visual Studio连接Android设备,以Release模式调试,直接捕获异常堆栈。
  • 添加全局异常捕获:在App.xaml.cs中注册全局异常处理事件,记录未捕获异常到本地文件:
    public App()
    {
        InitializeComponent();
        AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
        TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
    }
    
    private void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
    {
        var logPath = Path.Combine(FileSystem.AppDataDirectory, "task_errors.log");
        File.WriteAllText(logPath, e.Exception.ToString());
        e.SetObserved();
    }
    
    private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        var logPath = Path.Combine(FileSystem.AppDataDirectory, "domain_errors.log");
        File.WriteAllText(logPath, e.ExceptionObject.ToString());
    }
    
  • 替换DisplayAlert为日志记录:在TryToGetUser的catch块中,避免调用UI相关方法,直接写入异常日志,防止二次异常:
    catch (Exception ex)
    {
        var logPath = Path.Combine(FileSystem.AppDataDirectory, "login_errors.log");
        File.AppendAllText(logPath, $"[{DateTime.Now}] {ex.ToString()}\n");
        return null;
    }
    
  • 移除Task.Run直接调用异步方法:TryToGetUser本身是异步方法,无需用Task.Run包裹,减少线程切换带来的上下文问题:
    User currentUser = await service.TryToGetUser(usersRepository, login, password);
    
  • 检查Android权限配置:确保AndroidManifest.xml中添加了必要权限,比如本地存储、数据库访问权限,Release模式下权限验证更严格。
  • 临时禁用代码优化:关闭Release配置的Optimize code选项,测试问题是否消失。若消失,可给关键方法添加[MethodImpl(MethodImplOptions.NoOptimization)]特性针对性禁用优化。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 04:02:04