October 2008 Entries

As mentioned in my previous article, the Managed AddIn Framework supports AppDomain isolation out of the box. This can come in very handy as long as you understand what is really happening under the covers. I am not going to cover all the details of AppDomain isolation and assembly loading within the CLR, but there are plenty of great resources about such things on MSDN. All you need to know for this article is that every .NET assembly much be loaded into memory within an AppDomain, and unless you specifically share assemblies across these domains (as explained below) then they will be loaded into memory for every AppDomain you create. This is particularly important for WPF AddIns, because the WPF assemblies consume a rather generous portion of memory, and since your AddIns are each loaded into their own AppDomain, this means that the WPF assemblies must also be loaded into each of these AppDomains. If you are not careful, your application could begin to consume large amounts of memory without you even noticing.

To solve this, you can place an attribute on the Main method of any .NET executable, explicitly stating that you want the CLR to share any assemblies that it can. There are certain rules for an assembly to be shareable, one of which is that it must have a strong name and be placed in the GAC – obviously this is not a problem for the .NET framework assemblies, WPF in our case.

When you create a new WPF Project the project template will create an App.xaml for you. Since WPF does a little magic behind the scenes, there is no way to access the Main method of your application. In this case, you simply delete the App.xaml and create a new Application.cs class with the following code:


public class Application : System.Windows.Application
{
    public Application()
    {
        StartupUri = new Uri("Window1.xaml", UriKind.Relative);
    }
    
    public static Application App;

    [System.STAThreadAttribute()]
    [System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [System.LoaderOptimization(LoaderOptimization.MultiDomainHost)]
    public static void Main()
    {
        // Add attribute above this method
        Application app = new Application();
        App = app;
        app.Run();
    }
}
Technorati Tags: ,

Disclaimer: This post is mainly for my own reference. Quite honestly, the Managed AddIn Framework (henceforth known as MAF), is a rather complex beast, and I simply cannot remember all the steps necessary to utilize it properly without a small reference guide. This post will cover the complete step-by-step tutorial of every action that a developer must perform to utilize the AddIn framework. It will not be a complete overview of what MAF is or how all the parts tie together. I will do my best to cover these things, but I have also included some very helpful reference material that will cover these topics better than I ever could.

Before continuing

This post does not cover all the intricacies and overall design of the Managed AddIn framework. While it will in fact walk you through a step-by-step creation of a WPF app that supports AddIns, it will not fully explain what the various MAF pipeline projects are used for (or the pipeline itself for that matter). It would be in your best interest to watch this excellent screencast from Daniel Roth first.

What is it?

MAF is the (much overdue, in my opinion) plugin/addin framework for .NET applications. It allows application developers to expose very simple extensibility points that allows third party developers to enhance your product. Common examples are creating an email client and relying on AddIns for services like Spell Checking, Virus Scanning, etc. Whether plugins are a core part of your application or merely a small feature, the Managed AddIn Framework should be employed to your advantage from here on out.

Note: System.AddIn is a .NET 3.5 assembly, and as such means that you must target .NETFX 3.5 to utilize it.

image

MAF consists of the following assemblies

  • System.AddIn
  • System.AddIn.Contract

MAF gives your application the following benefits (at the expense of extra complexity and a steeper learning curve)

