List icon 目录

常见异常

本指南介绍在使用 DotNetBrowser 库时可能抛出的常见异常。

初始化异常 

许可证异常 

当许可证检查由于某种原因失败时会抛出这些异常。

  • NoLicenseException 在缺少许可证时抛出。这种情况通常发生在 EngineOptions 中没有设置许可证密钥,以及 DotNetBrowser 无法找到包含许可证密钥的 dotnetbrowser.license 文件时。要解决这种情况,请检查许可证是否 已添加到项目中。
  • InvalidLicenseException 在许可证配置正确但检查失败时抛出。许可证检查失败的确切原因作为异常消息提供。例如,当许可证过期或许可证中的产品绑定与任何命名空间不匹配时,可能会抛出此异常。

例如,可能出现的 InvalidLicenseException 消息之一:DotNetBrowser 许可证检查失败。原因:此产品版本与许可证不兼容。这意味着项目中指定的许可证密钥与引用的 DotNetBrowser 版本不兼容。您需要确保使用正确且有效的密钥。

如若非上述情况,请随时联系我们的销售团队 以获取更新的许可证。

Chromium 二进制文件异常 

当 DotNetBrowser 由于 Chromium 二进制文件丢失且无法恢复而无法启动绑定的 Chromium engine 时,将抛出 ChromiumBinariesMissingException。异常的实际原因作为异常消息提供。例如,当在 Chromium 二进制文件目录中找不到兼容的 Chromium 二进制文件,并且 DotNetBrowser 找不到包含兼容二进制文件的程序集时,可能会抛出此异常。

在单独进程中提取 Chromium 二进制文件失败 

当在程序集中找到 Chromium 二进制文件,但在将其提取到 Chromium 二进制目录时出现问题时,将引发此异常。

