Using controllers from an external assembly in ASP.NET Web API

Β· 536 words Β· 3 minutes to read

In general, in my day-to-day job, I am working with large enterprise web applications, where clean projects, noise reduction and test driven development are holy. Therefore I have always been a big fan of placing MVC controllers outside the actual web application project, in a separate class library (or libraries).

With MVC it was very simple, but recently I faced this challenge in Web API, and turns out neither passing the assembly name through MapHttpRoute (not supported) or using something like ControllerBuilder.Current.DefaultNamespaces is not a viable option. So I turned to Henrik Nielsen for advice, and sure enough, he helped immediately. Let’s explore the solution.

The solution πŸ”—

The solution to our problem is to write a custom class implementing IAssemblyResolver, hook it up to the GlobalConfiguration and add a list of our additionally required assemblies there.

Let’s assume we have our controllers in a library called ControllersLibrary, and it is a regular class library, located at c:/libs/controllers/ControllersLibrary.dll.

If you are not used to that concept, think about that for a second. Controllers don’t really need Global.asax or anything else the web application provides; they might as well live elsewhere, and be loaded from there - think of it as plugging them into your application.

To achieve all this, following Henrik’s advice, you need a class implementing IAssemblyResolver, for example, your own class derived from System.Web.Http.Dispatcher.DefaultAssembliesResolver:

public class AssembliesResolver : DefaultAssembliesResolver  
{  
public override ICollection<Assembly> GetAssemblies()  
{  
ICollection<Assembly> baseAssemblies = base.GetAssemblies();  
List<Assembly> assemblies = new List<Assembly>(baseAssemblies);  
var controllersAssembly = Assembly.LoadFrom(@"C:libscontrollersControllersLibrary.dll");  
baseAssemblies.Add(controllersAssembly);  
return assemblies;  
}  
}  

So effectively you are asking the framework to get its default assemblies (located under web app’s /bin/ folder), and merge your custom assembly in there as well.

There is a kicker though. It only works with the latest Web API source (nighly Nuget packages or build from Codeplex), not with RC.

Making this work with ASP.NET Web API RC πŸ”—

Why? The issue here is that the class from which we inherited from, DefaultAssembliesResolver, is internal in RC, and was only made public after the RC was released.

However, there is no reason why you wouldn’t write your own class implementing IAssembliesResolver. Let’s modify the above code to get there:

public class CustomAssemblyResolver : IAssembliesResolver  
{  
public ICollection<Assembly> GetAssemblies()  
{  
List<Assembly> baseAssemblies = AppDomain.CurrentDomain.GetAssemblies().ToList();  
var controllersAssembly = Assembly.LoadFrom(@"C:libscontrollersControllersLibrary.dll");  
baseAssemblies.Add(controllersAssembly);  
return baseAssemblies;  
}  
}  

So this looks very similar to the bit above. Instead of inheriting from DefaultAssembliesResolver, we implement IAssembliesResolver directly, and read the assemblies from AppDomain ourselves (that’s what DefaultAssembliesResolver does), and merge in a List with our custom assembly.

Now we are ready to plug this in, and as expected this has to be done in Global.asax, or any other class you have to manipulate GlobalConfiguration.

GlobalConfiguration.Configuration.Services.Replace(typeof(IAssembliesResolver), new CustomAssemblyResolver());  

Trying it out πŸ”—

Now assuming that:

  • ValuesController is located under main web application project
  • ExternalController is located in C:libscontrollersControllersLibrary.dll

You can see that it’s easy to navigate to both of them:

Summary πŸ”—

It is really easy to separate your controllers from your web application. While this might seem like an overkill in small projects, in large enterprise scale applications, it is an absolute lifesaver. I hope I don’t have to convince anyone who much it helps maintainability, testability and mess/noise reduction.

Enjoy!

About


Hi! I'm Filip W., a cloud architect from ZΓΌrich πŸ‡¨πŸ‡­. I like Toronto Maple Leafs πŸ‡¨πŸ‡¦, Rancid and quantum computing. Oh, and I love the Lowlands 🏴󠁧󠁒󠁳󠁣󠁴󠁿.

You can find me on Github and on Mastodon.

My Introduction to Quantum Computing with Q# and QDK book
Microsoft MVP