VS Beta 1 ProvideService or MEF Export?
***Disclaimer: This information applies to Visual Studio 2010 Beta 1 only.***
When we are developing a VS package it is really common to declare and promote services.
Let’s first recap how do we create a VS service:
- We decorate our package class with the ProvideService attribute
- We promote the service (make it visible to other VS Packages) at service creation time
[ProvideService(typeof(SMyService))]
public sealed class ServicesPackage : Package
{
public ServicesPackage()
{
}
protected override void Initialize()
{
base.Initialize();
IServiceContainer serviceContainer = (IServiceContainer)this;
serviceContainer.AddService(typeof(SMyService), new MyService(), true); //true to promote the service
}
}
[Guid("70673710-F36C-4B09-9468-0D0A7A1F7BCF")]
public interface SMyService : IMyService
{
}
public interface IMyService
{
void DoStuff();
}
internal class MyService : SMyService
{
public void DoStuff()
{
}
}
Once the service is declared and promoted it can be consumed from other packages or components.
Couple of points with this implementation:
- VS Services are singletons
- VS Packages are lazy loaded by VS
- In this particular case the VS Package will be loaded when another component queries the service via the GetService method.
var myService = (IMyService)GetService(typeof(SMyService)); myService.DoStuff();
Now let’s create a MEF export:
- We create a CompositionContainer
- We declare the Export
public sealed class ServicesPackage : Package
{
public ServicesPackage()
{
}
protected override void Initialize()
{
base.Initialize();
var editorCompositionContainer =
VsCompositionContainer.Create(
this.ComponentModel.GetCatalog("FooCatalog"),
new VsExportProviderSettings(
null, VsExportProvidingPreference.Default, VsExportSharingPolicy.ShareEverything, false));
}
}
To declare the export we use the PartCreationPolicy attribute to specify that the part will be a singleton. (Just to mimic VS Services behavior)
[Export(typeof(IMyMEFService))]
[PartCreationPolicy(CreationPolicy.Shared)]
public class MyMEFService : IMyMEFService
{
public MyMEFService()
{
}
public void DoStuff()
{
}
}
Consuming the export:
var componentModel = this.GetService(typeof(SComponentModel)) as IComponentModel;
var myMEFService = componentModel.GetExtensions<IMyMEFService>().FirstOrDefault();
myMEFService.DoStuff();
No lazy loading:
Before we can consume the export the container should be created.
But for that, the VS Package should be initialized. Therefore the package should be loaded before any other component tries to consume the exports.
This can be achieved with the ProvideAutoLoad attribute and the NoSolution context guid. But that means the VSPackage will be loaded at VS startup and therefore we loose the VS package lazy initialization feature that the ProvideService model has.
Maybe in the next VS10 Beta version we see a core package that creates a general purpose container that can be used to add global services, but for the time being there is no such container and you need to create a VS package that creates it.
Stay tuned,
Pablo