在大多数情况下,从 DLL 中提取二进制文件是通过 GZipCompress.exe 执行的,该实用程序是 DotNetBrowser 的一部分。由于某些原因,此实用程序可能无法提取二进制文件。例如,它被第三方应用程序 (防病毒软件或防火墙) 阻止或缺少此操作的权限。在这种情况下会出现以下异常消息:`Failed to extract the Chromium binaries in the separate process.GZipCompress.exe 已退出,代码为 <exit_code>。

发生此异常时,GZipCompress.exe 的详细输出将写入 DotNetBrowser 日志。检查这些日志通常有助于了解故障的实际原因。

其他 Engine 初始化异常 

EngineInitializationException 在初始化 IEngine 实例期间出现错误时抛出。

用户数据目录已被使用 

即使在不同的.NET进程中创建这些 IEngine 实例,也不允许创建指向相同 用户数据目录的两个或多个 IEngine 实例。Chromium 本身不支持这种用例,它会导致不可预测的行为和 Engine 突然崩溃。

因此,当检测到这种情况时,将抛出 EngineInitializationException 并显示以下消息:The user data directory is already in use: <path>

有几种可能的解决方案:

  1. 使用同一个 IEngine 创建多个 IBrowser 实例:

    C#
    VB
    IEngine engine = EngineFactory.Create(engineOptions);
    
    IBrowser browser1 = engine.CreateBrowser();
    IBrowser browser2 = engine.CreateBrowser();
    
    Dim engine As IEngine = EngineFactory.Create(engineOptions)
    
    Dim browser1 As IBrowser = engine.CreateBrowser()
    Dim browser2 As IBrowser = engine.CreateBrowser()
    

  2. 使用不同的用户数据目录创建单独的 IEngine 实例:

    C#
    VB
    IEngine engine1 = EngineFactory.Create(new EngineOptions.Builder
    {
        UserDataDirectory = @"C:\Users\Me\DotNetBrowser1"
    }.Build());
    
    IEngine engine2 = EngineFactory.Create(new EngineOptions.Builder
    {
        UserDataDirectory = @"C:\Users\Me\DotNetBrowser2"
    }.Build());
    
    IBrowser browser1 = engine1.CreateBrowser();
    IBrowser browser2 = engine2.CreateBrowser();
    
    Dim engine1 As IEngine = EngineFactory.Create(New EngineOptions.Builder With 
    {
        .UserDataDirectory = "C:\Users\Me\DotNetBrowser"
    }.Build())
    
    Dim engine2 As IEngine = EngineFactory.Create(New EngineOptions.Builder With 
    {
        .UserDataDirectory = "C:\Users\Me\DotNetBrowser"
    }.Build())
    
    Dim browser1 As IBrowser = engine1.CreateBrowser()
    Dim browser2 As IBrowser = engine2.CreateBrowser()
    

运行时异常 

ObjectDisposedException 

ObjectDisposedException 在尝试使用已被处理的对象时抛出。例如,在处理以下内容时会抛出此异常:

  • 在加载不同的网页后,尝试使用之前缓存的 DOM 元素或 JavaScript 对象;
  • 浏览器中已不存在的某个框架;
  • 在调用 IEngine.Dispose() 后,尝试使用 IEngine 实例,任何由此 Engine 创建的 IBrowser 实例或与这些实例相关的任何其他对象。
  • Chromium 崩溃之后,尝试使用 IEngine 实例,任何由此 Engine 创建的 IBrowser 实例或与这些实例相关的任何其他对象。

ConnectionClosedException 

ConnectionClosedException 在与 Chromium engine 的连接关闭时抛出。此异常通常与 IEngine.Dispose() 方法调用Chromium 崩溃有关。

跨线程操作无效 

当您尝试在 DotNetBrowser 事件上修改 UI 时,您会看到 System.InvalidOperationException 以及以下描述:Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on.

DotNetBrowser 通过单独的线程触发其事件,并且不为此目的使用主 UI 线程。要在 DotNetBrowser 事件上修改 UI,请使用 WinForms 中的 InvokeBeginInvoke 或 WPF 中的 Dispatcher.InvokeDispatcher.BeginInvoke 将执行传递到主 UI 线程。WinForms 中的 Control.InvokeRequired 属性或 WPF 中的 Dispatcher.CheckAccess() 调用可用于检查是否有必要通过执行。

下面的代码示例演示了如何从另一个线程访问 UI。

WinForms 

C#
VB
browser.Navigation.FrameLoadFinished += (s, e) =>
{
    if (e.Frame.IsMain)
    {
        if (InvokeRequired)
        {
            BeginInvoke(new Action(() =>
            {
                this.Title = e.Browser.Url;
            }));
        }
        else
        {
            this.Title = e.Browser.Url;
        }
    }
};
browser.Navigation.LoadUrl("https://www.teamdev.com");
AddHandler browser.Navigation.FrameLoadFinished, Sub(s, e)
    If e.Frame.IsMain Then
        If InvokeRequired Then
            BeginInvoke(New Action(Sub()
                Me.Title = e.Browser.Url
            End Sub))
        Else
            Me.Title = e.Browser.Url
        End If
    End If
End Sub
browser.Navigation.LoadUrl("https://www.teamdev.com")

WPF 

C#
VB
browser.Navigation.FrameLoadFinished += (s, e) =>
{
    if (e.Frame.IsMain)
    {
        if (!Dispatcher.CheckAccess())
        {
            Dispatcher.BeginInvoke(new Action(() =>
            {
                this.Title = e.Browser.Url;
            }));
        }
        else
        {
            this.Title = e.Browser.Url;
        }
    }
};
browser.Navigation.LoadUrl("https://www.teamdev.com");
AddHandler browser.Navigation.FrameLoadFinished, Sub(s, e)
    If e.Frame.IsMain Then
        If Not Dispatcher.CheckAccess() Then
            Dispatcher.BeginInvoke(New Action(Sub()
                Me.Title = e.Browser.Url
            End Sub))
        Else
            Me.Title = e.Browser.Url
        End If
    End If
End Sub
browser.Navigation.LoadUrl("https://www.teamdev.com")

Avalonia UI 

C#
VB
browser.Navigation.FrameLoadFinished += (s, e) =>
{
    if (e.Frame.IsMain)
    {
        if (!Dispatcher.UIThread.CheckAccess())
        {
            Dispatcher.UIThread.InvokeAsync(new Action(() =>
            {
                this.Title = e.Browser.Url;
            }));
        }
        else
        {
            this.Title = e.Browser.Url;
        }
    }
};
browser.Navigation.LoadUrl("https://www.teamdev.com");
AddHandler browser.Navigation.FrameLoadFinished, Sub(s, e)
    If e.Frame.IsMain Then
        If Not Dispatcher.UIThread.CheckAccess() Then
            Dispatcher.UIThread.InvokeAsync(New Action(Sub()
                Me.Title = e.Browser.Url
            End Sub))
        Else
            Me.Title = e.Browser.Url
        End If
    End If
End Sub
browser.Navigation.LoadUrl("https://www.teamdev.com")