As it was described in the previous entry, the idea of the action providers is to allow to gather cross-cutting concerns into more generic (not in the C# terms, but functionalities/features) bag than a derivation from a generic controller. To provide a working example, a standard CRUD operations can be taken into the consideration. Let’s take a look into another gist.
I do hate static code, but for sake of a simplicity all the CRUD operations were moved to a static class, CrudActions. All of them are pretty simple, as they use an entity model binder introduced in the former blog entries. For instance, when an entity edit result is posted to the server, a model binder will take care of updating the entity, so the entity being passed to the [HttpPost]Edit will be already altered with the changes made by a user.
The very second step was discovering all of the CrudActions. It is made by a DetachedActionProvider which caches information in a ReadWriteCache taken from the MVC internals. To close the open generic of CrudActions, an entity type with an id’s type is needed. The entity type information is retrieved from a IEntityController, which is a simple markup convention (you can come up with a name convention, or delegate it somewhere else), for attaching to a controller a handled entity type. The id metadata are gathered from the NHibernate’s ISessionFactory. Once the data are retrieved, the CrudActions generic class definition can be turned into a closed generic and the specific method can be found.
Wait a second… how do we transform a MethodInfo into an ActionDescriptor? First, the method infos are wrapped with an ActionInfo instance (it caches attributes as well as the method info itself). Next, the ActionInfos, those who applies (HttpGet, HttpPost, etc.), are passed to the ReflectedMvc to create a ReflectedActionDescriptor.
At the end I left some bitterness about MVC internalization policy. I must admit, that I don’t understand internalizing types or constructors or any members which could be helpful for future app development. That case applies to the ReflectedActionDescriptor ctor, which (the public one) throws an exception if the method passed to it is a static method. The other, non-checking one, is of course internalized. I’m asking: why? The internalization should be used as a last resort, no as a ‘hide it, because I cannot predict if someone doesn’t want to crush MVC in his project’ rule.
Hope you like the action provider extension point and will use it for cross-cutting, ‘I can compose, not only derive from a generic class’ actions in your controllers.
Yep, that’s another post in a series which will finally bring so-called detached actions to live. Today I’ll introduce the concept of action providers, something, which in my opinion is missing in the ASP MVC.
The standard pipeline of handling a request in ASP MVC starts with creating a controller with implementation of IControllerFactory. The default one, uses simply a controller constructor, passing none to it. Then controller is returned and its Controller.ActionInvoker is queried for a method/action matching the request. If none is found, an exception is thrown. After reading this paragraph it must be clear, that adding an action to a controller can be done also on the action invoker level.
The IActionInvoker interface provides not much space to move, since it has only one, bool method. If we take a look into the default implementation, ControllerActionInvoker, we can find an interesting method called: FindAction. The method returns something called ActionDescriptor and in the default implementation scans only the controller type in the search of the actions. But we can describe some static methods and return them during the search. To address it, I introduced an IActionProvider interface, which can be (almost) easily implemented.
To get the whole idea, take a look into GIST: https://gist.github.com/989733
As always, all needed types should be registered in the Windsor Container and resolved with it (in the current example, the only need which is to be resolved is IControllerFactory, or nothing if you register service location with the new feature from MVC 3).
Hope you like it. In the very next post, the final implementation of one of IActionProviders.
It’s time to provide some more features before getting deeper into detached actions for ASP MVC. The very first requirement is to have a nice model binder, which not only uses a container to resolve all the parameter types (my previous model binder), but also is intelligent enough to deal with an ORM of your choice. And mine is NHibernate.
Before getting the final snippet, a few assumptions has to be made:
- No hierarchies are bound automatically. For sake of simplicity, we’re considering only simple entities with no derivations.
- All the collections, which reflect one-to-many relationships, are bound in the inverse way. The one ending has its collection marked as inversed (there is a drop-down for the many ending, where the parent can be selected)
To provide you with a better way of viewing the code, I pushed the file to the gisthub and it can be located under: https://gist.github.com/984310. It’s good time to take a look into it.
As you can see, the binder does some pretty nice things:
- It still uses container as the fallback for all the models. Using Windsor you’d better be sure to have all of them registered
- If entity has its id passed, it uses session to get it; otherwise a new instance is created. It’s up to you to save it in your session
Maybe it addresses a few concerns, like handling entities and non entities in one binder, but it’d be easier to get the whole idea having one straight class without the whole projects.
This is my default model binder in my current project so far and it provides strong base for the detached actions mechanism, which will be covered in the very next entry.