  • Discovery – Find addins at runtime
  • Activation – Load an addin at runtime
  • Versioning - Backwards/forward compatibility
  • Isolation – Load addins into separate AppDomains/Processes so they cannot crash they whole app, among other reasons
  • Lifetime Management – MAF will handle addin lifetimes and memory/AppDomain management
  • Sandboxing – Load addins with specific permission sets like “Internet”
  • Unloading – Unload an addin without worrying about tedious AppDomain management

Our goal

By the end of this article you should be able to produce something like below. I know it doesn’t look like much, but it’s tackling a very specific scenario for a hobby project I am working on currently. The goal is to create a host WPF app that allows me (or third parties) to write addins for the host that will render custom WPF UI and allow interaction with the rest of the application.

Below we have a very basic WPF window with a TabControl. The cool thing about this application is that the TabControl is databound to an AddIn collection -- the tabs themselves as well as the tab content are entirely rendered at runtime from an AddIn via the Managed AddIn framework.

image

Step 1 – Define Contact Interface and utilize Pipeline Builder

The first thing you need to be (painfully) aware of, is the project/directory structure that the MAF Pipeline requires. There is some flexibility here but not a whole lot of wiggle room. Thankfully, the only project I have to concern myself with is the Contract assembly (CouchPotato.AddIn.Contract below). With a proper directory structure in place you can use a tool that the MAF team released called Pipeline Builder to generate the necessary MAF projects for you automatically. The arrows below indicate which projects were generated by Pipeline Builder – it is important to understand that the only project/code I actually wrote in this entire solution is the ICouchPotatoAddInContract.cs. Please see the screencast above or the resources below for more details on Pipeline Builder.

image

Ok let’s get started. The following instructions will create the optimal directory/project structure for a MAF-based application.

  • Prepare the directory structure for your MAF application by creating a parent folder in your Visual Studio 2008\Projects folder (or wherever you choose). I named my folder “CouchPotato”
  • Next, create a new Class Library project for your AddIn contact, I chose CouchPotato.AddIn.Contract. Create this project inside your parent folder from Step 1.
    • Add reference to System.AddIn and System.AddIn.Contract
    • Hopefully you have installed Pipeline Builder by now, so you should add reference to “C:\Program Files\Microsoft\Visual Studio Pipeline Builder\PipelineHints.dll”
      • This assembly does not need to be deployed with your application. It is only used by the Pipeline Builder during debugging
    • Create your contract interface, I chose the following
[AddInContract]
public interface ICouchPotatoAddInContract : IContract
{
    string Name { get; }
    string Description { get; }
    void Initialize();
    INativeHandleContract HomeScreen { get; }
}
    • For now, don’t worry about INativeHandleContract. This is an interface that the MAF team added to support much better UI passing between isolation boundaries (AppDomains). This interface allows an AddIn to very easily pass direct UI elements to the host application, which is very important for my application.
    • Notice that MAF requires two rules for your AddIn Contracts: first you must derive from the IContact interface from System.AddIn.Contract assembly, as well as add the [AddInContract] attribute also from the same assembly.
    • Next, I chose to specify some naming ‘hints’ to the Pipeline builder. These hints tell the Pipeline Builder utility what to name the 4 assemblies that it will be generating for me. Click here to view all available Pipeline Hints
[assembly: PipelineHints.SegmentAssemblyName(PipelineHints.PipelineSegment.HostView, "CouchPotato.AddIn.HostView")]
[assembly: PipelineHints.SegmentAssemblyName(PipelineHints.PipelineSegment.AddInView, "CouchPotato.AddIn.AddInView")]
[assembly: PipelineHints.SegmentAssemblyName(PipelineHints.PipelineSegment.HostSideAdapter, "CouchPotato.AddIn.HostSideAdapters")]
[assembly: PipelineHints.SegmentAssemblyName(PipelineHints.PipelineSegment.AddInSideAdapter, "CouchPotato.AddIn.AddInSideAdapters")]
    • We are almost done, but before we build this project we need to change to output path from the default “/bin/Debug” to “../output/Contracts”. For further explanation on this please see the excellent screencast by Daniel Moth.

image

    • Ok we are ready to build, go ahead and build your project.
      • This step is important because the Pipeline builder does not examine your source code to generate the dependent assemblies, only the compiled code via reflection.
    • Launch the Pipeline Builder from the Tools menu. Default settings should be fine if you have been following along. Pressing OK should generate 4 new projects to your solution, as seen above.
    • Note: I believe this is a bug I ran into with the Pipeline Builder CTP, but in my case I was forced to rename the generated Assembly Name/Default Namespace after the first generation as seen below. Take a look at your projects and verify these settings. Once you change them the first time you will not have to do it again, even if you use Pipeline builder again (and you will).

image

 

Step 2 – Create our Host WPF Application

Now that our AddIn Pipeline is complete let’s create the host application.

Open a new instance of Visual Studio and create a new WPF Project, create it inside the same parent folder that we used for our Contracts project.

