Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WPF

Running the AxWebBrowser Control in a separate process

4.50/5 (2 votes)
17 Nov 2014CPOL4 min read 20.6K   581  
Browser control plays an important role in hybrid application development, when browser controls are used for a prolonged time its memory foot print starts to increase gradually. This article explains a way to host the browser control in a separate process which can be loaded/unloaded as needed.

Introduction

The sample utlizes the Microsoft AddIn Framework (MAF) to host the browser control in a separate process. This helps in making sure the navigated Website's memory leaks, errors and exceptions are isolated and running in a separate process. This avoids the windows WPF parent process going down because of any issues with the browsed site.

This application takes the Url as an input and navigates to that specified Url in a separate process. The Host application is a WPF windows application. AddIn browser control is a WPF wrapper for axWebBrowser, which runs in a separate process named AddInProcess32. This supports two way communication from host application to AddIn is supported by method calls and the AddIn to host application is supported by event mechanisms.

Microsoft AddIn Framework Basics

For novice users who are new to MAF visit the following MSDN documentation to understand the basic architecture of the way the Pipeline Development works.

Image 1

Browser Host Application

Image 2

Load Browser: Loads the Browser control in a separate AddIn process and paints with in the specified frame.

Unload Browser: Unloads the browser control and terminates the AddIn process.

Navigate: Navigates the browser to the mentioned Url

ListBox Url: Displays the Url's navigated from BeforeNavigate event

Navigate from List: Select a Url and click this to navigate to the selected Url

Using the code

There are Seven Projects referencing to each of the layers in the Pipeline Architecture.

Project 1: AppContracts

Define the interface IBrowserAddInContract derived from IContract, attribute this interface as an AddInContract<font color="#990000" face="Consolas" size="3">IBrowserAddInContract</font> is the interface that needs to be implement within an AddIn to run the browser out of process using the AddIn framework. This interface has two methods one to get the handle and other to navigate to a specified URL.

Before navigating, inform the Host of the URL it will be navigating to. This is implmented based on Events. Add/Remove event handlers using BeforeNavigateEventAdd and BeforeNavigateEventRemove.

C#
[AddInContract]
public interface IBrowserAddInContract : IContract
{
	INativeHandleContract GetUI();
	void Navigate(string url, string cookie);
	void BeforeNavigateEventAdd(INavigateEventHandler handler);
	void BeforeNavigateEventRemove(INavigateEventHandler handler);
}

Define two interfaces for handling the events raised by AddIns in host application and the other interface is for passing the event arguments.

C#
public interface INavigateEventHandler : IContract
{
  bool Handler(INavigateEventArgs args);
}
C#
public interface INavigateEventArgs : IContract
{
        string url
        {
            get;
        }
}

Project 2: HostSideAdapter

In this project, reference both AppContracts and BrowserHostView projects. Implement two classes, one for calling methods from ContractToHost and another for HostToContract.

ContractToView: Derive the class IsolatedElementContractToViewHostAdapter from BrowserHostView.BrowserAddIn. Attribute the class with HostAdapter. Declare an Event and eventhandler variables. AppContract is referenced via composition.


Contracts instance is assigned by the framework. The class performs 4 functions
- implements GetUI.
- implements Navigate.
- Fire_Navigate to call the events.
- Add and remove event functions.

ViewToContract: Derive the class from AppContracts interface. Implement all the methods defined.

Project 3: AddInSideAdapter

In this project, reference both AppContracts and BrowserAddInView projects.
One of the important things to be handled in this project is the dispatcher for running the events. This is being done within the AppDispatcher class.


ViewToContract: This class relies on AppDispatcher for calling the events. Derive the class from AppContracts interface. Attribute the class with AddInAdapterAttribute. Implement all the methods defined.

ContractToView: AppContract is referenced via composition.

Project 4 & 5: BrowserAddInView and BrowserHostView

Both projects defines the view class as abstract. All methods in the AppContracts are defined. Attribute the AddInView alone as [AddInBase]

public abstract class BrowserAddIn
{
    public abstract event System.EventHandler<NavigateEventArgs> Navigating;
 public abstract FrameworkElement GetUI();
 public abstract void Navigate(string url, string cookie);
}

Project 6: BrowserHostApplication

In this project, reference the BrowserHostView. Find the specific type of AddIn as mentioned in the LoadAddIn method. Use the AddInStore static method FindAddIns to retrive the AddIns available on a machine in the specific path. Create the AddIn as separate process as shown below:

C#
private void LoadAddIn()
{
	String path = Environment.CurrentDirectory;
        String[] warnings = AddInStore.Rebuild(path);
        IList<AddInToken> tokens = AddInStore.FindAddIns(typeof(BrowserHostView.BrowserAddIn), path);
        addins = new List<BrowserHostView.BrowserAddIn>();

        ap = new AddInProcess();
        ap.Start();
        AddInStore.FindAddIns(typeof(BrowserHostView.BrowserAddIn), PipelineStoreLocation.ApplicationBase);
        addInInstance = tokens[0].Activate<BrowserHostView.BrowserAddIn>(ap,
                                                                                  AddInSecurityLevel.FullTrust);
        addins.Add(addInInstance);
        addInIndex = dp.Children.Add(c.GetUI());
        addInInstance.Navigating += new EventHandler<BrowserHostView.NavigateEventArgs>(usercontrol_BeforeNavigate);
}

 

To Unload the AddIn, remove the events and shutdown the process as shown below:

C#
private void UnloadAddIn()
{
    addInInstance.Navigating -= usercontrol_BeforeNavigate;
    dp.Children.RemoveAt(addInIndex);
    addInInstance = null;
    ap.Shutdown();
}

 

Project 7: BrowserAddIn

Declare a new class BrowserAddInCode and attribute it as [System.AddIn.AddIn("BrowserAddIn")]. Implements the abstract view class and its methods GetUI, Navigate and NavigatingEventCall. This class instantiates the BrowserControl.

References

This was all possible by referencing the below articles. This enabled me to accomplish the task that I was looking for within my project. Thanks for the contributions and samples provided within the articles.

.NET Application Extensibility, Part 2 by Jack Gudenkauf and Jesse Kaplan

Hosting WPF UI cross-thread and cross-process by Chango V. - MSFT

AppDomain Isolated WPF Add-Ins by Jesse Kaplan

Points of Interest

The AddIn architecture provided a very quick way to host any control in a spearate process with very few lines of code with out worrying about synchronization and inter process communications.

 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)