Skip to content

2012 01 10 re mix encapsulate and share asp net mvc controller actions

Fabian Schmied edited this page Jan 12, 2012 · 1 revision

Published on January 10th, 2012 at 10:09

Encapsulate and share ASP.NET MVC controller actions

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.

Comments

Jan - January 15th, 2012 at 15:37

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!

Fabian Schmied - January 16th, 2012 at 08:21

Cool, I’ve added a link to the blog post.