Introduction
Installation
Guides
- Engine
- Profile
- Browser
- BrowserView
- Navigation
- Content
- Context menu
- DOM
- JavaScript
- Pop-ups
- Dialogs
- Downloads
- Network
- Cache
- Cookies
- Proxy
- Authentication
- Permissions
- Plugins
- Printing
- Passwords
- User data profiles
- Credit cards
- Media
- Zoom
- Spell checker
- Deployment
- Chromium
Troubleshooting
- Logging
- Common exceptions
- Application does not terminate
- Video does not play
- Cannot sign in to Google account
- User data is not stored
- Color scheme
- Startup failure
- Slow startup on Windows
- Unresponsive .NET Application
- Unexpected Chromium process termination
- Unexpected behavior
- Windows 7/8/8.1 end of support
Migration
Migrating from 1.x to 2.0
DotNetBrowser version 2.0 brings major improvements to both internal features and public API of the library. This guide shows how to make your application code written with DotNetBrowser version 1.x compatible with version 2.0.
Overview
Why migrate?
We recommend you to update your code to the latest version because all the new features, Chromium upgrades, support of new operating systems and .NET Framework versions, bug fixes, security patches, performance, and memory usage enhancements are applied on top of the latest version.
How long does it take?
From our experience, upgrade to a new major version may take from a couple of hours to a few days depending on the number of the features you use in your application. As usual, we strongly recommend to test your software after the upgrade in all the environments it supports.
Getting help
Please check out the FAQ section at the end of this guide. Maybe the answer to your question is already there.
In case you did not find the answer in this guide and you need assistance with migration, please contact us. We will be happy to help.
Key changes
API & architecture
In DotNetBrowser version 2.0, the architecture of the library has been improved. Now DotNetBrowser allows you to create two absolutely independent IBrowser
instances and control their life cycle. Along with this internal architecture change, public API has been improved and extended with new features.
Refer to the Mapping section to find out how the main functionality of version 1.x maps to version 2.0.
System requirements
Starting with this version, DotNetBrowser no longer supports .NET Framework 4.0. Current system requirements are available here.
Assemblies
The structure of the library has changed. Now the library consists of the following assemblies:
DotNetBrowser.dll
— data classes and interfaces;DotNetBrowser.Core.dll
— core implementation;DotNetBrowser.Logging.dll
— DotNetBrowser Logging API implementation;DotNetBrowser.WinForms.dll
— classes and interfaces for embedding into a WinForms application;DotNetBrowser.Wpf.dll
— classes and interfaces for embedding into a WPF app;DotNetBrowser.Chromium.Win-x86.dll
— Chromium 32-bit binaries for Windows;DotNetBrowser.Chromium.Win-x64.dll
— Chromium 64-bit binaries for Windows.
Basic concepts
The way to create and dispose various objects has changed in the new API.
To create an IEngine
object use the EngineFactory.Create()
static method:
IEngine engine = EngineFactory.Create(options);
Dim engine As IEngine = EngineFactory.Create(options)
To create an immutable data object use the <Object>.Builder.Build()
method:
EngineOptions engineOptions = new EngineOptions.Builder()
{
Language = Language.EnglishUs
}.Build();
Dim engineOptions As EngineOptions = New EngineOptions.Builder() With {
.Language = Language.EnglishUs
}.Build()
Every object that should be disposed manually implements the IDisposable
interface, for example, IBrowser
. To dispose the object, call the IDisposable.Dispose()
method:
browser.Dispose();
browser.Dispose()
Some service objects depend on the other service objects. When you dispose a service object, all the service objects depending on it will be disposed automatically, so you do not need to dispose them manually. Refer to Architecture guide for more details about the key objects and their interaction principles.
Handlers
Handlers are used to process various callbacks from the Chromium engine and modify its behavior.
v1.x
In DotNetBrowser version 1.x, handlers are usually implemented as the properties of interface types, such as PrintHandler
, PermissionHandler
, LoadHandler
, and others.
v2.0
In DotNetBrowser version 2.0, all the handlers are implemented as the properties of type IHandler<in T>
or IHandler<in T, out TResult>
, where T
is the parameters type, TResult
is the result type. The result returned from the handler will be used to notify the Chromium engine and affect its behavior.
To register and unregister a handler, use corresponding property setters and getters.
There are default implementations of the IHandler<in T, out TResult>
interface:
Handler<T, TResult>
class allows wrapping lambdas and method groups;AsyncHandler<T, TResult>
class allows wrapping async lambdas and method groups, or lambdas and method groups that returnTask<TResult>
.
In some cases, engine appears blocked until the handler returns the result. In case of using the AsyncHandler
, engine appears blocked until the result is available in the returned task.
Thread safety
The library is not thread-safe, so please avoid working with the library from different threads at the same time.
Licensing
In DotNetBrowser version 2.0 the license format and the way how the library checks the license has been improved.
v1.x
In previous version, the license represented a teamdev.licenses
text file. This text file contained the plain text of the license. To set up the license, you had to include this text file in your project as an EmbeddedResource
or copy it to the working directory of the .NET application.
Project license was tied to a fully qualified type name (for example, Company.Product.MyClass
). It could be any class of your application. The only requirement was that this class must be included in the classpath of your .NET app where you used DotNetBrowser.
v2.0
Now, the library requires a license key that represents a string with combination of letters and digits. You can add the license to your project through the API.
It is also possible to put this string to a text file named dotnetbrowser.license
and include this text file in your project as an EmbeddedResource
or copy it to the working directory of the .NET application.
The Project license is tied to a namespace now. The namespace is expected to be in the Company.Product.Namespace
format. It should be a top-level namespace for the classes where you create an IEngine
instance.
For example, if the Project license is tied to the Company.Product
namespace, then you can create IEngine
instances only in the classes located in this namespace or its inner namespaces, e. g. Company.Product.Namespace
.
The IEngine
was introduced in DotNetBrowser 2. We recommend that you check out the guide that describes the new architecture, how to create an IEngine
and manage multiple IBrowser
s lifecycle.
You can work with the created IEngine
instance and make calls to the library’s API from the classes located in other namespaces without any restrictions.
Dropped functionality
Starting with this version DotNetBrowser no longer supports .NET Framework 4.
In the new version, the following functionality has been temporarily dropped:
Notifications
API;PasswordManager
API;- Printing API (restored in DotNetBrowser 2.4);
- HTML5 Application Cache API;
- Displaying the
BeforeUnload
dialog when disposingIBrowser
(restored in DotNetBrowser 2.5); - Drag&Drop
IDataObject
API (restored in DotNetBrowser 2.3); - Intercepting Drag&Drop events (restored in DotNetBrowser 2.3);
- Intercepting and suppressing touch and gesture events (touch events interception restored in DotNetBrowser 2.11).
We are going to provide the alternatives of the above-mentioned features in the next versions.
Mapping
In this section, we describe how the main functionality of DotNetBrowser version 1.x maps to version 2.0.
Engine
Creating Engine
1.x
The IEngine
is not a part of the public API. It is created internally when the first Browser
instance is created in the application. Only one IEngine
can be created and used in the application.
2.0
The IEngine
is a part of the public API now. You can create and use multiple Engine
instances in the application. To create an Engine
instance with the required options, use the code sample below:
IEngine engine = EngineFactory.Create(new EngineOptions.Builder
{
// The language used on the default error pages and GUI.
Language = Language.EnglishUs,
// The absolute path to the directory where the data
// such as cache, cookies, history, GPU cache, local
// storage, visited links, web data, spell checking
// dictionary files, etc. is stored.
UserDataDirectory = @"C:\Users\Me\DotNetBrowser"
}.Build());
Dim engine As IEngine = EngineFactory.Create(New EngineOptions.Builder With {
' The language used on the default error pages and GUI.
.Language = Language.EnglishUs,
' The absolute path to the directory where the data
' such as cache, cookies, history, GPU cache, local
' storage, visited links, web data, spell checking
' dictionary files, etc. is stored.
.UserDataDirectory = "C:\Users\Me\DotNetBrowser"
}.Build())
Each IEngine
instance runs a separate native process where Chromium with the provided options is created and initialized. The native process communicates with the .NET process using the Inter-Process Communication (IPC) bridge. If the native process is unexpectedly terminated because of a crash, the .NET process will continue running.
You can use the following notification to find out when the IEngine
is unexpectedly terminated, so that you can re-create the Engine and restore the IBrowser
instances:
engine.Disposed += (s, e) =>
{
long exitCode = e.ExitCode;
if(exitCode != 0)
{
// Clear all the allocated resources and re-create the Engine.
}
};
AddHandler engine.Disposed, Sub(s, e)
Dim exitCode As Long = e.ExitCode
If exitCode <> 0 Then
' Clear all the allocated resources and re-create the Engine.
End If
End Sub
Closing Engine
1.x
The IEngine
is disposed automatically when the last Browser
instance is disposed in the application.
2.0
The IEngine
should be disposed manually using the Dispose()
method when it is no longer required:
engine.Dispose();
engine.Dispose()
When the IEngine
is disposed, all its IBrowser
instances are disposed automatically. Any attempt to use an already disposed IEngine
leads to an exception.
To find out when the IEngine
is disposed, use the following event:
engine.Disposed += (s, e) => {};
AddHandler engine.Disposed, Sub(s, e)
End Sub
Browser
Creating a browser
1.x
Browser browser = BrowserFactory.Create();
Dim browser As Browser = BrowserFactory.Create()
2.0
IBrowser browser = engine.CreateBrowser();
Dim browser As IBrowser = engine.CreateBrowser()
Creating a browser with options
1.x
BrowserContextParams parameters = new BrowserContextParams(@"C:\Users\Me\DotNetBrowser")
{
StorageType = StorageType.MEMORY
};
BrowserContext context = new BrowserContext(parameters);
Browser browser = BrowserFactory.Create(context, BrowserType.LIGHTWEIGHT);
Dim parameters As BrowserContextParams =
New BrowserContextParams("C:\Users\Me\DotNetBrowser") With {
.StorageType = StorageType.MEMORY
}
Dim context As BrowserContext = New BrowserContext(parameters)
Dim browser As Browser = BrowserFactory.Create(context, BrowserType.LIGHTWEIGHT)
2.0
The BrowserContext
functionality has been moved to IEngine
. Thus, the same code should be replaced with the code sample below:
IEngine engine = EngineFactory.Create(new EngineOptions.Builder
{
IncognitoEnabled = true,
RenderingMode = RenderingMode.OffScreen,
UserDataDirectory = @"C:\Users\Me\DotNetBrowser"
}.Build());
IBrowser browser = engine.CreateBrowser();
Dim engine As IEngine = EngineFactory.Create(New EngineOptions.Builder With {
.IncognitoEnabled = True,
.RenderingMode = RenderingMode.OffScreen,
.UserDataDirectory = "C:\Users\Me\DotNetBrowser"
}.Build())
Dim browser As IBrowser = engine.CreateBrowser()
Disposing a browser
1.x
browser.Dispose();
browser.Dispose()
2.0
browser.Dispose();
browser.Dispose()
Responsive/Unresponsive
1.x
browser.RenderResponsiveEvent += (s, e ) => {};
browser.RenderUnresponsiveEvent += (s, e) => {};
AddHandler browser.RenderResponsiveEvent, Sub(s, e)
End Sub
AddHandler browser.RenderUnresponsiveEvent, Sub(s, e)
End Sub
2.0
browser.BrowserBecameResponsive += (s, e ) => {};
browser.BrowserBecameUnresponsive += (s, e) => {};
AddHandler browser.BrowserBecameResponsive, Sub(s, e)
End Sub
AddHandler browser.BrowserBecameUnresponsive, Sub(s, e)
End Sub
BrowserView
In DotNetBrowser version 1.x, creating a BrowserView
with its default constructor leads to initializing a bound Browser
instance in the same thread. As a result, the main UI thread may appear blocked until the Browser
instance is created and initialized, and this may take a significant amount of time.
In DotNetBrowser version 2.0, creating an IBrowserView
implementation with its default constructor creates a UI control that is not initially bound to any browser.
The connection with a specific IBrowser
instance is established when it is necessary by calling InitializeFrom(IBrowser)
extension method.
The IBrowserView
implementations do not dispose the connected IBrowser
or IEngine
instances when the application is closed. As a result, the browser and engine will appear alive even after all the application windows are closed and prevent the application from terminating. To handle this case, dispose IBrowser
or IEngine
instances during your application shutdown.
Creating WinForms BrowserView
1.x
using DotNetBrowser.WinForms;
// ...
BrowserView view = new WinFormsBrowserView();
Imports DotNetBrowser.WinForms
' ...
Dim view As BrowserView = New WinFormsBrowserView()
2.0
using DotNetBrowser.WinForms;
// ...
BrowserView view = new BrowserView();
view.InitializeFrom(browser);
Imports DotNetBrowser.WinForms
' ...
Dim view As BrowserView = New BrowserView()
view.InitializeFrom(browser)
Creating WPF BrowserView
1.x
using DotNetBrowser.WPF;
// ...
BrowserView view = new WPFBrowserView(browser);
Imports DotNetBrowser.WPF
' ...
Dim view As BrowserView = New WPFBrowserView()
2.0
using DotNetBrowser.Wpf;
// ...
BrowserView view = new BrowserView();
view.InitializeFrom(browser);
Imports DotNetBrowser.Wpf
' ...
Dim view As BrowserView = New BrowserView()
view.InitializeFrom(browser)
Frame
Working with frame
1.x
A web page may consist of the main frame including multiple sub-frames. To perform an operation with a frame, pass the frame’s identifier to the corresponding method:
// Get HTML of the main frame.
browser.GetHTML();
// Get HTML of the all frames.
foreach (long frameId in browser.GetFramesIds()) {
string html = browser.GetHTML(frameId);
}
' Get HTML of the main frame.
browser.GetHTML()
' Get HTML of the all frames.
For Each frameId As Long In browser.GetFramesIds()
Dim html As String = browser.GetHTML(frameId)
Next
2.0
The IFrame
is a part of the public API now. You can work with the frame through the IFrame
instance:
// Get HTML of the main frame if it exists.
string html = browser.MainFrame?.Html;
// Get HTML of all the frames.
foreach (IFrame frame in browser.AllFrames)
{
string html = frame.Html;
}
' Get HTML of the main frame if it exists.
Dim html As String = browser.MainFrame?.Html
' Get HTML of all the frames.
For Each frame As IFrame In browser.AllFrames
Dim html As String = frame.Html
Next
Navigation
Loading URL
1.x
browser.LoadURL("https://www.google.com");
browser.LoadURL("https://www.google.com")
2.0
browser.Navigation.LoadUrl("https://www.google.com");
browser.Navigation.LoadUrl("https://www.google.com")
Loading HTML
1.x
browser.LoadHTML("<html><body></body></html>");
browser.LoadHTML("<html><body></body></html>")
2.0
browser.MainFrame?.LoadHtml("<html><body></body></html>"));
browser.MainFrame?.LoadHtml("<html><body></body></html>"))
Navigation events
Start loading
1.x
browser.StartLoadingFrameEvent += (s, e) =>
{
string url = e.ValidatedURL;
};
AddHandler browser.StartLoadingFrameEvent, Sub(s, e)
Dim url As String = e.ValidatedURL
End Sub
2.0
browser.Navigation.NavigationStarted += (s, e) =>
{
string url = e.Url;
};
AddHandler browser.Navigation.NavigationStarted, Sub(s, e)
Dim url As String = e.Url
End Sub
Finish loading
1.x
browser.FinishLoadingFrameEvent+= (s, e) =>
{
string html = browser.GetHTML(e.FrameId);
};
AddHandler browser.FinishLoadingFrameEvent, Sub(s, e)
Dim html As String = browser.GetHTML(e.FrameId)
End Sub
2.0
browser.Navigation.FrameLoadFinished += (s, e) =>
{
string html = e.Frame.Html;
};
AddHandler browser.Navigation.FrameLoadFinished, Sub(s, e)
Dim html As String = e.Frame.Html
End Sub
Fail loading
1.x
browser.FailLoadingFrameEvent += (s, e) =>
{
NetError errorCode = e.ErrorCode;
};
AddHandler browser.FailLoadingFrameEvent, Sub(s, e)
Dim errorCode As NetError = e.ErrorCode
End Sub
2.0
browser.Navigation.FrameLoadFailed += (s, e) =>
{
NetError error = e.ErrorCode;
};
or
browser.Navigation.NavigationFinished += (s, e) =>
{
NetError error = e.ErrorCode;
};
AddHandler browser.Navigation.FrameLoadFailed, Sub(s, e)
Dim errorCode As NetError = e.ErrorCode
End Sub
or
AddHandler browser.Navigation.NavigationFinished, Sub(s, e)
Dim errorCode As NetError = e.ErrorCode
End Sub
Network
Configuring User-Agent
1.x
BrowserPreferences.SetUserAgent("My User-Agent");
BrowserPreferences.SetUserAgent("My User-Agent")
2.0
IEngine engine = EngineFactory.Create(new EngineOptions.Builder
{
UserAgent = "My User-Agent"
}
.Build());
Dim engine As IEngine = EngineFactory.Create(New EngineOptions.Builder With {
.UserAgent = "My User-Agent"
}.Build())
Configuring Accept-Language
1.x
browserContext.AcceptLanguage = "fr, en-gb;q=0.8, en;q=0.7";
browserContext.AcceptLanguage = "fr, en-gb;q=0.8, en;q=0.7"
2.0
engine.Network.AcceptLanguage = "fr, en-gb;q=0.8, en;q=0.7";
engine.Network.AcceptLanguage = "fr, en-gb;q=0.8, en;q=0.7"
Configuring proxy
1.x
ProxyConfig proxyConfig = browserContext.ProxyConfig;
browserContext.ProxyConfig = new CustomProxyConfig("http-proxy-server:80");
Dim proxyConfig As ProxyConfig = browserContext.ProxyConfig
browserContext.ProxyConfig = New CustomProxyConfig("http-proxy-server:80")
2.0
engine.Proxy.Settings = new CustomProxySettings("http-proxy-server:80");
engine.Proxy.Settings = New CustomProxySettings("http-proxy-server:80")
Redirecting URL request
1.x
class MyNetworkDelegate : DefaultNetworkDelegate
{
public override void OnBeforeURLRequest(BeforeURLRequestParams parameters)
{
parameters.SetURL("https://www.google.com");
}
}
// ...
browserContext.NetworkService.NetworkDelegate = new MyNetworkDelegate();
Class MyNetworkDelegate
Inherits DefaultNetworkDelegate
Public Overrides Sub OnBeforeURLRequest(ByVal parameters As BeforeURLRequestParams)
parameters.SetURL("https://www.google.com")
End Sub
End Class
' ...
browserContext.NetworkService.NetworkDelegate = New MyNetworkDelegate()
2.0
engine.Network.SendUrlRequestHandler =
new Handler<SendUrlRequestParameters, SendUrlRequestResponse>((e) =>
{
return SendUrlRequestResponse.Override("https://www.google.com");
});
engine.Network.SendUrlRequestHandler =
New Handler(Of SendUrlRequestParameters, SendUrlRequestResponse)(
Function(e) SendUrlRequestResponse.Override("https://www.google.com"))
Overriding HTTP headers
1.x
class MyNetworkDelegate : DefaultNetworkDelegate
{
public override void OnBeforeSendHeaders(BeforeSendHeadersParams parameters)
{
HttpHeadersEx headers = params.HeadersEx;
headers.SetHeader("User-Agent", "MyUserAgent");
headers.SetHeader("Content-Type", "text/html");
}
}
// ...
browserContext.NetworkService.NetworkDelegate = new MyNetworkDelegate();
Class MyNetworkDelegate
Inherits DefaultNetworkDelegate
Public Overrides Sub OnBeforeSendHeaders(parameters As BeforeSendHeadersParams)
Dim headers As HttpHeadersEx = params.HeadersEx
headers.SetHeader("User-Agent", "MyUserAgent")
headers.SetHeader("Content-Type", "text/html")
End Sub
End Class
' ...
browserContext.NetworkService.NetworkDelegate = New MyNetworkDelegate()
2.0
engine.Network.SendHeadersHandler =
new Handler<SendHeadersParameters, SendHeadersResponse>((e) =>
{
return SendHeadersResponse.OverrideHeaders(new[] {
new HttpHeader("User-Agent", "MyUserAgent"),
new HttpHeader("Content-Type", "text/html")
});
});
engine.Network.SendHeadersHandler =
New Handler(Of SendHeadersParameters, SendHeadersResponse)(
Function(e) SendHeadersResponse.OverrideHeaders(
{New HttpHeader("User-Agent", "MyUserAgent"),
New HttpHeader("Content-Type", "text/html")}))
Intercepting URL requests
1.x
class MyProtocolHandler : IProtocolHandler
{
public IUrlResponse Handle(IUrlRequest request)
{
string html = "<html><body><p>Hello there!</p></body></html>";
IUrlResponse response = new UrlResponse(Encoding.UTF8.GetBytes(html));
response.Headers.SetHeader("Content-Type", "text/html");
return response;
}
}
// ...
browser.Context.ProtocolService.Register("https", new MyProtocolHandler());
Class MyProtocolHandler
Inherits IProtocolHandler
Public Function Handle(ByVal request As IUrlRequest) As IUrlResponse
Dim html As String = "<html><body><p>Hello there!</p></body></html>"
Dim response As IUrlResponse = New UrlResponse(Encoding.UTF8.GetBytes(html))
response.Headers.SetHeader("Content-Type", "text/html")
Return response
End Function
End Class
' ...
browser.Context.ProtocolService.Register("https", New MyProtocolHandler())
2.0
network.InterceptRequestHandler =
new Handler<InterceptRequestParameters, InterceptRequestResponse>(p =>
{
if (!p.UrlRequest.Url.StartsWith("https"))
{
return InterceptRequestResponse.Proceed();
}
UrlRequestJobOptions options = new UrlRequestJobOptions
{
Headers = new List<HttpHeader>
{
new HttpHeader("Content-Type", "text/plain"),
new HttpHeader("Content-Type", "charset=utf-8")
}
};
UrlRequestJob job = network.CreateUrlRequestJob(p.UrlRequest, options);
Task.Run(() =>
{
// The request processing is performed in a background thread
// in order to avoid freezing the web page.
string html = "<html><body><p>Hello there!</p></body></html>";
job.Write(Encoding.UTF8.GetBytes(html));
job.Complete();
});
return InterceptRequestResponse.Intercept(job);
});
network.InterceptRequestHandler =
New Handler(Of InterceptRequestParameters, InterceptRequestResponse)(Function(p)
If Not p.UrlRequest.Url.StartsWith("https") Then
Return InterceptRequestResponse.Proceed()
End If
Dim options = New UrlRequestJobOptions With {
.Headers = New List(Of HttpHeader) From {
New HttpHeader("Content-Type", "text/plain"),
New HttpHeader("Content-Type", "charset=utf-8")
}
}
Dim job As UrlRequestJob = network.CreateUrlRequestJob(p.UrlRequest, options)
Task.Run(Sub()
' The request processing is performed in a background thread
' in order to avoid freezing the web page.
Dim html = "<html><body><p>Hello there!</p></body></html>"
job.Write(Encoding.UTF8.GetBytes(html))
job.Complete()
End Sub)
Return InterceptRequestResponse.Intercept(job)
End Function)
Authentication
Proxy, Basic, Digest, NTLM
1.x
class MyNetworkDelegate : DefaultNetworkDelegate
{
public override bool OnAuthRequired(AuthRequiredParams params)
{
if(params.IsProxy)
{
params.Username = "user";
params.Password = "password";
return false;
}
// Cancel authentication request.
return true;
}
}
// ...
browserContext.NetworkService.NetworkDelegate = new MyNetworkDelegate();
Class MyNetworkDelegate
Inherits DefaultNetworkDelegate
Public Overrides Function OnAuthRequired(ByVal params As AuthRequiredParams) As Boolean
If params.IsProxy Then
params.Username = "user"
params.Password = "password"
Return False
End If
' Cancel authentication request.
Return True
End Function
End Class
' ...
browserContext.NetworkService.NetworkDelegate = New MyNetworkDelegate()
2.0
engine.Network.AuthenticateHandler =
new Handler<AuthenticateParameters, AuthenticateResponse>((p) =>
{
if (p.IsProxy)
{
return AuthenticateResponse.Continue("user", "password");
}
else
{
return AuthenticateResponse.Cancel();
}
});
engine.Network.AuthenticateHandler =
New Handler(Of AuthenticateParameters, AuthenticateResponse)(Function(p)
If p.IsProxy Then
Return AuthenticateResponse.Continue("user", "password")
Else
Return AuthenticateResponse.Cancel()
End If
End Function)
HTTPS client certificate
1.x
class MyDialogHandler : DialogHandler
{
public CloseStatus OnSelectCertificate(CertificatesDialogParams parameters)
{
List<Certificate> certificates = parameters.Certificates;
if (certificates.Count == 0) {
return CloseStatus.CANCEL;
} else {
parameters.SelectedCertificate = certificates.LastOrDefault();
return CloseStatus.OK;
}
}
// ...
}
// ...
browser.DialogHandler = new MyDialogHandler();
Class MyDialogHandler
Inherits DialogHandler
Public Function OnSelectCertificate(parameters As CertificatesDialogParams) As CloseStatus
Dim certificates As List(Of Certificate) = parameters.Certificates
If certificates.Count Is 0 Then
Return CloseStatus.CANCEL
Else
parameters.SelectedCertificate = certificates.LastOrDefault()
Return CloseStatus.OK
End If
End Function
' ...
End Class
' ...
browser.DialogHandler = New MyDialogHandler()
2.0
browser.SelectCertificateHandler
= new Handler<SelectCertificateParameters, SelectCertificateResponse>(p =>
{
int count = p.Certificates.Count();
return count == 0 ?
SelectCertificateResponse.Cancel() :
SelectCertificateResponse.Select(p.Certificates.Count() - 1);
});
browser.SelectCertificateHandler =
New Handler(Of SelectCertificateParameters, SelectCertificateResponse)(Function(p)
Dim count As Integer = p.Certificates.Count()
Return If (count = 0,
SelectCertificateResponse.Cancel(),
SelectCertificateResponse.Select(p.Certificates.Count() - 1))
End Function)
Plugins
Filtering plugins
1.x
class MyPluginFilter : PluginFilter
{
public bool IsPluginAllowed(PluginInfo pluginInfo)
{
return true;
}
}
// ...
browser.PluginManager.PluginFilter = new MyPluginFilter();
Class MyPluginFilter
Inherits PluginFilter
Public Function IsPluginAllowed(ByVal pluginInfo As PluginInfo) As Boolean
Return True
End Function
End Class
' ...
browser.PluginManager.PluginFilter = New MyPluginFilter()
2.0
engine.Plugins.AllowPluginHandler =
new Handler<AllowPluginParameters, AllowPluginResponse>(p =>
{
return AllowPluginResponse.Allow();
});
engine.Plugins.AllowPluginHandler =
New Handler(Of AllowPluginParameters, AllowPluginResponse)(
Function(p) AllowPluginResponse.Allow())
DOM
Accessing a document
1.x
DOMDocument document = browser.GetDocument();
Dim document As DOMDocument = browser.GetDocument()
2.0
IDocument document = browser.MainFrame?.Document;
Dim document As IDocument = browser.MainFrame?.Document
DOM events
Working with events
1.x
element.AddEventListener(DOMEventType.OnClick, (s, e) =>
{
DOMEventTarget eventTarget = e.Target;
if (eventTarget != null) {
// ...
}
}, false);
element.AddEventListener(DOMEventType.OnClick, Sub(s, e)
Dim eventTarget As DOMEventTarget = e.Target
If eventTarget IsNot Nothing Then
' ...
End If
End Sub, False)
2.0
element.Events.Click += (s, e) =>
{
IEventTarget eventTarget = e.Event.Target;
if (eventTarget != null)
{
// ...
}
};
AddHandler element.Events.Click, Sub(s, e)
Dim eventTarget As IEventTarget = e.Event.Target
If eventTarget IsNot Nothing Then
' ...
End If
End Sub
JavaScript
Calling JavaScript from .NET
1.x
string name = browser.ExecuteJavaScriptAndReturnValue("'Hello'")
.AsString().Value;
double number = browser.ExecuteJavaScriptAndReturnValue("123")
.AsNumber().Value;
bool flag = browser.ExecuteJavaScriptAndReturnValue("true")
.AsBoolean().Value;
JSObject window = browser.ExecuteJavaScriptAndReturnValue("window")
.AsObject();
Dim name As String = browser.ExecuteJavaScriptAndReturnValue("'Hello'") _
.AsString().Value
Dim number As Double = browser.ExecuteJavaScriptAndReturnValue("123") _
.AsNumber().Value
Dim flag As Boolean = browser.ExecuteJavaScriptAndReturnValue("true") _
.AsBoolean().Value
Dim window As JSObject = browser.ExecuteJavaScriptAndReturnValue("window") _
.AsObject()
2.0
The JSValue
class has been removed in DotNetBrowser 2.0. The type conversion is done automatically now. You can execute JavaScript both synchronously blocking the current thread execution or asynchronously:
IFrame mainFrame = browser.MainFrame;
if(mainFrame != null)
{
// Execution with await.
string name = await mainFrame.ExecuteJavaScript<string>("'Hello'");
double number = await mainFrame.ExecuteJavaScript<double>("123");
bool flag = await mainFrame.ExecuteJavaScript<bool>("true");
IJsObject window = await mainFrame.ExecuteJavaScript<IJsObject>("window");
// Synchronous execution that blocks the current thread.
name = mainFrame.ExecuteJavaScript<string>("'Hello'").Result;
number = mainFrame.ExecuteJavaScript<double>("123").Result;
flag = mainFrame.ExecuteJavaScript<bool>("true").Result;
window = mainFrame.ExecuteJavaScript<IJsObject>("window").Result;
// Asynchronous execution with continuation.
mainFrame.ExecuteJavaScript<IDocument>("document").ContinueWith(t =>{
string baseUri = t.Result.BaseUri;
});
}
Dim mainFrame As IFrame = browser.MainFrame
If mainFrame IsNot Nothing Then
' Execution with await.
Dim name As String = Await mainFrame.ExecuteJavaScript (Of String)("'Hello'")
Dim number As Double = Await mainFrame.ExecuteJavaScript (Of Double)("123")
Dim flag As Boolean = Await mainFrame.ExecuteJavaScript (Of Boolean)("true")
Dim window As IJsObject = Await mainFrame.ExecuteJavaScript (Of IJsObject)("window")
' Synchronous execution that blocks the current thread.
name = mainFrame.ExecuteJavaScript (Of String)("'Hello'").Result
number = mainFrame.ExecuteJavaScript (Of Double)("123").Result
flag = mainFrame.ExecuteJavaScript (Of Boolean)("true").Result
window = mainFrame.ExecuteJavaScript (Of IJsObject)("window").Result
' Asynchronous execution with continuation.
mainFrame.ExecuteJavaScript (Of IDocument)("document").ContinueWith(
Sub(t)
Dim baseUri As String = t.Result.BaseUri
End Sub)
End If
Calling .NET from JavaScript
1.x
In .NET code:
public class MyObject {
public void foo(string text) {}
}
// ...
JSValue window = browser.ExecuteJavaScriptAndReturnValue("window");
if (window.IsObject()) {
window.AsObject().SetProperty("myObject", new MyObject());
}
Public Class MyObject
Public Sub foo(text As String)
End Sub
End Class
' ...
Dim window As JSValue = browser.ExecuteJavaScriptAndReturnValue("window")
If window.IsObject() Then
window.AsObject().SetProperty("myObject", New MyObject())
End If
In JavaScript code:
window.myObject.foo("Hello");
2.0
In .NET code:
public class MyObject {
public void foo(string text) {}
}
// ...
IJsObject window = frame.ExecuteJavaScript<IJsObject>("window").Result;
window.Properties["myObject"] = new MyObject();
Public Class MyObject
Public Sub foo(text As String)
End Sub
End Class
' ...
Dim window As IJsObject = frame.ExecuteJavaScript(Of IJsObject)("window").Result
window.Properties("myObject") = New MyObject()
In JavaScript code:
window.myObject.foo("Hello");
Injecting JavaScript
1.x
browser.ScriptContextCreated += (sender, args) =>
{
JSValue window = browser.ExecuteJavaScriptAndReturnValue(args.Context.FrameId, @"window");
window.AsObject().SetProperty("myObject", new MyObject());
};
AddHandler browser.ScriptContextCreated, Sub(sender, args)
Dim window As JSValue =
browser.ExecuteJavaScriptAndReturnValue(args.Context.FrameId, "window")
window.AsObject().SetProperty("myObject", New MyObject())
End Sub
2.0
browser.InjectJsHandler = new Handler<InjectJsParameters>((args) =>
{
IJsObject window = args.Frame.ExecuteJavaScript<IJsObject>("window").Result;
window.Properties["myObject"] = new MyObject();
});
browser.InjectJsHandler = New Handler(Of InjectJsParameters)(Sub(args)
Dim window As IJsObject = args.Frame.ExecuteJavaScript (Of IJsObject)("window").Result
window.Properties("myObject") = New MyObject()
End Sub)
Console events
1.x
browser.ConsoleMessageEvent += (s, args) =>
{
string message = args.Message;
};
AddHandler browser.ConsoleMessageEvent, Sub(s, args)
Dim message As String = args.Message
End Sub
2.0
browser.ConsoleMessageReceived += (s, args) =>
{
string message = args.Message;
};
AddHandler browser.ConsoleMessageReceived, Sub(s, args)
Dim message As String = args.Message
End Sub
Pop-ups
Suppressing pop-ups
1.x
class MyPopupHandler : PopupHandler
{
public PopupContainer HandlePopup(PopupParams popupParams)
{
return null;
}
}
// ...
browser.PopupHandler = new MyPopupHandler();
Class MyPopupHandler
Inherits PopupHandler
Public Function HandlePopup(ByVal popupParams As PopupParams) As PopupContainer
Return Nothing
End Function
End Class
' ...
browser.PopupHandler = New MyPopupHandler()
2.0
browser.CreatePopupHandler = new Handler<CreatePopupParameters, CreatePopupResponse>((p) =>
{
return CreatePopupResponse.Suppress();
});
browser.CreatePopupHandler =
New Handler(Of CreatePopupParameters, CreatePopupResponse)(
Function(p) CreatePopupResponse.Suppress())
Opening pop-ups
1.x
class MyPopupContainer : PopupContainer
{
public void InsertBrowser(Browser browser, System.Drawing.Rectangle initialBounds)
{
// ...
}
}
class MyPopupHandler : PopupHandler
{
public PopupContainer HandlePopup(PopupParams popupParams)
{
return new MyPopupContainer();
}
}
// ...
browser.PopupHandler = new MyPopupHandler();
Class MyPopupContainer
Inherits PopupContainer
Public Sub InsertBrowser(browser As Browser, initialBounds As Rectangle)
' ...
End Sub
End Class
Class MyPopupHandler
Inherits PopupHandler
Public Function HandlePopup(popupParams As PopupParams) As PopupContainer
Return New MyPopupContainer()
End Function
End Class
' ...
browser.PopupHandler = New MyPopupHandler()
2.0
browser.CreatePopupHandler = new Handler<CreatePopupParameters, CreatePopupResponse>((p) =>
{
return CreatePopupResponse.Create();
});
browser.OpenPopupHandler = new Handler<OpenPopupParameters>((p) =>
{
IBrowser popup = p.PopupBrowser;
// ...
});
browser.CreatePopupHandler =
New Handler(Of CreatePopupParameters, CreatePopupResponse)(
Function(p) CreatePopupResponse.Create())
browser.OpenPopupHandler = New Handler(Of OpenPopupParameters)(
Sub(p)
Dim popup As IBrowser = p.PopupBrowser
' ...
End Sub)
Dialogs
JavaScript dialogs
1.x
class MyDialogHandler : DialogHandler
{
public void OnAlert(DialogParams parameters)
{
}
public CloseStatus OnConfirmation(DialogParams parameters)
{
return CloseStatus.CANCEL;
}
public CloseStatus OnPrompt(PromptDialogParams parameters)
{
parameters.PromptText = "Text";
return CloseStatus.OK;
}
// ...
}
// ...
browser.DialogHandler = new MyDialogHandler();
Class MyDialogHandler
Inherits DialogHandler
Public Sub OnAlert(ByVal parameters As DialogParams)
End Sub
Public Function OnConfirmation(ByVal parameters As DialogParams) As CloseStatus
Return CloseStatus.CANCEL
End Function
Public Function OnPrompt(ByVal parameters As PromptDialogParams) As CloseStatus
parameters.PromptText = "Text"
Return CloseStatus.OK
End Function
' ...
End Class
' ...
browser.DialogHandler = New MyDialogHandler()
2.0
browser.JsDialogs.AlertHandler = new Handler<AlertParameters>(p =>
{
// ...
});
browser.JsDialogs.ConfirmHandler =
new Handler<ConfirmParameters, ConfirmResponse>(p =>
{
return ConfirmResponse.Cancel();
});
browser.JsDialogs.PromptHandler =
new Handler<PromptParameters, PromptResponse>(p =>
{
return PromptResponse.SubmitText("responseText");
});
browser.JsDialogs.AlertHandler = New Handler(Of AlertParameters)(
Sub(p)
' ...
End Sub)
browser.JsDialogs.ConfirmHandler =
New Handler(Of ConfirmParameters, ConfirmResponse)(
Function(p) ConfirmResponse.Cancel())
browser.JsDialogs.PromptHandler =
New Handler(Of PromptParameters, PromptResponse)(
Function(p) PromptResponse.SubmitText("responseText"))
File dialogs
1.x
class FileChooserHandler : DialogHandler
{
public CloseStatus OnFileChooser(FileChooserParams parameters) {
FileChooserMode mode = parameters.Mode;
if (mode == FileChooserMode.Open) {
parameters.SelectedFiles = "file1.txt";
}
if (mode == FileChooserMode.OpenMultiple) {
string[] selectedFiles = {"file1.txt", "file2.txt"};
parameters.SelectedFiles = string.Join("|", selectedFiles);
}
return CloseStatus.OK;
}
// ...
}
// ...
browser.DialogHandler = new FileChooserHandler();
Class FileChooserHandler
Inherits DialogHandler
Public Function OnFileChooser(parameters As FileChooserParams) As CloseStatus
Dim mode As FileChooserMode = parameters.Mode
If mode Is FileChooserMode.Open Then
parameters.SelectedFiles = "file1.txt"
End If
If mode Is FileChooserMode.OpenMultiple Then
Dim selectedFiles As String() = {"file1.txt", "file2.txt"}
parameters.SelectedFiles = String.Join("|", selectedFiles)
End If
Return CloseStatus.OK
End Function
' ...
End Class
' ...
browser.DialogHandler = New FileChooserHandler()
2.0
browser.Dialogs.OpenFileHandler =
new Handler<OpenFileParameters, OpenFileResponse>(p =>
{
return OpenFileResponse.SelectFile(Path.GetFullPath(p.DefaultFileName));
});
browser.Dialogs.OpenMultipleFilesHandler =
new Handler<OpenMultipleFilesParameters, OpenMultipleFilesResponse>(p =>
{
return OpenMultipleFilesResponse.SelectFiles(Path.GetFullPath("file1.txt"),
Path.GetFullPath("file2.txt"));
});
browser.Dialogs.OpenFileHandler =
New Handler(Of OpenFileParameters, OpenFileResponse)(
Function(p) OpenFileResponse.SelectFile(
Path.GetFullPath(p.DefaultFileName)))
browser.Dialogs.OpenMultipleFilesHandler =
New Handler(Of OpenMultipleFilesParameters, OpenMultipleFilesResponse)(
Function(p) OpenMultipleFilesResponse.SelectFiles(
Path.GetFullPath("file1.txt"),
Path.GetFullPath("file2.txt")))
Color dialogs
1.x
class ColorDialogHandler : DialogHandler
{
private Color color;
public ColorDialogHandler()
{
color = Color.White;
}
public CloseStatus OnColorChooser(ColorChooserParams parameters)
{
parameters.Color = color;
return CloseStatus.OK;
}
// ...
}
// ...
browser.DialogHandler = new ColorDialogHandler();
Class ColorDialogHandler
Inherits DialogHandler
Private ReadOnly color As Color
Public Sub New()
color = Color.White
End Sub
Public Function OnColorChooser(parameters As ColorChooserParams) As CloseStatus
parameters.Color = color
Return CloseStatus.OK
End Function
' ...
End Class
' ...
browser.DialogHandler = New ColorDialogHandler()
2.0
browser.Dialogs.SelectColorHandler =
new Handler<SelectColorParameters, SelectColorResponse>(p =>
{
return SelectColorResponse.SelectColor(p.DefaultColor);
});
browser.Dialogs.SelectColorHandler =
New Handler(Of SelectColorParameters, SelectColorResponse)(
Function(p) SelectColorResponse.SelectColor(p.DefaultColor))
SSL certificate dialogs
1.x
class SelectCertificateDialogHandler : DialogHandler
{
private const string ClientCertFile = "<cert-file>.pfx";
private const string ClientCertPassword = "<cert-password>";
private Certificate certificate;
public SelectCertificateDialogHandler()
{
certificate = new X509Certificate2(Path.GetFullPath(ClientCertFile),
ClientCertPassword,
X509KeyStorageFlags.Exportable);
}
public CloseStatus OnSelectCertificate(CertificatesDialogParams parameters)
{
parameters.SelectedCertificate = certificate;
selectCertificateEvent.Set();
return CloseStatus.OK;
}
// ...
}
// ...
browser.DialogHandler = new SelectCertificateDialogHandler();
Class SelectCertificateDialogHandler
Inherits DialogHandler
Private Const ClientCertFile As String = "<cert-file>.pfx"
Private Const ClientCertPassword As String = "<cert-password>"
Private certificate As Certificate
Public Sub New()
certificate = New X509Certificate2(Path.GetFullPath(ClientCertFile),
ClientCertPassword,
X509KeyStorageFlags.Exportable)
End Sub
Public Function OnSelectCertificate(ByVal p As CertificatesDialogParams) As CloseStatus
p.SelectedCertificate = certificate
selectCertificateEvent.Set()
Return CloseStatus.OK
End Function
' ...
End Class
' ...
browser.DialogHandler = New SelectCertificateDialogHandler()
2.0
string ClientCertFile = "<cert-file>.pfx";
string ClientCertPassword = "<cert-password>";
// ...
X509Certificate2 certificate = new X509Certificate2(Path.GetFullPath(ClientCertFile),
ClientCertPassword,
X509KeyStorageFlags.Exportable);
Certificate cert = new Certificate(certificate);
browser.SelectCertificateHandler
= new Handler<SelectCertificateParameters, SelectCertificateResponse>(p =>
{
return SelectCertificateResponse.Select(cert);
});
Dim ClientCertFile = "<cert-file>.pfx"
Dim ClientCertPassword = "<cert-password>"
' ...
Dim certificate = New X509Certificate2(Path.GetFullPath(ClientCertFile),
ClientCertPassword,
X509KeyStorageFlags.Exportable)
Dim cert = New Certificate(certificate)
browser.SelectCertificateHandler =
New Handler(Of SelectCertificateParameters, SelectCertificateResponse)(
Function(p) SelectCertificateResponse.Select(cert))
Printing
Configuring printing
1.x
class MyPrintHandler : PrintHandler
{
public PrintStatus OnPrint(PrintJob printJob)
{
PrintSettings printSettings = printJob.PrintSettings;
printSettings.PrinterName = "Microsoft XPS Document Writer";
printSettings.Landscape = true;
printSettings.PrintBackgrounds = true;
return PrintStatus.CONTINUE;
}
}
// ...
browser.PrintHandler = new MyPrintHandler();
Class MyPrintHandler
Inherits PrintHandler
Public Function OnPrint(ByVal printJob As PrintJob) As PrintStatus
Dim printSettings As PrintSettings = printJob.PrintSettings
printSettings.PrinterName = "Microsoft XPS Document Writer"
printSettings.Landscape = True
printSettings.PrintBackgrounds = True
Return PrintStatus.CONTINUE
End Function
End Class
' ...
browser.PrintHandler = New MyPrintHandler()
2.0
Functionality that allows configuring printing has been removed in DotNetBrowser version 2.0. Now the standard Print Preview dialog where you can provide the required settings is displayed:
browser.PrintHandler =
new Handler<PrintParameters, PrintResponse>(p =>
{
return PrintResponse.ShowPrintPreview();
});
browser.PrintHandler =
New Handler(Of PrintParameters, PrintResponse)(
Function(p) PrintResponse.ShowPrintPreview())
Suppressing printing
1.x
class MyPrintHandler : PrintHandler
{
public PrintStatus OnPrint(PrintJob printJob)
{
return PrintStatus.CANCEL;
}
}
// ...
browser.PrintHandler = new MyPrintHandler();
Class MyPrintHandler
Inherits PrintHandler
Public Function OnPrint(ByVal printJob As PrintJob) As PrintStatus
Return PrintStatus.CANCEL
End Function
End Class
' ...
browser.PrintHandler = New MyPrintHandler()
2.0
browser.PrintHandler =
new Handler<PrintParameters, PrintResponse>(p =>
{
return PrintResponse.Cancel();
});
browser.PrintHandler =
New Handler(Of PrintParameters, PrintResponse)(
Function(p) PrintResponse.Cancel())
Cache
Clearing HTTP cache
1.x
browser.CacheStorage.ClearCache(() =>
{
// HTTP Disk Cache has been cleared.
});
browser.CacheStorage.ClearCache(Sub()
' HTTP Disk Cache has been cleared.
End Sub)
2.0
await engine.HttpCache.ClearDiskCache();
// HTTP Disk Cache has been cleared.
or
engine.HttpCache.ClearDiskCache().Wait();
// HTTP Disk Cache has been cleared.
Await engine.HttpCache.ClearDiskCache()
' HTTP Disk Cache has been cleared.
or
engine.HttpCache.ClearDiskCache().Wait()
' HTTP Disk Cache has been cleared.
Cookies
Accessing cookies
1.x
List<Cookie> cookies = browser.CookieStorage.GetAllCookies();
Dim cookies As List(Of Cookie) = browser.CookieStorage.GetAllCookies()
2.0
IEnumerable<Cookie> cookies = await engine.CookieStore.GetAllCookies();
or
IEnumerable<Cookie> cookies = engine.CookieStore.GetAllCookies().Result;
Dim cookies As IEnumerable(Of Cookie) = Await engine.CookieStore.GetAllCookies()
or
Dim cookies As IEnumerable(Of Cookie) = engine.CookieStore.GetAllCookies().Result
Render process termination
Each browser instance is running on a separate native process where the web page is rendered.
Sometimes this process can exit unexpectedly because of the plugin crash. The render process termination event can be used to receive notifications about unexpected render process termination.
1.x
browser.RenderGoneEvent += (s, e) =>
{
TerminationStatus status = e.TerminationStatus;
};
AddHandler browser.RenderGoneEvent , Sub(s, e)
Dim status As TerminationStatus = e.TerminationStatus
End Sub
2.0
browser.RenderProcessTerminated += (s, e) =>
{
TerminationStatus status = e.TerminationStatus;
};
AddHandler browser.RenderProcessTerminated , Sub(s, e)
Dim status As TerminationStatus = e.TerminationStatus
End Sub
Chromium
Switches
The library does not support all possible Chromium switches. It allows configuring Chromium with the switches, but we do not guarantee that the passed switches will work correctly or work at all. We recommend to check this functionality before using.
1.x
BrowserPreferences.SetChromiumSwitches(
"--<switch_name>",
"--<switch_name>=<switch_value>"
);
BrowserPreferences.SetChromiumSwitches(
"--<switch_name>",
"--<switch_name>=<switch_value>"
)
2.0
IEngine engine = EngineFactory.Create(new EngineOptions.Builder
{
ChromiumSwitches = { "--<switch-name>", "--<switch-name>=<switch-value>" }
}.Build());
Dim engineOptions = New EngineOptions.Builder
engineOptions.ChromiumSwitches.Add("--<switch-name>")
engineOptions.ChromiumSwitches.Add("--<switch-name>=<switch-value>")
Dim engine = EngineFactory.Create(engineOptions.Build())
API keys
1.x
BrowserPreferences.SetChromiumVariable(
"GOOGLE_API_KEY", "My API Key");
BrowserPreferences.SetChromiumVariable(
"GOOGLE_DEFAULT_CLIENT_ID", "My Client ID");
BrowserPreferences.SetChromiumVariable(
"GOOGLE_DEFAULT_CLIENT_SECRET", "My Client Secret");
BrowserPreferences.SetChromiumVariable( _
"GOOGLE_API_KEY", "My API Key")
BrowserPreferences.SetChromiumVariable( _
"GOOGLE_DEFAULT_CLIENT_ID", "My Client ID")
BrowserPreferences.SetChromiumVariable( _
"GOOGLE_DEFAULT_CLIENT_SECRET", "My Client Secret")
2.0
IEngine engine = EngineFactory.Create(new EngineOptions.Builder
{
GoogleApiKey = "<api-key>",
GoogleDefaultClientId = "<client-id>",
GoogleDefaultClientSecret = "<client-secret>"
}.Build());
Dim engine As IEngine = EngineFactory.Create(New EngineOptions.Builder With {
.GoogleApiKey = "<api-key>",
.GoogleDefaultClientId = "<client-id>",
.GoogleDefaultClientSecret = "<client-secret>"
}.Build())
Logging
In the new version, we improved the logging API. Read more about how to configure logging in the Troubleshooting guide.
FAQ
How long will DotNetBrowser version 1.x be supported?
DotNetBrowser version 1.x will be supported till February 2021. All new features, Chromium upgrades, support of the new operating systems and .NET implementations, different enhancements, will be applied on top of the latest (mainstream) version.
Can I upgrade to DotNetBrowser 2 for free?
If you already own a commercial license for DotNetBrowser 1 with an active Subscription, then you can receive a commercial license key for DotNetBrowser 2 for free. Contact our Sales Team if you have any questions regarding this.
I have a case not covered by this guide. What should I do?
We recommend checking our Guides section. DotNetBrowser version 1.0 and version 2.0 have almost identical functionality. So, if this migration guide does not describe an alternative to the DotNetBrowser version 1.0 functionality you use, you can find description of the similar functionality in our guides where the documents are grouped by feature areas.
If you do not see description of the required functionality in the guides, submit a ticket.