问题
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.
回答1:
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.
来源:https://stackoverflow.com/questions/25915205/web-api-2-is-it-possible-to-load-a-route-controller-programmatically