Helix, 8.2 DI and An error occurred when trying to create a controller of type ‘ScBasics.Feature.Nav.NavController’. Make sure that the controller has a parameterless public constructor

Challenge:

The best part of our lives is, Whatever/However experience you are you will face one exception/error which challenges your experience. And that’s what happened with me recently. And I am sure you agree — That’s when your basics come to rescue — Same was the case in my case.

We were deploying Helix based solution which was working like a charm in local. [In case you haven’t heard of Helix/Habitat yet – Which I don’t expect to be the case. But If heard and not explored/clear on it. Then this post might help you]

https://i0.wp.com/www.ybrikman.com/assets/img/blog/docker/say-works-on-my-machine.jpg

But as you know “life is not as easy as it seems to be” When we deployed it on Dev/QA environment. We met following error:

Sitecore.Mvc.Diagnostics.ControllerCreationException was unhandled by user code
  ControllerName=Navigation
  HResult=-2146233088
  Message=Could not create controller: ‘Navigation’.
The item being rendered is: ‘/sitecore/content/SCBasics/Home’.
The context item is: ‘/sitecore/content/SCBasics/Home’.
The current route url is: ‘{*pathInfo}’. This is the default Sitecore route which is set up in the ‘InitializeRoutes’ processor of the ‘initialize’ pipeline.
  Source=Sitecore.Mvc
  StackTrace:
       at Sitecore.Mvc.Controllers.SitecoreControllerFactory.CreateController(RequestContext requestContext, String controllerName)
       at Sitecore.Mvc.Controllers.ControllerRunner.GetController()
       at Sitecore.Mvc.Controllers.ControllerRunner.Execute()
       at Sitecore.Mvc.Presentation.ControllerRenderer.Render(TextWriter writer)
       at Sitecore.Mvc.Pipelines.Response.RenderRendering.ExecuteRenderer.Render(Renderer renderer, TextWriter writer, RenderRenderingArgs args)
       at Sitecore.Mvc.Pipelines.Response.RenderRendering.ExecuteRenderer.Process(RenderRenderingArgs args)
       at (Object , Object[] )
       at Sitecore.Pipelines.CorePipeline.Run(PipelineArgs args)
       at Sitecore.Pipelines.DefaultCorePipelineManager.Run(String pipelineName, PipelineArgs args, String pipelineDomain)
       at Sitecore.Mvc.Pipelines.PipelineService.RunPipeline[TArgs](String pipelineName, TArgs args)
       at Sitecore.Mvc.Pipelines.Response.RenderPlaceholder.PerformRendering.Render(String placeholderName, TextWriter writer, RenderPlaceholderArgs args)
       at (Object , Object[] )
       at Sitecore.Pipelines.CorePipeline.Run(PipelineArgs args)
       at Sitecore.Pipelines.DefaultCorePipelineManager.Run(String pipelineName, PipelineArgs args, String pipelineDomain)
       at Sitecore.Mvc.Pipelines.PipelineService.RunPipeline[TArgs](String pipelineName, TArgs args)
       at Sitecore.Mvc.Helpers.SitecoreHelper.Placeholder(String placeholderName)
       at ASP._Page_Views_Website_Layouts_Default_cshtml.Execute() in c:\…..\Website\Views\Website\Layouts\Default.cshtml:line 38
       at System.Web.WebPages.WebPageBase.ExecutePageHierarchy()
       at System.Web.Mvc.WebViewPage.ExecutePageHierarchy()
       at System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage)
       at System.Web.Mvc.Html.PartialExtensions.Partial(HtmlHelper htmlHelper, String partialViewName, Object model, ViewDataDictionary viewData)
       at Sitecore.Mvc.Presentation.ViewRenderer.Render(TextWriter writer)
  InnerException:
       HResult=-2146233079
       Message=An error occurred when trying to create a controller of type ‘SCBasics.Feature.Navigation.Controllers.NavigationController’. Make sure that the controller has a parameterless public constructor.
       Source=System.Web.Mvc
       StackTrace:
            at System.Web.Mvc.DefaultControllerFactory.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType)
            at System.Web.Mvc.DefaultControllerFactory.CreateController(RequestContext requestContext, String controllerName)
            at Sitecore.Mvc.Controllers.SitecoreControllerFactory.CreateController(RequestContext requestContext, String controllerName)
       InnerException:
            HResult=-2147467261
            Message=Context is null
            Source=Glass.Mapper
            StackTrace:
                 at Glass.Mapper.AbstractService..ctor(Context glassContext) in c:\TeamCity\buildAgent\work\8567e2ba106d3992\Source\Glass.Mapper\AbstractService.cs:line 103
                 at lambda_method(Closure , ServiceProvider )
                 at Sitecore.Mvc.Controllers.SitecoreDependencyResolver.GetService(Type serviceType)
                 at System.Web.Mvc.DefaultControllerFactory.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType)
            InnerException:

You might say that’s easy “controller has a parameterless public constructor.” – Just add this and it should work 🙂 But same code works in local, and second thing is we are using Sitecore 8.2 DI for controllers. And in that case, it is not required to have parameter less public constructor. And if it is same error for you, it means that, your DI is not working.

You are also facing same error? Then this post might help you!

Solution:

So, as every developer on this earth does, We also did a quick Google search and found following links, which were helpful:

  1. http://sitecore.stackexchange.com/questions/2929/no-parameterless-constructor-defined-for-this-object-after-upgrade-to-sitecore8 – dnstommy’s reply gave us a hint that our DI is not working
  2. Apart from this there were no any good results on web. So, now it was time to look back in code and see how things laid down and figuring out what’s going on

Troubleshooting process:

public static class ServiceCollectionExtensions
  {
    public static void AddMvcControllersInCurrentAssembly(this IServiceCollection serviceCollection)
    {
      AddMvcControllers(serviceCollection, Assembly.GetCallingAssembly());
    }
// Removed for simplicity
 public static void AddMvcControllers(this IServiceCollection serviceCollection, params Assembly[] assemblies)
    {
      var controllers = GetTypesImplementing<IController>(assemblies)
        .Where(controller => controller.Name.EndsWith("Controller", StringComparison.Ordinal));

      foreach (var controller in controllers)
      {
        serviceCollection.AddTransient(controller);
      }
    }
// Removed for simplicity
}
  • Looking at code, it makes sense. But it works in local. But not when deployed. So, after troubleshooting a bit. Thought to log what we get in calling assembly — We also faced challenge here. Sitecore logging will not work at this layer. So, we had to use plain old StreamWriter [You remember, I told. Basics!?]
  • The log results were something like this:
    • In local : In Calling assembly we were getting Feature assemblies
    • In QA/Dev : In Calling assembly we were getting Sitecore.Kernel
  • It was clear, Assembly.GetCallingAssembly() was misbehaving
  • Quick Google search reveled the mystery, GetCallingAssembly works different in Debug and Release mode https://blog.codeinside.eu/2014/10/05/Be-Aware-Of-Asssembly-GetCallingAssembly-Behaviour/
  • In local we are using Debug mode and on QA/Dev – We are using Release mode
  • Root cause “The JIT compiler moves code around to optimize for performance. Small methods (up to about 56 Byte IL-Code if I remember it right) can be inlined where the method call was before. But the compiler does this only in release, not in debug mode. Also when attaching the debugger to our release build the JIT compiler stopped inlining to enable debugging and our bug was gone” : Source : http://www.ticklishtechs.net/2010/03/04/be-careful-when-using-getcallingassembly-and-always-use-the-release-build-for-testing/
  • Last post had an approach — Adding [MethodImplAttribute(MethodImplOptions.NoInlining)] on method — Which somehow didn’t work for us
  • But then thought to look for some better options and we found it!
  • We added one more Service configurator in Foundation which has following code:
namespace SCBasics.Foundation.DependencyInjection.Services
{
    public class RegisterAllFeatureControllers : IServicesConfigurator
    {
        public void Configure(IServiceCollection serviceCollection)
        {
            /* We were facing issue in Release mode
               Which was not resolving  
            */
            serviceCollection.AddMvcControllers("SCBasics.Feature.*");
        }
    }
}
  • Above code, uses an alternate method for adding MVC Controllers and best part of this approach is. You no need to register your controllers, which you added in feature project. This foundation project will automatically do it! [BTW, Nothing is automatic, we wrote one time code for it ;-)]

Happy Coding! 🙂

How I learnt Sitecore MVC?

Challenge:

Before few months back. I started delving in to Sitecore MVC. Before that I knew basics of it. But no hands on. As I was busy with launching other site. Initially when I searched I found the lot of articles and blogs which scared me! You too?! Google can give you results. But which are best and which are not. You can find it out either trying or finding out other folks who already tried and provide good articles. So, while working I took some notes and I promised my self that once I am done I will share with you. So, you may get benefited out of it.

Sounds interesting? You are also searching for something like that? Then go ahead..!

Solution:

