C# WinForms 崩溃,没有异常

C# WinForms crashes with no Exception

我有一个 C# WinForms 应用程序。

我正在使用 Unity Container nuget 包注入我的服务 classes。如果我在 Program.cs 中获得服务 class 并调用我的网站 api 以使用 odata 验证用户名和密码,它会成功运行。如果我调用 Application.Run(myForm),其中 myForm 是一个 Telerik RadForm,并且异步 运行 相同的调用,应用程序将关闭且不会抛出任何异常。

我正在使用 Application.ThreadException 并注册 Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException) 但这并没有捕捉到任何东西。

导致应用程序崩溃的行是对 System.Net.Http.HttpClient.PostAsync() 的调用。此调用是从位于单独的 .Net Standard 2.0 Class Library 中的服务 class 中进行的。主应用程序是 .NET Framework 4.7.2 Windows Application,UI 控件位于 .NET Framework 4.7.2 Class Library 中。同样,如果在 Telerik RadForm 之外调用,则此调用成功。

在 Telerik RadForm 中,我尝试使用以下方法执行调用:

当我在服务 class 上调用 LoginAsync(...).Result 时,我确实得到了不同的结果。这导致应用程序进入线程锁定状态,但没有使应用程序崩溃。

更新:

有两个RadForm;一个 DashboardForm 和一个 LoginFormProgram.cs 启动仪表板,检查现有的 Bearer 令牌。如果令牌不存在,仪表板会使用 .ShowDialog() 显示登录,以防止在通过身份验证之前使用仪表板。登录然后使用上述服务 class。

如果我没有使用 Application.Run()Program.cs 中启动仪表板,而是启动登录,则验证服务调用成功。

然后我尝试在新线程中从仪表板启动登录,但这导致了与上述相同的问题。

为什么 System.Net.Http.HttpClient.PostAsync() 如果从另一个窗体显示的窗体调用应用程序,它会崩溃应用程序(无一例外)?

计划

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        WinInjectionHelper.Register(UnityConfig.RegisterComponents);

        Application.ThreadException += Application_ThreadException;
        Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);

        Application.Run(new DashboardForm());
    }

    private static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
    {
        MessageBox.Show("Big error...");
    }

仪表板

public partial class DashboardForm : Telerik.WinControls.UI.RadForm, IDashboard
{
    private readonly IProductService _service;

    public DashboardForm()
    {
        this._service = WinInjectionHelper.Generate2<IProductService>();
        this.InitializeComponent();
    }

    private void DashboardForm_Load(object sender, EventArgs e)
    {
        if (this.NotAuthenticated())
        {
            var frm = new LoginForm();

            if (frm.ShowDialog() != DialogResult.OK)
            {
                this.Close();
            }
        }
        else
        {
            //TODO: display error to user
            this.Close();
        }
    }
}

登录

public partial class LoginForm : Telerik.WinControls.UI.RadForm
{
    private const string CLIENT_ID = "...";
    private readonly IAuthenticationService _service;

    public LoginForm()
    {
        this._service = WinInjectionHelper.Generate2<IAuthenticationService>();
        this.InitializeComponent();
    }

    private void btnCancel_Click(object sender, System.EventArgs e)
    {
        this.DialogResult = DialogResult.Cancel;
        this.Close();
    }

    private async void btnLogin_Click(object sender, System.EventArgs e)
    {
        var u = this.txtUsername.Text.Trim();
        var p = this.txtPassword.Text.Trim();

        if (string.IsNullOrWhiteSpace(u))
        {
            MessageBox.Show("Username is required!", "NOTICE", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            return;
        }

        if (string.IsNullOrWhiteSpace(p))
        {
            MessageBox.Show("Password is required!", "NOTICE", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            return;
        }

        try
        {
            var jwt = await this._service.LoginAsync(new Credentials(u, p, CLIENT_ID));

            var identity = new ClaimsIdentity(new[]
            {
                new Claim(ClaimTypes.Name, u),
                new Claim(ClaimTypes.Email, u),
                new Claim(ClaimTypes2.AccessToken, jwt.AccessToken),
            }, "JWT");

            ((GenericPrincipal)Thread.CurrentPrincipal).AddIdentity(identity);

            this.DialogResult = DialogResult.OK;

            this.Close();
        }
        catch
        {
            MessageBox.Show("An error occurred while processing your request.", "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }
}

您可以检查 Windows 事件查看器并查看应用程序以查找崩溃日志。我正在处理的应用程序遇到了同样的问题,这是唯一有任何信息的地方。它实际上帮助我解决了与针对特定 .NET Framework 版本相关的问题。单击左下方的 Window 按钮并在其中键入 "event viewer",然后单击出现的图标。

最简单的方法是 运行 应用程序并使其崩溃,然后立即转到事件查看器,使其位于列表顶部。

我通过先调用登录表单然后在关闭登录之前显示仪表板解决了这个问题,并更改了 program.cs 以便关闭登录不会退出应用程序。这确实需要在应用程序确实需要关闭时调用 Application.Exit()

计划

internal static class Program
{
    [STAThread]
    private static void Main()
    {
        ...

        new LoginForm().Show();

        Application.Run();
    }
}