Applications with decoupled components are often easier to build and manage. Managed Extensibility Framework (MEF) trades some modest added complexity for better decoupling. One decoupling aspect involves minimizing an application’s moving parts. The fewer the parts and the fewer the dependencies between the parts the easier an application is to manage and maintain. WCF File-less activation eliminates WCF Service .svc files. Even better though, file-less activation offers more control over ServiceHost and Service instantiation.
Control and low coupling happen when a developer combines these technologies. What follows is an approach to chaining the technologies together.
A complete review of MEF, WCF, and File-less activation is beyond the scope of this article. Instead I’ll briefly describe what role a particular technology plays in the solution. Service activation starts inside IIS with File-less activation.
IIS WCF File-less Activation
Typically IIS based WCF service class namespaces are embedded in the service endpoint .svc file like in the following sample.
<%@ServiceHost language=c# Debug="true" Service= "Test.MEFIIS.Instance.TestServiceService"%>
IIS handles activating a ServiceHost with the appropriate service class embedded in the .svc file. While the approach is straightforward; it tightly couples activating the ServiceHost with the Service. If a developer needed to change the service instance a change is also needed in the .svc file. Also the arrangement leaves little room to make some “conditional” ServiceHost or Service decision. The instantiated ServiceHost and Service instance become what is defined in the config and .svc file.
An approach that offers a developer control over the process would involve adding another layer. So, for example, with an added layer, instead of using the default ServiceHost, a developer can choose a custom ServiceHost. Also, instead of being bound to the Service in the .svc file a new layer would allow a developer to select from multiple Service implementations. Typically this means adding some indirection layer. File-less activation is such an indirection layer.
Central to file-less activation is a ServiceHostFactory. Instead of embedding a Service name in a .svc file a developer ties a “virtual” .svc file to a ServiceHostFactory. An example from the sample’s web.config follows.
<serviceHostingEnvironment> <serviceActivations> <add factory="Test.MEFIIS.Host.TestServiceHostFactory" service="MyStringParameterHere" relativeAddress="TestService1.svc" /> </serviceActivations> </serviceHostingEnvironment>
The config information directs IIS to execute the following code.
public sealed class TestServiceHostFactory : ServiceHostFactory { .... public override ServiceHostBase CreateServiceHost(string service, Uri[] baseAddresses) { return this.CreateFromMEF(baseAddresses); } }
As demonstrated in the sample; a developer overrides the CreateServiceHost method. IIS passes the “service” attribute value into the service string parameter. The baseAddresses parameter comprises the Service.svc and the Host name. ServiceHostFactory is not confined to the web.config. It can also be used in the .svc file. However, File-less activation via the web.config eliminates the .svc file altogether.
In the solution, ServiceHostFactory is simply a boot strapper for MEF. Before looking at the MEF solution portion it helps to know what MEF is and does.
MEF Overview
MEF includes classes and attributes that support component discovery and extensibility. MEF allows applications to load components without baking references into the compiled application. Two simple ideas underlie MEF solutions.
- Components providing functionality are called “Exports”.
- Components “consuming” an “Export” are called “Imports”.
So, for example, a class within an assembly may “export” functionality that another class in another assembly “imports”.
Some core MEF components are described below:
- Import and Export attributes designate the components a developer will consume or provide.
- A CompositionContainer gathers the exports and matches exports to imports. CompositionContainers can, for example, instantiate class instances and apply the instance on a class Property.
- CompositionContainers read from Catalogs. MEF components can be housed in Directories and Assemblies. A CompositionContainer works through, for example, a DirectoryCatalog to gather all MEF components in a Directory.
This is all great, but what does MEF enable?
Putting MEF to Work
While a developer could simply stop with ServiceHostFactory; leveraging MEF enables scenarios like the following.
MEF excels at locating Interface signatures and creating instances. Developers simply drop new assemblies alongside existing assemblies and new functionality is enabled. Since the developer codes to the interface and not to a class; this means unit testing can be done with simpler class interface implementations.
Versioning becomes easier because assemblies need not contain references to one another. Also Interface changes can be implemented with new interfaces without breaking backward compatibility. The older code simply invokes anything with the old implementation.
Finally, ServiceHostFactory could be reusable if the MEF implementation follows the ideas outlined in this article. The MEF solution portion code follows.
public sealed class TestServiceHostFactory : ServiceHostFactory { [ImportMany(typeof(ICreateHost))] private IEnumerable<ICreateHost> Instances { get; set; } private void PopulateInstances() { var catalog = new DirectoryCatalog(AppDomain.CurrentDomain.BaseDirectory + "bin"); using (var container = new CompositionContainer(catalog)) { container.ComposeParts(this); } } private ServiceHost CreateFromMEF(Uri[] baseAddresses) { PopulateInstances(); ServiceHost host = null; foreach (var inst in Instances) { host = inst.Create(baseAddresses); } return host; } .... }
ImportMany creates Instances of any class that Exports ICreateHost. ImportMany accommodates multiple ICreateHost implementations. So a single TestServiceHostFactory could work for many ICreateHost instances. DirectoryCatalog collects Exported MEF components and the ComposeParts method applies the components to anything requiring an Import.
Creating the WCF ServiceHost happens in the ICreateHost implementation. Following is the ICreateHost implementation.
[Export(typeof(ICreateHost))] public class TestCustomServiceHost : ICreateHost { #region ICreateHost Members public ServiceHost Create(Uri[] baseAddresses) { var service = new TestServiceService(); var host = new WebServiceHost(service,baseAddresses); var binding = new WebHttpBinding(); binding.Security.Mode = WebHttpSecurityMode.TransportCredentialOnly; binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows; var ep = host.AddServiceEndpoint(typeof(ITestServiceContract), binding, ""); var sdb = host.Description.Behaviors.Find<ServiceDebugBehavior>(); sdb.HttpHelpPageEnabled = false; return host; } #endregion }
The arrangement also makes it easier to test outside of IIS in a self-hosting scenario. The sample solution creates a WebServiceHost, but could have created any ServiceHost type. A ServiceHost instance passes up through the layers, out of the Factory, and IIS does the rest.
Conclusion
Combining MEF with IIS File-less activation is a recipe for a more modular and decoupled WCF IIS Service. File-less activation and the accompanying ServiceHostFactory indirection creates a MEF boot-strapping platform. MEF, in turn, makes File-less activation reusable.