As per my practice. I started understanding ASP.NET MVC. Because i always believe in starting from basics. And following links helped me to do so:

  1. http://www.asp.net/mvc/overview/getting-started/recommended-resources-for-mvc
  2. http://www.asp.net/mvc/videos/pluralsight-aspnet-mvc-5-fundamentals
  3. https://mva.microsoft.com/en-US/training-courses/introduction-to-asp-net-mvc-8322?l=nKZwZ8Zy_3504984382
  4. http://www.w3schools.com/aspnet/mvc_intro.asp
  5. http://www.asp.net/mvc/overview/getting-started/mvc-learning-sequence
  6. https://msdn.microsoft.com/en-us/library/dd381612%28v=vs.100%29.aspx
  7. https://msdn.microsoft.com/en-us/library/dd381412%28v=vs.100%29.aspx

Then moved to Sitecore MVC:

  1. http://www.sitecore.net/learn/blogs/business-blogs/technical-trends/posts/2012/06/mvc-and-sitecore-651-overview.aspx
  2. http://www.sitecore.net/learn/blogs/technical-blogs/john-west-sitecore-blog/posts/2015/02/how-is-sitecore-mvc-different-from-aspnet-mvc.aspx
  3. https://sdn.sitecore.net/upload/sitecore7/72/sitecore_mvc_developer_guide_72-a4.pdf
  4. http://sitecore-community.github.io/docs/sitecore-mvc/
  5. http://sitecore-community.github.io/docs/sitecore-mvc/creating-project/
  6. http://www.joe-stevens.com/2014/08/17/sitecore-mvc-tutorial-creating-your-first-sitecore-mvc-website/
  7. https://github.com/Sitecore-Community/sample-sitecore-mvc

I liked following excerpt from Lars – Especially RCMV and this diagram!

MVC stands for Model, View and Controller, though I have never understood the order of the abbreviation (by my limited intellect, RCMV would have been more appropriate, with a Route being a significant part of the equation).
Essentially, the request lifecycle of MVC is a Route (usually something that parses the http request) points to a Control (some .net code) which generates a Model (object), which is parsed by a View (usually a Razor view).
MVC Request Lifecycle
This approach is distinctly different from Web Forms, because it requires more code plumbing to create the page, and with less automated code reuse. On the other hand, the developer has more rigid control of the code executed on the page, and the data delivered to the output. Also, not to forget, MVC makes unit testing easier as (most of/all) the code usually is executed in the controller part of the lifecycle.

In my opinion, MVC is well suited for web sites with application functionality (e.g. HTML 5 applications).

Okay, enough theory. I know you developers! 🙂 We need some action now. So, thought to look for some quick start application tried lot of things. But few things were out dates or not properly documented. Finally Martina’s video helped me to give a hands on. I strongly recommend you to follow exercise given in tutorial. It will give you good hands on experience. Which will boost your confidence and clarify your concepts a lot!

I faced some challenges in quick start. But life is NULL without challenge. And your best learnings come out of a challenging situation only. Here are few blog posts helped me to come out of it:

  1. http://sitecoreskills.blogspot.in/2014/06/preparing-sitecore-72-and-mvc-in-visual.html
  2. http://www.seanholmesby.com/fixing-visual-studio-intellisense-in-sitecore-mvc-views/ – Especially for Intellisense
    1. If you are using Project and Webroot model then make sure you copy web.config from Sitecore root to project
    2. Make sure Sitecore.MVC is there in reference
    3. Sitecore.MVC and Sitecore.Kernel – Is Copy Local  true
    4. Or final resort copy all webroot/bin assemblies to project/bin
  3. http://stackoverflow.com/questions/24147846/system-web-webpages-html-htmlhelper-does-not-contain-a-definition-for-sitecor/24152053#24152053

MVC is fun! It is like Maths — Once you understand it. You would like to do it again and again!

Further reading:

  1. http://blog.alen.pw/2012/08/learning-sitecore-mvc-part-1.html
  2. http://blog.alen.pw/2012/08/learning-sitecore-mvc-part-2.html
  3. http://www.matthewdresser.com/sitecore/moving-to-sitecore-mvc
  4. http://techitpro.com/sitecore-mvc/http://www.dotnet-tricks.com/Tutorial/mvc/a9P1010113-MVC-Areas-with-example.html
  5. http://www.codeproject.com/Articles/714356/Areas-in-ASP-NET-MVC
  6. https://community.sitecore.net/developers/f/8/t/108s
  7. https://sitecore.unic.com/2015/06/24/the-sitecore-mvc-puzzle