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.
Browser Host Application
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.
[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.
public interface INavigateEventHandler : IContract
{
bool Handler(INavigateEventArgs args);
}
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:
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:
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.