-
Notifications
You must be signed in to change notification settings - Fork 3
2012 01 10 re mix encapsulate and share asp net mvc controller actions
Published on January 10th, 2012 at 10:09
Jan Jonas has written a blog post about how to encapsulate commonly used controller actions using mixins with ASP.NET MVC 3. I think that it’s a really cool idea to use re-mix for this, however Jan is facing a few stumbling blocks that I want to comment upon. (Actually, I wanted to post this as a comment to his blog post, but for some reason, the comment form isn’t working.)
I understand Jan is saying that ASP.NET MVC doesn't find the action methods added by mixins because the proxies generated by re-mix don't inherit from ControllerBase
. Therefore he needs to implement a custom ControllerActionInvoker
to get ASP.NET MVC to invoke action methods introduced by mixins.
Actually, the proxies re-mix generates do inherit from the mixed classes; in Jan’s example, those are Controller1Controller
and Controller2Controller
, i.e., the proxies do inherit (indirectly) from ControllerBase
. Then why isn’t ASP.NEW MVC finding those controller actions by default?
Maybe the problem is that the proxies implement the mixin interfaces (in the example, IEchoControllerMixin
) explicitly, and ASP.NET MVC probably doesn't search for explicit interface implementations. However, one can tell re-mix to implement interface members publicly, either by putting the MemberVisibilityAttribute
on the methods in the mixin, or by specifying IntroducedMemberVisibility = MemberVisibility.Public
when applying the UsesAttribute
. (You can also derive a custom attribute from UsesAttribute
that sets IntroducedMemberVisibility
to MemberVisibility.Public
by default, since you'll always want to do that for controller mixins.)
If, for some reason, that still doesn't work, one could put the CreateActionInvoker
override into the target class (Controller1Controller
) rather than the mixin, or into a different mixin (e.g., a ControllerMixinSupportMixin
). That would enable one to use multiple controller mixins without generating conflicts on the CreateActionInvoker
method.
A second problem Jan is facing is that the controller mixins can’t access the protected members declared by the controller and its base classes. However, re-mix allows this: to give mixins access to protected members of the target class, one can specify a custom interface as the TTarget
parameter to the Mixin<TTarget>
base class. Just define a public interface redeclaring all the controller methods the mixins should be able to access and specify that for the TTarget
type parameter. The target class doesn't actually have to implement that interface, it just needs to provide all the members, with either public or protected visibility.
I’ve adapted Jan’s example accordingly:
public interface IMixedController
{
ViewResult View();
ViewResult View (string viewName);
...
}
public class EchoControllerMixin : Mixin<IMixedController>, IEchoControllerMixin
{
public ActionResult Echo(string id)
{
var result = new ContentResult();
var controllerName =
Target.ControllerContext.RouteData.Values["controller"].ToString();
result.Content = string.Format(
"re-mix added Echo action to controller '{0}'<hr/>You said: {1}",
controllerName,
!string.IsNullOrEmpty(id) ? id : "<i>nothing</i>");
return result;
}
}
public class UsesControllerMixinAttribute : UsesAttribute
{
public UsesControllerMixinAttribute (Type mixinType)
: base (mixinType)
{
IntroducedMemberVisibility = MemberVisibility.Public;
}
}
[UsesControllerMixin(typeof(EchoControllerMixin))]
public class Controller1Controller : Controller
{
}
Feel free to ask at the discussion list (http://groups.google.com/group/re-motion-users) if you face any other issues with re-mix.
Update (2012-01-11): Fixed base attribute ctor call in code.
Update (2012-01-16): As mentioned in the comments, Jan Jonas has published a blog post discussing my suggestions.
Hi Fabian, I’ve written a follow-up post http://blog.janjonas.net/2012-01-15/asp_net-mvc_3-remix-library-add-controller-actions-mixins-part2 that shows how to integrate your suggestions into my first approach. Thanks again!
Cool, I’ve added a link to the blog post.