Skip to content
Alex Maitland edited this page Dec 1, 2015 · 12 revisions

CefSharp 43 provides much better access to the underlying CEF API and as such there are many changes over version 41. A number of changes will be required when updating. This document provides some information, if you have something to add then please be aware that any registered GitHub user an contribute.

  • Expose IFrame and IBrowser interfaces.

  • Access to the underlying popup browser wrappers.

  • New CEF binary files need to be included with libcef.dll, etc.:

  • natives_blob.bin

  • snapshot_blob.bin

  • Breaking changes for many handlers

  • Built-in PDF viewer removed. See #1144 for workaround.

  • The following are now deprecated:

    • IWebBrowser.CanReload, use IWebBrowser.IsLoading instead (will be removed from the three ChromiumWebBrowser instances).
    • FrameLoadStartEventArgs.IsMainFrame use FrameLoadStartEventArgs.Frame.IsMain instead
    • FrameLoadEndEventArgs.IsMainFrame use FrameLoadEndEventArgs.Frame.IsMain instead
  • PR's tagged as breaking change can be found at https://github.com/cefsharp/CefSharp/issues?utf8=%E2%9C%93&q=label%3Abreaking-change+is%3Amerged+milestone%3A43.0.0

  • WCF can now be disabled via CefSharpSettings.WcfEnabled = false;. Disables JavaScript object binding. Native Chrome IPC used instead for all IPC, ExecuteScriptAsync and EvaluateScriptAsync.

  • Changed to using process-per-tab model (One Render Process per ChromiumWebBrowser instance). This is to workaround a problem with the native IPC and JavascriptBinding.

Breaking Changes

Most of the public facing API has breaking changes, the scheme handler implementation was totally rewritten to simplify the underlying code, give you access to underlying API. The Handler interfaces have also undergone major changes, the key concepts are outlined below. There are unfortunately too many changes to list them all.

ISchemeHandlerFactory

//To upgrade: add new parameters.  Code logic does not need to change.
public SchemeHandlerFactory: ISchemeHandlerFactory
{
  //Old
  ISchemeHandler Create()
  {
    return handler;
  }

  //New
  public IResourceHandler Create(IBrowser browser, IFrame frame, string schemeName, IRequest request)
  {
        //To read a file of disk no need to implement your own handler
	if (schemeName == SchemeName && request.Url.EndsWith("CefSharp.Core.xml", System.StringComparison.OrdinalIgnoreCase))
	{
		//Display the CefSharp.Core.xml file in the browser
		return ResourceHandler.FromFileName("CefSharp.Core.xml", ".xml");
	}
	return new CefSharpSchemeHandler();
  }
}

ISchemeHandler

//NOTE: ISchemeHandler renamed to IResourceHandler (shares code with ResourceHandler implementation)
public class CefSharpSchemeHandler : IResourceHandler
{
	//Old:
	public bool ProcessRequestAsync(IRequest request, ISchemeHandlerResponse response, OnRequestCompletedHandler requestCompletedCallback)
	{
		//Processing goes here...
		return true;
	}
	
	//New: 
	//To upgrade: store the response stream in a class field, then call callback.Continue() instead of the old `requestCompletedCallback`.
	//See here for example of new usage: https://github.com/cefsharp/CefSharp/blob/cefsharp/43/CefSharp.Example/CefSharpSchemeHandler.cs
	public bool ProcessRequestAsync(IRequest request, ICallback callback)
    {
		Task.Run(() =>
		{
			// Base to dispose of callback as it wraps a managed resource
			using (callback)
			{ 
				//Perform processing here
				
				// When processing complete call continue
				callback.Continue();
			}
		});

		return true;
	}

	public Stream GetResponse(IResponse response, out long responseLength, out string redirectUrl)
	{
		//How long is your stream?
		responseLength = stream.Length;
		//Set to null if not redirecting to a different url
		redirectUrl = null;

		//Set response related stuff here
		response.StatusCode = (int)HttpStatusCode.OK;
		response.StatusText = "OK";
		response.MimeType = mimeType;
		
		//Return your populated stream
		return stream;
	}	
}

Handler Interfaces

Most handler interfaces, IKeyboardHandler, IRequestHandler, etc no provide access to the underlying CefBrowser through the IBrowser interface. IMenuHandler was renamed to IContextMenuHandler (matches the underlying CefContextMenuHandler naming). Whilst IBrowser wraps a managed resource, please don't call Dispose(), CefSharp will take care of this. Some handlers will also expose IFrame interface which wraps CefFrame, again, don't Dispose(). You will also note the appearance of many callback interfaces, for example IRequestCallback. You can now perform tasks in an async operation. We do reccomend you Dispose() of the callbacks when your finished as they wrap an unmanaged resource. (Easiest way is a using() block.

Example of the updated IKeyboardHandler interface

public class KeyboardHandler : IKeyboardHandler
{
	//Old:
	public bool OnKeyEvent(IWebBrowser browserControl, KeyType type, int windowsKeyCode, CefEventFlags modifiers, bool isSystemKey)
	{
		return false;
	}
	
	//New:
	public bool OnPreKeyEvent(IWebBrowser browserControl, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey, ref bool isKeyboardShortcut)
	{
		return false;
	}
}

See https://github.com/cefsharp/CefSharp/blob/cefsharp/43/CefSharp.Example/RequestHandler.cs

public class RequestHandler : IRequestHandler
{
	//NOTE: In some cases new methods have been added, check the interface documentation for more details.
	//e.g. https://github.com/cefsharp/CefSharp/blob/cefsharp/43/CefSharp/IRequestHandler.cs#L43
	bool IRequestHandler.OnOpenUrlFromTab(IWebBrowser browserControl, IBrowser browser, IFrame frame, string targetUrl, WindowOpenDisposition targetDisposition, bool userGesture)
	{
		return false;
	}

	//NOTE: The IWebBrowser control variable is now called browserControl, you now have access to IBrowser, IFrame and in this instance IRequestCallback
	CefReturnValue IRequestHandler.OnBeforeResourceLoad(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IRequestCallback callback)
	{
		//NOTE: If you do not wish to implement this method returning false is the default behaviour
		// We also suggest you explicitly Dispose of the callback as it wraps an unmanaged resource.
		//callback.Dispose();
		//return false;

		//NOTE: When executing the callback in an async fashion need to check to see if it's disposed
		if (!callback.IsDisposed)
		{
			using (callback)
			{
				//Do some stuff here

				//Callback in async fashion
				//callback.Continue(true);
				//return CefReturnValue.ContinueAsync;
			}
		}

		return CefReturnValue.Continue;
	}
}

BrowserSettings

The settings have been simplified and now closely mimic the behavior of CEF.

browserSettings.ImageLoadingDisabled = true;

becomes

browserSettings.ImageLoading = CefState.Disabled;
(The enum has three states CefState.Default, CefState.Enabled, CefState.Disabled