I am currently working on an enterprise web application that uses WCF to implement a REST API. It utilizes a VirtualPathProvider to catch requests to *.svc files (which don't actually exist), and then builds them on the fly to dynamically load the associated WCF services. This allows the system to have "modules" that can be added to the application at runtime without impacting the web server or anyone using it.
What I would like to know, is if the same is conceptually possible with Web API 2. I've been doing some research, but it looks like the routes can only be configured at startup... What I was hoping for is a means to handle for non-existent routes, and basically use the controller name from the request to look-up and load the associated assembly (if it exists) while programmatically adding a new route to it.
I've just started with Web API 2 so I was hoping for some more experienced users to chime in. Basically my team is interested in switching to Web API 2 to reduce the overhead and complexity we've encountered with WCF, but this particular requirement could be a deal breaker.
by Mike Wasson. This article describes how ASP.NET Web API routes HTTP requests to controllers. Note. If you are familiar with ASP.NET MVC, Web API routing is very similar to MVC routing. The main difference is that Web API uses the HTTP verb, not the URI path, to select the action.
This article describes how ASP.NET Web API routes HTTP requests to controllers. If you are familiar with ASP.NET MVC, Web API routing is very similar to MVC routing. The main difference is that Web API uses the HTTP verb, not the URI path, to select the action. You can also use MVC-style routing in Web API.
Once a matching route is found, Web API selects the controller and the action: To find the controller, Web API adds "Controller" to the value of the {controller} variable. To find the action, Web API looks at the HTTP verb, and then looks for an action whose name begins with that HTTP verb name.
But in its version 2, instead of defining routing templates in WebApiConfig.cs, we can define these templates at the method level, in other words on the methods of the Web API controllers. This is possible using the use of the Route and RoutePrefix attributes, added to the Web API 2.
Okay, so after much research... I have tracked down the proper class to override, and can now per-request check whether or not the controller was able to be resolved, and if not, attempt to load the proper assembly into memory (based on controller name at the moment), and return the associated controller.
Here is the code:
public class CustomHttpControllerSelector : DefaultHttpControllerSelector {
private readonly HttpConfiguration _configuration;
public CustomHttpControllerSelector(HttpConfiguration configuration) : base(configuration) {
_configuration = configuration;
}
public override HttpControllerDescriptor SelectController(HttpRequestMessage request) {
HttpControllerDescriptor controller;
try {
controller = base.SelectController(request);
}
catch (Exception ex) {
String controllerName = base.GetControllerName(request);
Assembly assembly = Assembly.LoadFile(String.Format("{0}pak\\{1}.dll", HostingEnvironment.ApplicationPhysicalPath, controllerName));
Type controllerType = assembly.GetTypes()
.Where(i => typeof(IHttpController).IsAssignableFrom(i))
.FirstOrDefault(i => i.Name.ToLower() == controllerName.ToLower() + "controller");
controller = new HttpControllerDescriptor(_configuration, controllerName, controllerType);
}
return controller;
}
}
and of course you'd need to replace the service in the WebApiConfig's Register method file as such:
config.Services.Replace(typeof(IHttpControllerSelector), new CustomHttpControllerSelector(config));
There is definitely more work to be done here, but this is a good start. It allows me to dynamically add controllers to the hosting website while it's up and running, without requiring an outage.
The main issue with this code obviously is that the newly loaded controller isn't added to the list of registered controllers, so the exception is always thrown and handled on every request (for those controllers). I'm looking into whether or not I can add it to the registered list in some way, so we'll see where this leads.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With