  • Add reference to System.AddIn
  • Add reference to your HostView assembly that can be found by browsing to “../output/CouchPotato.AddIn.HostView.dll”
  • Important: Make sure you set CopyLocal=false for your HostView assembly

image

  • Finally, change your build output path to the root output directory

image

  • I have created a very simple WPF Window with a TabControl. As you can see I am taking advantage of the ContentPresenter control to handle rending of the AddIn control for me. This is a great trick
<TabControl x:Name="PluginContainer" TabStripPlacement="Bottom">
    <TabControl.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <TextBlock Text="{Binding Name}" />
            </StackPanel>
        </DataTemplate>
    </TabControl.ItemTemplate>
    <TabControl.ContentTemplate>
        <DataTemplate>
            <Grid>
                <ContentPresenter Content="{Binding HomeScreen}" />
            </Grid>
        </DataTemplate>
    </TabControl.ContentTemplate>
</TabControl>
  • That is the last of our host configuration. Last thing we need to do is Update our AddInStore and load some AddIns (unfortunately, we don’t have any yet, please see Step 3 :) 
public Window1()
{
    InitializeComponent();

    AddInStore.Update(PipelineStoreLocation.ApplicationBase);
    Collection<AddInToken> addinTokens = AddInStore.FindAddIns(typeof(ICouchPotatoAddIn), PipelineStoreLocation.ApplicationBase);

    ObservableCollection<ICouchPotatoAddIn> addins = new ObservableCollection<ICouchPotatoAddIn>();
    foreach (AddInToken addinToken in addinTokens)
    {
        ICouchPotatoAddIn addin = addinToken.Activate<ICouchPotatoAddIn>(AddInSecurityLevel.Internet);
        addins.Add(addin);
    }
    
    PluginContainer.ItemsSource = addins;
}

 

Step 3 – Create our first AddIn

For this last step we are going to create a fake PhotoGallery AddIn.

  • Open a new instance of Visual Studio and create a new Class Library project, create it inside the same parent folder that we used for our Contracts project.
    • Add reference System.AddIn
    • If this is a WPF Addin, add reference PresentationFramework for FrameworkElement
    • Add reference to your AddInView assembly that can be found by browsing to “../output/AddInViews/AddInView.dll”
    • Important: Make sure you set CopyLocal=false for your AddInView assembly

image

  • Set the AddIn output to a specific directory within the output/AddIns folder, for example:

    • ..\output\AddIns\PhotoGalleryAddIn

image

  • Now that configuration is complete let’s create our UserControl that will represent the UI for the AddIn. Simply right-click on the project and Add New Item, select WPF User Control, add any UI that you choose.
<UserControl x:Class="CouchPotato.PhotoGalleryAddIn.PhotoGalleryControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="300" Width="300">
    <Grid>
        <TextBlock Text="Happy Photos!" />
    </Grid>
</UserControl>
  • Lastly, create a the WeatherAddIn.cs file

    • Implement the ICouchPotatoAddIn interface
    • Add the [AddIn] attribute to describe the AddIn.
    • As you can see below, the Pipeline Builder has turned the INativeHandleContract interface into a FrameworkElement for us! This is very handy, as it will allow seamless calls from UI elements across AppDomains without us knowing anything about it! All we have to do is return any FrameworkElement to satisfy the contract, in this case, a WPF UserControl does in fact derive from FrameworkElement, as does just about anything in the WPF visual namespace.
[AddIn("Photo Gallery", Version = "1.0.0.0")]
public class PhotoGalleryAddin : ICouchPotatoAddIn
{
    private readonly PhotoGalleryControl _control;

    public PhotoGalleryAddin()
    {
        _control = new PhotoGalleryControl();
    }

    public string Name
    {
        get { return "Photo Gallery"; }
    }

    public string Description
    {
        get { return "View all your photos"; }
    }

    public void Initialize()
    {
    }

