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 return Task<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 IBrowsers 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 disposing IBrowser(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

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>"))

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.

Go Top