Extensibility; Clients and Services calling each other
In this post I will be showing sample code (also found on our CodePlex site) as well as an execution sequence diagram. I will show sample code addressing some frequently asked questions; A Host calling AddIn services, AddIns calling (aka. Automation) a Host, AddIns calling AddIns, Managing AddIns (utilizing LINQ), which assemblies are loaded (Per AD and utilizing direct connect), etc…
1. A sample Host application that supports calls from the AddIn (aka., Automation) to the Host.
a. In the past we have shown the Host calling into the AddIn (Sample code), which happens naturally via System.AddIn activation of the AddIn. In other words, the activation of an AddIn allows the Host to call through to the AddIn.
b. We have shown the *pipeline* allowing the AddIn to automate the Host (Sample code).
i. As a result of several requests, this is a sample solution showing an end-to-end solution that includes the Host, Pipeline, and AddIn.
c. In the past I have shown sample code using pure remoting (i.e., No System.AddIn*) for two-way remoting / bi-directional calls (i.e., Host Automation) but now I will show the equivalent using MAF (i.e., Managed AddIn Framework).
2. I am including a Sequence diagram that ties to the Sample App source code showing;
a. AddIn Discovery, Qualification, Activation, AddIn calls into the Host (aka., Host Automation), AddIns requesting and calling other AddIn services (i.e., Client/Services).
3. Isolation - AppDomains and AddIns/Assemblies activated within each, understanding Activation optimization (i.e., Direct Connect forgoing Isolation), and unloadability (i.e., which assemblies/Types are loaded/unloadable).
4. Using LINQ to help you manage AddIns.
5. The benefits of having Adapters, whereby you have code running in the locality of an AppDomain. This is also an example aiding in understanding MarshalByRef (MBRO) .
a. See List<string> GetASMInAppDomain(string AppDomainName) in HostHelper.cs for comments on the problem and the solution.
6. New features we included in the latest features we added to the VS2008 3.5 release.
a. Direct connect Optimization. We have received a few questions on this feature and as such I wanted to clarify the implementation.
i. You must enable DirectConnect
1. AddInToken.EnableDirectConnect = true;
ii. Our Activate method makes it easy to create an Add-in in a new AppDomain and as a result people are forgetting to pass in an existing AppDomain to the Activate method.
1. HAV = tokens[i].Activate<IAuthProvider>(AppDomain.CurrentDomain);
iii. Although we do not instantiate the Adapters we still require them to be defined in the pipeline folders. As some have pointed out, this may be counter-intuitive. We took this approach in order to guide you toward the right design (i.e., support for isolation and version resilience) going forward.
iv. Your Host view of AddIn and AddIn view of Host types respectively, must be the same type (i.e., in the same assembly).
1. In my sample code I list the assemblies in a selected AppDomain so you can see what is loaded. In the direct connect scenario you should not see the Adapter assemblies loaded in the AppDomain.
b. [ActivatableAs] Attribute enables AddIn side, View Type hierarchies.
i. I created an Abstract base class (ABC) as the Base for my views and I marked the ABC with our new attribute [ActivatableAs] which tells us which Base type is used for activating the Addin. The sample code shows how you can use Interfaces and Abstract Base Classes as views. This also shows some of the differences between versioning an Interface (which would require casting over time or Adapting) and an Abstract Base Class which allows a little more flexibility in versioning due to its ability to have default implementations. Note that the CLR does not support multiple inheritance so using Abstract Base Classes should be carefully considered.
c. Custom Qualification
i. Example of an Addin advertising its demand for activation in the Hosts default AppDomain. The Key/Value pair is nothing more than metadata you may use to suite any need your imagination allows.
i. There are a number of scenarios where you may not have a clean directory structure for Add-in’s, or you may not have write access to the Add-in store, or you may not know the location of the Add-in until runtime (e.g., Click-Once deployed Add-in’s), etc..
e. AddIns calling AddIns
i. I will show one Add-in utilizing other AddIns that were instantiated by the Host. The AddIn consumer (Client) requests the List of other AddIns (Services) from the Host. This enables the AddIn to consume other services without having to do its own discovery and activation.
ii. This sample also shows the benefits of Adapter creation helper methods (AuthProviderHostAdapter) and the MAF support for passing Lists of reference types (CollectionAdapters.ToIListContract<> and CollectionAdapters.ToIListContract<>).
1. For more on Value and Reference type behavior, check out these posts by TQ
7. Multiple Add-ins in a single Assembly
a. Although this isn’t a new feature, I am frequently asked about how assemblies and pipeline segments should be factored (more on this later) and confusion over Add-ins and Assemblies.
i. Check out the DefaultAuthProvider.cs as an example.