A while ago I had blogged about Service Composition using ServiceStack and MEF. With ServiceStack no longer free, I figured I’d try the same thing using ASP.NET Web Api from Big Mike. The result was…not as good.
To make it work, I had to rely heavily on Autofac and their Web Api Integration packages.
First I defined the IComposableApiMetadata interface which is to be implemented by my clients. It’s 2 methods are pretty simple: one takes a ContainerBuilder to allow them to inject anything extra as per their needs, while the other returns the specific Assembly from which the ApiControllers would be loaded.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public interface IComposableApiMetadata | |
{ | |
void Compose(ContainerBuilder builder); | |
Assembly ApiAssembly(); | |
} |
Here’s an example of what it would look like
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[Export(typeof(IComposableApiMetadata))] | |
public class ExternalApiMetadata : IComposableApiMetadata { | |
public void Compose(ContainerBuilder builder) { | |
builder.Register(e => new BookRepository()).As<IBookRepository>().InstancePerApiRequest(); | |
} | |
public Assembly ApiAssembly() { | |
return typeof(BooksController).Assembly; | |
} | |
} |
With that done, all that should be left is calling it from the Application Start (i.e. Global.asax) right?
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class WebApiApplication : System.Web.HttpApplication { | |
[ImportMany] | |
List<IComposableApiMetadata> m_composers; | |
private CompositionContainer m_container; | |
protected void Application_Start() { | |
var catalog = new AggregateCatalog(); | |
var servicesFolder = @"C:\dllFolder"; | |
catalog.Catalogs.Add(new DirectoryCatalog(servicesFolder)); | |
m_container = new CompositionContainer(catalog); | |
m_container.ComposeParts(this); | |
var builder = new ContainerBuilder(); | |
foreach (var composableApiMetadata in m_composers) { | |
composableApiMetadata.Compose(builder); | |
builder.RegisterApiControllers(composableApiMetadata.ApiAssembly()); | |
} | |
var container = builder.Build(); | |
var resolver = new AutofacWebApiDependencyResolver(container); | |
GlobalConfiguration.Configuration.DependencyResolver = resolver; | |
AreaRegistration.RegisterAllAreas(); | |
WebApiConfig.Register(GlobalConfiguration.Configuration); | |
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); | |
RouteConfig.RegisterRoutes(RouteTable.Routes); | |
BundleConfig.RegisterBundles(BundleTable.Bundles); | |
} | |
} |
Sadly, this isn’t enough. I had to actually reference the client dlls in my ASP.NET MVC project, which somewhat defeats the purpose of using such a Composer. Sure I could have a process automatically update the csproj with the adequate references but that feels silly.
I am sure there is a better way and once I find it I will make sure to blog about it. Until then I hope the hour or so I spent on this will help one of you guys out there.