Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Kieron McIntyre 116 posts 359 karma points
    Nov 22, 2013 @ 12:08
    Kieron McIntyre
    0

    "Ambiguous match found" using T4MVC, Umbraco 6 and hijacking routes

    In my current Umbraco 6 build, I am using T4MVC and when I hijack a route I get the following exception:

    [AmbiguousMatchException: Ambiguous match found.]
       System.RuntimeType.GetMethodImpl(String name, BindingFlags bindingAttr, Binder binder, CallingConventions callConv, Type[] types, ParameterModifier[] modifiers) +11199352
       System.Type.GetMethod(String name) +28
       Umbraco.Web.Mvc.RenderActionInvoker.FindAction(ControllerContext controllerContext, ControllerDescriptor controllerDescriptor, String actionName) +100
       System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +100
       System.Web.Mvc.<>c__DisplayClass1d.b__19() +23
       System.Web.Mvc.Async.<>c__DisplayClass1.b__0() +19
       System.Web.Mvc.Async.<>c__DisplayClass8`1.b__7(IAsyncResult _) +10
       System.Web.Mvc.Async.WrappedAsyncResult`1.End() +62
       System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +57
       System.Web.Mvc.Async.<>c__DisplayClass4.b__3(IAsyncResult ar) +23
       System.Web.Mvc.Async.WrappedAsyncResult`1.End() +62
       System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) +47
       System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.EndExecute(IAsyncResult asyncResult) +10
       System.Web.Mvc.<>c__DisplayClass8.b__3(IAsyncResult asyncResult) +25
       System.Web.Mvc.Async.<>c__DisplayClass4.b__3(IAsyncResult ar) +23
       System.Web.Mvc.Async.WrappedAsyncResult`1.End() +62
       System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +47
       System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +9
       System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +9688704
       System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

     

    I know what is causing it ... T4MVC creates a duplicate Index() which is confusing the  Umbraco.Web.Mvc.RenderActionInvoker.FindAction() call since there are now two Index() actions. However, the T4MVC action is marked with the `[NonAction]` attributea dn s should be ignored by Umbraco's RendeActionInvoker - but it isn't.

    But how do I fix this? The only thing I can think of is to introduce a custom RenderActionInvoker that ignores methods with such an attribute but then I would also need to override the default ControllerFactory too. 

    Any ideas? There must be projects using T4MVC in Umbraco successfully.

  • Sebastiaan Janssen 5044 posts 15475 karma points MVP admin hq
    Nov 22, 2013 @ 12:21
    Sebastiaan Janssen
    0

    Sounds like it needs to be fixed in the core, created an issue : http://issues.umbraco.org/issue/U4-3675

  • Kieron McIntyre 116 posts 359 karma points
    Nov 22, 2013 @ 12:53
    Kieron McIntyre
    1

    Ok, yes I have a solution but you have to:

    1. Override the ControllerFactory with a new ControllerFactory that inherits from RenderControllerFactory
    2. Create a new ControllerActionInvoker
    So, in the global.asax:
    protected override void OnApplicationStarted(object sender, EventArgs e)
    {
        IControllerFactory factory = new CustomControllerFactory();
        ControllerBuilder.Current.SetControllerFactory(new CustomControllerFactory());
    }
    
    Using the following classes:
    public class CustomControllerFactory : RenderControllerFactory
    {
        public override IController CreateController(RequestContext requestContext, string controllerName)
        {
            var instance = base.CreateController(requestContext, controllerName);
            var controllerInstance = instance as Controller;
            if (controllerInstance != null)
            {
                controllerInstance.ActionInvoker = new CustomRenderActionInvoker();
            }
    
            return instance;
        }
    }
    and
    public class CustomRenderActionInvoker : ControllerActionInvoker
    {
        protected override ActionDescriptor FindAction(ControllerContext controllerContext, ControllerDescriptor controllerDescriptor, string actionName)
        {
            var ad = base.FindAction(controllerContext, controllerDescriptor, actionName);
            if (ad == null)
            {
                if (controllerContext.Controller is RenderMvcController)
                {
                    return new ReflectedActionDescriptor(
                        controllerContext.Controller.GetType().GetMethods().First(x =>
                            x.Name == "Index" &&
                            !x.GetCustomAttributes(typeof(NonActionAttribute), false).Any()),
                        "Index",
                        controllerDescriptor
                    );
                }
            }
            return ad;
        }
    }
    
    These are essentially just modified duplicates of what already exists in the Umbraco source.
  • lucuma 261 posts 563 karma points
    Feb 15, 2014 @ 21:51
    lucuma
    0

    Thanks for posting that code. The current documentation isn't valid in that this still (v7.0.3) generates an ambiguous error when following the guide with regards to route hijacking and inheriting form RenderModel.

  • Kieron McIntyre 116 posts 359 karma points
    Feb 25, 2014 @ 12:47
    Kieron McIntyre
    0

    If you want to use this with the Hybrid framework (as I recently did), change the conditional line to read:

    if (controllerContext.Controller is IRenderMvcController)

  • Shannon Deminick 1524 posts 5269 karma points MVP 2x
    Mar 18, 2014 @ 04:27
    Shannon Deminick
    100

    This is fixed in 6.2/7.1

  • Kieron McIntyre 116 posts 359 karma points
    Mar 18, 2014 @ 07:47
    Kieron McIntyre
    0

    Awesome, thanks Shannon.

Please Sign in or register to post replies

Write your reply to:

Draft