I am looking at the ASP.NET MVC 4 Beta version of Web API.
What is the proper approach to implementing IHttpControllerFactory.CreateController(HttpControllerContext controllerContext, string controllerName)? The DefaultHttpControllerFactory has two interesting behaviours in addition to resolving the Type from the
controllerName:
1. It creates an HttpControllerDescriptor and attaches it to the HttpControllerContext. If you don't do this bad things happen!
2. To create the actual instance, it calls the registered IHttpControllerActivator passing the HttpControllerContext and calls its Create method passing through the HttpControllerContext and whatever Type it has resolved. The DefaultHttpControllerActivator
ends up using the DependencyResolver.GetService to get the actual instance.
From this, should we surmise that IHttpControllerFactory is really more of a controller name -> Type resolver? Should we write and register custom IHttpControllerActivators to call our IoC of choice, or should we call IoC directly from the factory implementation?
FYI, here is my custom factory at the moment:
public class CustomHttpControllerFactory : IHttpControllerFactory
{
private readonly HttpConfiguration _configuration;
private DefaultHttpControllerFactory _defaultHttpControllerFactory;
public CustomHttpControllerFactory(HttpConfiguration configuration)
{
_configuration = configuration;
_defaultHttpControllerFactory = new DefaultHttpControllerFactory(configuration);
}
public IHttpController CreateController(HttpControllerContext controllerContext, string controllerName)
{
if(// some condition that means I should handle this myself)
{
Type controllerType = // some code to get my type
controllerContext.ControllerDescriptor =
new HttpControllerDescriptor(_configuration, controllerName, controllerType);
var controller = controllerContext.ControllerDescriptor.HttpControllerActivator.Create(
controllerContext, controllerType);
controllerContext.Controller = controller;
return controller;
}
return _defaultHttpControllerFactory.CreateController(controllerContext, controllerName);
}
public void ReleaseController(IHttpController controller)
{
if (// this is a type I am responsible for)
{
// do what I need to do
}
_defaultHttpControllerFactory.ReleaseController(controller);
}
}
You can register this in Application_Start with:
var configuration = GlobalConfiguration.Configuration;
configuration.ServiceResolver.SetService( typeof(IHttpControllerFactory), new CustomHttpControllerFactory(configuration));
Much like within MVC, the controller factory is responsible for finding a controller instance to handle a request. And, much like within MVC, the default implementation uses the controller activator as an implementation detail in the process: it maps a controller
name into a type, and then utilitizes the activator to create the instance of the type. We separated these two behaviors primarily for DI container authors who cannot support creating arbitrary types like concrete controller types (for example, MEF will not
manufacture arbitrary types).
That said, you could certainly implement a controller factory without using the controller activator. That's up to the factory developer.
Thanks Brad. Are you able to address the specific question of contract? i.e. What must or should implementers do in addition to returning the instance?
It looks like we should be creating and attatching the HttpControllerDescriptor to the controllerContext? Is this right, and is there anything else that should be done?
I have a question about Areas. Will you include the Areas support into DefaultHttpControllerFactory? Because, I think it will be very useful. For now, to implement this functionality you have to rewrite HttpControllerFactory from scratch.
james-world
Member
103 Points
50 Posts
Implementing IHttpControllerFactory.CreateController
Feb 17, 2012 11:41 AM|LINK
I am looking at the ASP.NET MVC 4 Beta version of Web API.
What is the proper approach to implementing IHttpControllerFactory.CreateController(HttpControllerContext controllerContext, string controllerName)? The DefaultHttpControllerFactory has two interesting behaviours in addition to resolving the Type from the controllerName:
1. It creates an HttpControllerDescriptor and attaches it to the HttpControllerContext. If you don't do this bad things happen!
2. To create the actual instance, it calls the registered IHttpControllerActivator passing the HttpControllerContext and calls its Create method passing through the HttpControllerContext and whatever Type it has resolved. The DefaultHttpControllerActivator ends up using the DependencyResolver.GetService to get the actual instance.
From this, should we surmise that IHttpControllerFactory is really more of a controller name -> Type resolver? Should we write and register custom IHttpControllerActivators to call our IoC of choice, or should we call IoC directly from the factory implementation?
FYI, here is my custom factory at the moment:
public class CustomHttpControllerFactory : IHttpControllerFactory { private readonly HttpConfiguration _configuration; private DefaultHttpControllerFactory _defaultHttpControllerFactory; public CustomHttpControllerFactory(HttpConfiguration configuration) { _configuration = configuration; _defaultHttpControllerFactory = new DefaultHttpControllerFactory(configuration); } public IHttpController CreateController(HttpControllerContext controllerContext, string controllerName) { if(// some condition that means I should handle this myself) { Type controllerType = // some code to get my type controllerContext.ControllerDescriptor = new HttpControllerDescriptor(_configuration, controllerName, controllerType); var controller = controllerContext.ControllerDescriptor.HttpControllerActivator.Create( controllerContext, controllerType); controllerContext.Controller = controller; return controller; } return _defaultHttpControllerFactory.CreateController(controllerContext, controllerName); } public void ReleaseController(IHttpController controller) { if (// this is a type I am responsible for) { // do what I need to do } _defaultHttpControllerFactory.ReleaseController(controller); } }You can register this in Application_Start with:
bradwils
Contributor
5779 Points
691 Posts
Microsoft
Re: Implementing IHttpControllerFactory.CreateController
Feb 17, 2012 01:57 PM|LINK
Much like within MVC, the controller factory is responsible for finding a controller instance to handle a request. And, much like within MVC, the default implementation uses the controller activator as an implementation detail in the process: it maps a controller name into a type, and then utilitizes the activator to create the instance of the type. We separated these two behaviors primarily for DI container authors who cannot support creating arbitrary types like concrete controller types (for example, MEF will not manufacture arbitrary types).
That said, you could certainly implement a controller factory without using the controller activator. That's up to the factory developer.
james-world
Member
103 Points
50 Posts
Re: Implementing IHttpControllerFactory.CreateController
Feb 17, 2012 02:57 PM|LINK
Thanks Brad. Are you able to address the specific question of contract? i.e. What must or should implementers do in addition to returning the instance?
It looks like we should be creating and attatching the HttpControllerDescriptor to the controllerContext? Is this right, and is there anything else that should be done?
bradwils
Contributor
5779 Points
691 Posts
Microsoft
Re: Implementing IHttpControllerFactory.CreateController
Feb 19, 2012 07:01 PM|LINK
Yes, that is currently part of the contract, though it's not obvious right now.
Malkov
Member
18 Points
11 Posts
Re: Implementing IHttpControllerFactory.CreateController
Mar 26, 2012 09:08 AM|LINK
I have a question about Areas. Will you include the Areas support into DefaultHttpControllerFactory? Because, I think it will be very useful. For now, to implement this functionality you have to rewrite HttpControllerFactory from scratch.
panesofglass
Member
730 Points
237 Posts
Re: Implementing IHttpControllerFactory.CreateController
Mar 26, 2012 05:29 PM|LINK
This answered my question, as well. Thanks!
Malkov
Member
18 Points
11 Posts
Re: Implementing IHttpControllerFactory.CreateController
Mar 26, 2012 07:57 PM|LINK
I've created a post about how to implement the HttpControllerFactory to support Areas:
http://netmvc.blogspot.com/2012/03/aspnet-mvc-4-webapi-support-areas-in.html
And now i can just specify area name in MapHttpRoute in the Global.asax file:
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{area}/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);