常见异常
本指南描述了使用 DotNetBrowser 库时可能抛出的常见异常。
初始化异常
许可证异常
当许可证检查由于某种原因失败时会抛出这些异常。
NoLicenseException
在缺少许可证时抛出 。 这种情况通常发生在EngineOptions
中没有设置许可证密钥,以及 DotNetBrowser 无法找到包含许可证密钥的dotnetbrowser.license
文件时。 要解决这种情况,请检查许可证是否已添加到项目中。InvalidLicenseException
在许可证配置正确但检查失败时抛出。 许可证检查失败的确切原因作为异常消息提供。 例如,当许可证过期或许可证中的产品绑定与任何命名空间不匹配时,可能会抛出此异常。
例如,可能的 InvalidLicenseException
消息之一:DotNetBrowser license check failed. Reason: This product version is incompatible with the license.
这意味着项目中指定的许可证密钥与引用的 DotNetBrowser 版本不兼容。 您需要确保使用正确且有效的密钥。
如若非上述情况,请随时联系我们的销售团队 sales@teamdev.com 以获取更新的许可证。
Chromium 二进制文件异常
当 DotNetBrowser 由于 Chromium 二进制文件丢失且无法恢复而无法启动绑定的 Chromium 引擎时,将抛出 ChromiumBinariesMissingException
。 异常的实际原因作为异常消息提供。 例如,当在 Chromium 二进制文件目录中找不到兼容的 Chromium 二进制文件并且 DotNetBrowser 找不到包含兼容二进制文件的程序集时,会抛出此异常。
无法在单独的进程中提取 Chromium 二进制文件
当在程序集中找到 Chromium 二进制文件时会抛出此异常,但是,将它们提取到 Chromium 二进制文件目录时会出现问题。
在大多数情况下,从 DLL 中提取二进制文件是通过 GZipCompress.exe
执行的,该实用程序是 DotNetBrowser 的一部分。 由于某些原因,此实用程序可能无法提取二进制文件。 例如,如果它被第三方应用程序(防病毒或防火墙)阻止或缺少此操作的权限。 在这种情况下会出现以下异常消息:Failed to extract the Chromium binaries in the separate process. GZipCompress.exe has exited with code <exit_code>.
发生此异常时, GZipCompress.exe
的详细输出将写入 DotNetBrowser 日志。 检查这些日志通常有助于了解故障的实际原因。
其他引擎初始化异常
EngineInitializationException
在初始化 IEngine
实例期间出现错误时抛出。
用户数据目录已被使用
不允许创建两个或更多指向同一用户数据目录的 IEngine
实例,即使这些 IEngine
实例是在单独的 .NET 进程中创建的。 Chromium 本身不支持此类用例,并导致不可预测的行为和引擎突然崩溃。
因此,当检测到这种情况时,将抛出 EngineInitializationException
并显示以下消息:The user data directory is already in use: <path>
有几种可能的解决方案:
- 使用同一个
IEngine
创建多个IBrowser
实例: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()
- 使用不同的用户数据目录创建单独的
IEngine
实例: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
实例,此引擎创建的任何IBrowser
实例,或调用IEngine.Dispose()
后与这些实例相关的任何其他对象;IEngine
实例,此引擎创建的任何IBrowser
实例,或 Chromium 崩溃后与这些实例相关的任何其他对象。
ConnectionClosedException
当与 Chromium 引擎的连接出现关闭时,将抛出 ConnectionClosedException
。 此异常通常与 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 中的 Invoke
和 BeginInvoke
或 WPF 中的 Dispatcher.Invoke
和Dispatcher.BeginInvoke
将执行传递到主 UI 线程。 WinForms 中的 Control.InvokeRequired
属性或 WPF 中的 Dispatcher.CheckAccess()
调用可用于检查是否有必要通过执行。
下面的代码示例演示了如何从另一个线程访问 UI。
WinForms
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
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")