How to open a link in a native browser from CefSharp 3
As suggested by holroy I have implemented the OnBeforeNavigation() method in the RequestHandler class in CefSharp.Example package.
This is the working code,
bool IRequestHandler.OnBeforeBrowse(IWebBrowser browserControl,
IBrowser browser, IFrame frame, IRequest request, bool isRedirect)
{
// If the url is Google open Default browser
if (request.Url.Equals("http://google.com/"))
{
// Open Google in Default browser
System.Diagnostics.Process.Start("http://google.com/");
return true;
}else
{
// Url except Google open in CefSharp's Chromium browser
return false;
}
}
I hope this will help to some one else in future.
Thanks,
First you need to create a custom BrowserRequestHandler
class such as this:
public class BrowserRequestHandler : IRequestHandler
{
public bool OnBeforeBrowse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, bool isRedirect)
{
// Open in Default browser
if (!request.Url.StartsWith("file:"))
{
System.Diagnostics.Process.Start(request.Url);
return true;
}
return false;
}
public bool OnOpenUrlFromTab(IWebBrowser browserControl, IBrowser browser, IFrame frame, string targetUrl,
WindowOpenDisposition targetDisposition, bool userGesture)
{
return false;
}
public bool OnCertificateError(IWebBrowser browserControl, IBrowser browser, CefErrorCode errorCode, string requestUrl,
ISslInfo sslInfo, IRequestCallback callback)
{
callback.Dispose();
return false;
}
public void OnPluginCrashed(IWebBrowser browserControl, IBrowser browser, string pluginPath)
{
throw new Exception("Plugin crashed!");
}
public CefReturnValue OnBeforeResourceLoad(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request,
IRequestCallback callback)
{
return CefReturnValue.Continue;
}
public bool GetAuthCredentials(IWebBrowser browserControl, IBrowser browser, IFrame frame, bool isProxy, string host, int port,
string realm, string scheme, IAuthCallback callback)
{
callback.Dispose();
return false;
}
public bool OnSelectClientCertificate(IWebBrowser browserControl, IBrowser browser, bool isProxy, string host, int port,
X509Certificate2Collection certificates, ISelectClientCertificateCallback callback)
{
callback.Dispose();
return false;
}
public void OnRenderProcessTerminated(IWebBrowser browserControl, IBrowser browser, CefTerminationStatus status)
{
throw new Exception("Browser render process is terminated!");
}
public bool OnQuotaRequest(IWebBrowser browserControl, IBrowser browser, string originUrl, long newSize,
IRequestCallback callback)
{
callback.Dispose();
return false;
}
public void OnResourceRedirect(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response,
ref string newUrl)
{
var url = newUrl;
newUrl = url;
}
public bool OnProtocolExecution(IWebBrowser browserControl, IBrowser browser, string url)
{
return url.StartsWith("mailto");
}
public void OnRenderViewReady(IWebBrowser browserControl, IBrowser browser)
{
}
public bool OnResourceResponse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response)
{
return false;
}
public IResponseFilter GetResourceResponseFilter(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request,
IResponse response)
{
return null;
}
public void OnResourceLoadComplete(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request,
IResponse response, UrlRequestStatus status, long receivedContentLength)
{
}
}
The important part in this code is:
public bool OnBeforeBrowse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, bool isRedirect)
{
// Open in Default browser
if (!request.Url.StartsWith("file:"))
{
System.Diagnostics.Process.Start(request.Url);
return true;
}
return false;
}
In my case, I was opening locally saved HTML files in CEF, and if those locally saved HTML files had external links, they would open up in the default browser.
Now that you created the custom BrowserRequestHandler
, you need to assign it to the browser.
If you are using MVVM, you can create a BrowserRequestHandler
in your model and assign it to the RequestHandler
dependency property of the browser control. But in my case there were timing issues as I had several browser instances in dynamically opening tabs and browsers were not opening fast enough and throwing errors.
So the second option is to set up a Loaded event using the interactivity namespace like this:
<wpf:ChromiumWebBrowser Address="{Binding Html, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" x:Name="ChromiumWebBrowser">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding BrowserLoadedCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</wpf:ChromiumWebBrowser>
After this you can get the browser in your view model (or do this in a manager class), and set its RequestHandler
to your custom BrowserRequestHandler
like this:
browser.RequestHandler = new BrowserRequestHandler();
It seems like it possible through use of the OnBeforeNavigation or OnBeforeBrowse events. See following references from "CEF Forum":
- How to have link open in user's default browser
- CEF 3 Open all link targets externally
- Open external browser from link
A suggested implementation of the OnBeforeNavigation method (from Sending information from Chromium Embeded (Javascript) to a containing C++ application):
//declare (i.e. in header)
virtual bool OnBeforeNavigation(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request,
NavigationType navigation_type, bool is_redirect) OVERRIDE;
//implementation
bool CClientApp::OnBeforeNavigation(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request,
NavigationType navigation_type, bool is_redirect)
{
CefString cefval = request->GetURL();
CString csval = cefval.c_str();
if ( /* Match csval against your url/link */ )
{
//process the command here
//this is a command and not really intended for navigation
return true;
}
return false; //true cancels navigation, false allows it
}
Disclaimer: I haven't tried this code myself, but it should do the trick