How to fix: Multiple types were found that match the controller named issue in Sitecore Application

This blog post talks about the above mentioned MVC issue for the applications built on Sitecore. If you are here and your application doesn’t have anything to do with Sitecore you probably should look at this stackoverflow post.

In a Sitecore application, a controller gets created for two reasons 1) the controller is declared in the layout rendering and 2) when an action method from controller gets called directly (for example, application is making an ajax call). Let’s look at the following code to understand how Sitecore resolves the controller creation request.

    protected virtual IController CreateControllerInstance(RequestContext requestContext, string controllerName)
    {
      if (Sitecore.Mvc.Extensions.StringExtensions.EqualsText(controllerName, this.SitecoreControllerName))
        return this.CreateSitecoreController(requestContext, controllerName);
      if (TypeHelper.LooksLikeTypeName(controllerName))
      {
        Type type = TypeHelper.GetType(controllerName);
        if (type != (Type) null)
        {
          IController controller = DependencyResolver.Current.GetService(type) as IController ?? TypeHelper.CreateObject<IController>(type);
          if (controller != null)
            return controller;
        }
      }
      return this.InnerFactory.CreateController(requestContext, controllerName);
    }

If the controllerName is SitecoreControllerName (this is set in the Sitecore.Mvc.Config) then, code will call CreateSitecoreController special method to create that controller. If the controllerName is fully qualified type name, then Sitecore will create that type via the DependencyResolver or using TypeHelper, if DependencyResolver was not set. If none of those two conditions apply, Sitecore will pass the control over to the DefaultControllerFactory.

This issue happens when there are more than one namespace with the same controller name in the application. For example, if a third party dll in your application has a controller named AccountController and your application has a controller named AccountController which was added in the layout rendering. Then the conflict will arise because the DefaultControllerFactory would not know which controller to create. This problem can be solved easily if we assign the fully qualified class name in the layout rendering controller field as shown in the following picture.

pic1

Controller Rendering setting

That covers the first scenario, where controllers action method is used for layout rendering. But, when controller action method is used to return JSONResult for an ajax call or a view directly, there is no way to declare the controller with fully qualified name. We are going to talk about the solution for that case now, i.e. scenario 2. In this case you can create a custom route class like below. You have to specifically add the namespaces in the route. This means, you are telling DefaultControllerFactory to resolve controllers only from the namespaces added in the given route.

using Sitecore.Pipelines;
using System.Web.Mvc;
using System.Web.Routing;

namespace MyApp.Extensions
{
    public class CustomRoutes
    {
        public virtual void Process(PipelineArgs args)
        {
            RegisterRoute();
        }
        public static void RegisterRoute()
        {
            var route=RouteTable.Routes.MapRoute(
                name: "MyApp",
                url: "api/sitecore/{controller}/{action}",
                namespaces: new[] { "MyApp.Controllers", "Sitecore.Controllers" });
        }
    }
}

In addition to above code you need to create a patch config file with the following config to add that processor in the Initialize pipeline.

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <pipelines>
      <initialize>
        <processor type="MyApp.Extensions.CustomRoutes, MyApp"
                     patch:after="processor[@type='Sitecore.Mvc.Pipelines.Loader.InitializeControllerFactory, Sitecore.Mvc']"/>
      </initialize>
    </pipelines>
  </sitecore>
</configuration>

In the scenario 2, if the application has a same controller name in the included namespaces, the only way to resolve the conflict is to use unique controller name.

Reference:

Sitecore MVC and Unity

Safe Dependency Injection for MVC and WebApi within Sitecore

Changes to Dependency Injection in Sitecore 8.1

Sitecore MVC – Getting Started

Advertisements

About Himadri Chakrabarti

I am a software developer architect and a Sitecore MVP. My professional interest is everything and anything related to Software Architecture, .NET, Sitecore, Node.js, NoSQL etc. Outside of my profession, I am a hobbyist photographer. Link to my photography site http://himadriphotography.com/
This entry was posted in MVC, Sitecore and tagged , , , . Bookmark the permalink.

One Response to How to fix: Multiple types were found that match the controller named issue in Sitecore Application

  1. Or you could just use Web API controllers and decorate them with Sitecore.Services.Core.ServicesControllerAttribute. No routing or pipeline fiddling. See my post on the subject at http://www.agehrke.com/2015/08/web-api-controller-in-sitecore-8/.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s