    public FrameworkElement HomeScreen
    {
        get { return _control; }
    }
}

Run it!

With any luck, hopefully you are able to run your host application and find the AddIn you created. There are a lot of working parts when you use the Managed AddIn Framework, and as such, there are many points of failure. As you can see there is a slight learning curve to utilize MAF but hopefully after this article and the Daniel Moth screencasts you should be pretty comfortable with the framework.

image

 

Resources

Technorati Tags: ,

Just what exactly are these snippets?

I believe that snippets are an underused feature built into Visual Studio. This post is my attempt at comparing the two tools I have used for snippet creation, and hoping to make more developers out there aware of just how easy they are to create and use in your existing projects. I am by no means an expert with either of these tools, but I think that is the point: they take a few minutes to create and can be reused for immediate time savers.

Much to my surprise there exists a significant number of .NET developers that are not taking advantage of code snippets, built-in or otherwise. No doubt you have all seen them in intellisense before: they appear with a partially-jagged piece of paper as seen below. When selected, they expand into a template of code that has select editable variables. A number of predefined code-snippets ship with Visual Studio, many of which I use regularly, including ctor, prop, exception, try, etc.

image

The “prop” snippet “expands” into the following code:

image

So the big question is how can we create our own snippets? Let’s take a real-world example and find out.

Snipper Designer (free Visual Studio Plugin)

A few weeks ago a project was released on CodePlex called Snipper Designer. Snippet Designer is a plugin for Visual Studio that was previously used internally by Microsoft and has since been released for all of us to enjoy. After downloading the MSI, it istalled in no time and I was on my way to creating a basic snippet I wish I had created long ago.

To start off I took some Configuration Property code that I had already written as the starting point for my snippet. Anyone who has done extensive configuration with the System.Configuration assembly should be very familiar with this code: it is a property declaration for automatic strongly-typed reading and writing to an XML attribute in your app.config. There are a number of similar code snippets I will be creating for various Configuration-related tasks, and I hope to update this post with my complete list of Configuration snippets shortly.

image

As you can see, the Snipper Designer has added a context menu item to export highlighted code as a snippet. In doing so, the code below was produced in my Snippet Designer:

image

From here all I had to do was decide which “variables” would be available in my snippet. This is identifiable by the twin dollar signs ($) at the beginning and end of the variable. Finally, I assigned the snippet a shortcut, which is how we will invoke the snippet expansion in a code file. The shortcut I chose was “configProp.”

image

Our final bit of customization lies in a property pane below the snippet code. From here I can define tooltips to help other developers who may be using my snippets, as well as set default values and expected data types associated with a variable. As you can see, I specified that the isRequired variable should be a Boolean that defaults to true.

image


ReSharper Live Templates

Many of you will probably be familiar with the Visual Studio plugin ReSharper. ReSharper has quickly become a favorite of mine over the last year or so, and I feel as though I have only scratched the surface of it’s productivity potential. One of said features is their own snippet framework (which they have named Live Templates). ReSharper Live Templates are slightly more powerful than the aforementioned Snippet Designer.

image

As you can clearly see, the ReSharper snippet code is almost identical to Snippet Designer. This is a great thing. In fact, I copy-pasted my Snippet Designer code into ReSharper and it instantly recognized it, so the two are very interoperable in that regard.

image

The variable definition pane is where ReSharper really shines. It has significantly more customization over Snippet Designer, given it’s very nice macro support. I have certainly not experimented with all of these predefined macro’s but they seem like they would be great features for advanced and more intelligent snippet scenarios. I hope to play with them a bit more in the near future. Above you will notice that I have used the “Constant value” macro to specify defaults for the isRequired and DataType variable, which are “true” and “string”, respectively..

image

So what exactly did the last few minutes do for us? Well for me, any time in the future where I need to define a new Configuration Property in code, I will no longer by force into vastly error-prone copy-pasting. Instead, I simply trigger my snippet by it’s predefined shortcut. In my case, I chose “configProp.”

image

When selected, it expands into this simple code block, which allows me to [tab] through the 5 variables and be on my way. And if you happen to think this won’t save you much time, then I would challenge the fact that you have probably not copy-pasted a significant number of these configuration properties before. As I mentioned in the beginning, I will be creating an army of these snippets, ranging from not only my Configuration-related ones, but repeatable tasks like ViewState-backed property wrappers, etc.

image 

Download

Technorati Tags: ,