CHAPTER 2 VISUAL STUDIO IDE AND MEF
24
1. Open the project StartPage.csproj and note how StartPage.xaml is a standard XAML page with
some Visual Studio-specific controls to display items such as recently opened projects.
2. Perform a simple modification, such as altering some of the text content.
3. Save the file with a new file name, such as CustomStartPage.xaml, in the same directory.
Before you can use your new start page, you have to select it in Visual Studio options. Go into
ToolsOptions then select the Startup node. Select the new custom start page from the Custom Start
Page drop-down menu.
Close Visual Studio and reopen it. Your new start page should now appear the next time Visual
Studio is loaded.
T4 (Text Template Transformation Toolkit) Files
A T4 template is a code-generation language that has been around since VS2005. You should be aware of
them, as they are used in areas such as Entity Framework and MVC and can be useful for your own
development. To see T4 templates in action, create a file with the extension .tt, add some text content,
save the file, and note how Visual Studio will generate a code file from the template. You can apply
complex logic using T4 templating language to change the output that is generated depending on
various conditions.
T4 templates in VS2010 are compiled when they are saved (preprocessed). This means that they are
another type that can be instantiated.
Scott Hanselman has some great and information on this area so please refer to the following
article:
www.hanselman.com/blog/T4TextTemplateTransformationToolkitCodeGenerationBestKeptVisualStudio
Secret.aspx.
T4 templates don’t have Intellisense so your best bet is to download the Tangible T4 plugin:
For more see:
/>studio-2010/
VS2010 Premium and Ultimate
I will only be covering Professional edition in this book, but I want to make you aware of a couple of
fantastic features available in more expensive versions.
Generate Sequence Diagram
Generate sequence diagram creates a diagram of a methods calls. To use generate sequence diagram,
simply right-click on a function and select Generate Sequence Diagram.
CHAPTER 2 VISUAL STUDIO IDE AND MEF
25
Historical Debugging (Team System Edition Only)
Visual Studio Team edition contains a very cool feature called Historical Debugging. Ian Who, a
developer on the profiler team, says:
The Historical Debugger plays a role similar to that of a black box in a plane. We keep track
of important points in your programs execution and allow you to play back what happened
at those points at a later time.
For more information please refer to:
/>system-2010.aspx
Static Analysis of Code Contracts
Code contracts (which I cover in Chapter 3) allow you to express constraints within code that can be
analyzed at compile time to check if your code violates them. Although code contracts are present in all
versions of Visual Studio, only Premium and Ultimate provide static analysis.
Customization of IDE
VS2010 allows you to create much more advanced customizations than changing the start page or
creating snippets. VS2010 has been written from the ground up for extensibility and customization.
• Screens have been rewritten in WPF and managed code.
• The IDE API has been refactored for easier use.
• The IDE API is fully documented.
• New immutable text snapshots make it easier to obtain accurate snapshot of text editor.
Many areas of the IDE can be overridden by creating a MEF component (I will talk about MEF
shortly).
So, what can you customize? VS2010 allows you to customize the following areas, among other
things:
• Margins and scrollbars
• Tags
• Adornments (items painted on the editor surface)
• Mouse processors
• Drop handlers
• Options
• Intellisense and debugger
CHAPTER 2 VISUAL STUDIO IDE AND MEF
26
Before you can perform any of these customizations, however, you will first need to download and
install the Visual Studio SDK.
Extensions in VS2010 make heavy use of a new technology called MEF. Before we create any
customizations we need to understand a bit about MEF.
MEF (Managed Extensibility Framework)
MEF is a new framework for creating customizable applications that can be used by any .NET-
compatible language. Glenn Block (PM for the new Managed Extensibility Framework in .NET 4.0) says:
Quite simply, MEF makes building extensible apps, libraries and frameworks easy. It
shares some common characteristics of other frameworks out there, but it also
addresses a whole new set of problems that arise in building extremely large scalable
extensible systems.
/>framework.aspx
Let’s say you have created a Tetris application and want to allow users to extend it by creating their
own shapes of bricks. MEF enables you to do this by defining a brick interface and then dynamically
loading and resolving the created extensions.
When creating a MEF application, take the following steps:
1. Define areas of the application that can be extended and decorate them with the [Import]
attribute.
2. Determine a contract/interface that defines what your extensions must do/be (this could be a
simple as they must of String).
3. Create an extension that meets these requirements and decorate it with the [Export] attribute.
4. Modify your application to load these extensions.
Why Use MEF?
Using MEF has the following advantages:
• Microsoft hopes that MEF will become the preferred standard
method of creating extensions. By
utilizing a standard plug-in model, your extensions could be used in many applications
• MEF provides a number of flexible ways to load your extensions.
• Extensions can contain metadata to provide further information about their capabilities. For
example, you may only want to load extensions that can communicate securely.
• MEF is open source and works on VS2008 (www.codeplex.com/MEF).
CHAPTER 2 VISUAL STUDIO IDE AND MEF
27
BUT COULDN’T I ACCOMPLISH THIS WITH REFLECTION/DEPENDENCY
INJECTION/IOC CONTAINERS/VOODOO?
There is overlap in the functionality provided by the above technologies and MEF. MEF and IOC do have some
overlap, and many would classify MEF as an IOC. MEF’s primary purpose is, however, creating extensible
applications through discovery and composition, whereas IOC containers are generally more focused on
providing an abstraction for testing purposes. It’s not a discussion I want to get into, but Oren does, so please
refer to:
Hello MEF
In this sample application you will create two extensions that print out a message. You will then load
them both into an IEnumerable<string> variable called Message before iterating through them and
printing out the messages.
Create a new console project and call it Chapter2.HelloMEF.
1. Add a reference to System.ComponentModel.Composition.
2. Add a new class called MEFTest.
3. Add the following using statements to the class:
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;
5. Modify MEFTest class code to the following (note how we decorate the Message property with the
[Import] attribute):
public class MEFTest
{
[Import]
public string Message { get; set; }
public void HelloMEF()
{
CompositionContainer container = new CompositionContainer();
CompositionBatch batch = new CompositionBatch();
batch.AddPart(new Extension1());
batch.AddPart(this);
container.Compose(batch);
Console.WriteLine(Message);
Console.ReadKey();
}
}
CHAPTER 2 VISUAL STUDIO IDE AND MEF
28
We now need to create the extensions to load so create a new class called Extension1.
4. Add the following using statement:
using System.ComponentModel.Composition;
5. Amend Extension1.cs to the following:
public class Extension1
{
[Export]
public string Message
{
get
{
return "I am extension 1";
}
}
}
6. Finally open Program.cs and add the following code:
static void Main(string[] args)
{
MEFTest MEFTest = new MEFTest();
MEFTest.HelloMEF();
}
7. Press F5 to run the application, and you should see that both extensions are loaded and the
Message property printed out, as Figure 2-14 shows.
Figure 2-14. Output from HelloMEF application
Congratulations you have created your first MEF application.
CHAPTER 2 VISUAL STUDIO IDE AND MEF
29
How Did This Example Work?
You started off by telling MEF that your Message property can be extended by marking it with the
[Import] attribute. The [Import] attribute means “I can be extended” to MEF:
[Import]
public string Message { get; set; }
You then created an extension class and added the [Export] attribute. [Export] tells MEF “I am an
extension”:
class extension1
{
[Export]
public string Message
{
get
{
return "I am extension 1";
}
}
}
You then created a container (containers resolve MEF extensions when they are requested) to hold
the extensions and added your extension classes to it using a CompositionBatch:
CompositionContainer container = new CompositionContainer();
CompositionBatch batch = new CompositionBatch();
batch.AddPart(new extension1());
batch.AddPart(this);
The Compose method was then called which caused MEF to load our extensions into the Message
property.
container.Compose(batch);
MEF then loaded extensions into the Messages property decorated with the [Export] attribute that
matched the contract. Finally, you printed out the message to the screen. In this example, you only
loaded extensions contained within the project itself, which isn’t too useful. Luckily MEF allows you to
load extensions declared outside the project.
CHAPTER 2 VISUAL STUDIO IDE AND MEF
30
MEF Catalogs
MEF uses a concept called catalogs to contain extensions. Catalogs come in three different flavors:
• Assembly (extensions are contained in a .net assembly)
• Directory (extensions are in a physical directory)
• Aggregate (a catalog type that contains both assembly and directory extensions)
In this example you will use a directory catalogue to load an extension defined outside the main
project. Directory catalogs will scan the target directory for compatible extensions when first created.
You can rescan the directory by calling the Refresh method.
1. It is a good idea to declare MEF interfaces in a separate project to avoid circular reference issues
and facilitate reuse so open the existing Chapter2.HelloMEF project and add a new class library
project called Chapter2.MEFInterfaces.
2. Inside this project, create an interface called ILogger.
3. Replace the existing code in ILogger.cs with the following code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Chapter2.MEFInterfaces
{
public interface ILogger
{
string WriteToLog(string Message);
}
}
4. In the Chapter2.HelloMEF project, add a reference to the Chapter2.MEFInterfaces project.
5. In the Chapter2.HelloMEF project, create a class called MoreUsefulMEF and enter the following
code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;
using System.IO;
CHAPTER 2 VISUAL STUDIO IDE AND MEF
31
namespace Chapter2.HelloMEF
{
class MoreUsefulMEF
{
[Import]
private Chapter2.MEFInterfaces.ILogger Logger;
public void TestLoggers()
{
CompositionContainer container;
DirectoryCatalog directoryCatalog =
new DirectoryCatalog(
(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location))
);
container = new CompositionContainer(directoryCatalog);
CompositionBatch batch = new CompositionBatch();
batch.AddPart(this);
container.Compose(batch);
Console.Write(Logger.WriteToLog("test"));
Console.ReadKey();
}
}
}
6. Open Program.cs and amend the Main method to the following:
MoreUsefulMEF MoreUsefulMEF = new MoreUsefulMEF();
MoreUsefulMEF.TestLoggers();
You will now create a logging extension so add a new class library project to the solution called
Chapter2.EmailLogger.
7. Add a reference to the Chapter2.MEFInterfaces project.
8. Add a reference to System.ComponentModel.Composition.
9. Add a new class called EmailLogger.
10. Amend the code to the following:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition;
CHAPTER 2 VISUAL STUDIO IDE AND MEF
32
namespace Chapter2.EmailLogger
{
[Export(typeof(Chapter2.MEFInterfaces.ILogger))]
public class EmailLogger : MEFInterfaces.ILogger
{
public string WriteToLog(string Message)
{
//Simulate email logging
return "Email Logger Called";
}
}
}
11. When you use a directory catalog to load MEF components, you can either compile the
Chapter2.EmailLogger project and copy the built assembly to Chapter2.HelloMEF’s bin folder, or
add a project reference in Chapter2.HelloMEF to the Chapter2.EmailLogger project.
Once you have done this press F5 to run the HelloMEF project. The Email Logger extension
should then be loaded and “Email Logger Called” output to the screen.
Metadata
An important feature of MEF is that you can provide additional information about an extension's
capabilities with metadata. MEF can then utilize this information to determine the most appropriate
extension to load and query its capabilities. For example in the previous logging example you might
specify whether the logging method is secure or not and then in high security environments only load
extensions that communicated securely. Meta data can be defined at a class or method level.
To add metadata to a class use the [PartMetaData] attribute to your class:
[PartMetadata("secure", "false")]
[Export(typeof(Chapter2.MEFInterfaces.ILogger))]
public class EmailLogger : MEFInterfaces.ILogger
{ }
You can add metadata to an individual method with the [ExportMetadata] attribute:
[ExportMetadata("timeout", "5000")]
public string WriteToLog(string Message)
{ }
Metadata can then be retrieved using a part's Metadata property. The following code demonstrates
retrieving metadata from a directory catalog:
CompositionContainer container;
DirectoryCatalog directoryCatalog =
new DirectoryCatalog((Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)));
CHAPTER 2 VISUAL STUDIO IDE AND MEF
33
foreach (var Part in directoryCatalog.Parts)
{
Console.WriteLine(Part.Metadata["secure"]);
}
Note that querying a method’s metadata is slightly different and that you must instead use the
Part.ExportDefinitions property.
What’s This All Got to Do with Visual Studio Extensibility?
Visual Studio utilizes MEF in an almost identical way to the previous examples when it loads Visual
Studio extensions. When Visual Studio first loads, it examines the extensions directory and loads
available extensions. Let’s now look into how these extensions are created.
Visual Studio Extensibility
After you install the Visual Studio customization SDK, a number of new extensibility projects are
available for you to create. These projects are templates that demonstrate how to perform various “hello
world” type customizations that you can then build on. Figure 2-15 shows these new project types.
Figure 2-15. New extensibility projects are available after installing customization SDK.