Corey Peplau wrote this – WFFM conflict with Unity DI and a lesson on how Sitecore community is so amazing

This blog was since the beginning, a space to share my own experiences with Sitecore development, always trying to bring that something new, not easily seen, or showing my interpretation of common problems. But this time I need to break my own rule and bring a story starred by another person. I’m talking about my good friend Corey Smith, the most willful person I ever met.

First a small parable

An engineer was hired to fix a complex machine, which he did in less than an hour by simply twisting a single screw.

  • How much it cost? Asks the client.
  • 10 thousand dollars, sir…
  • But that is a lot of money just to twist a screw! I need you to do an invoice with details of your job to justify this price.

And the invoice listed:

  • Twist a screw: $ 5.00
  • Know what screw to twist: $ 9,995.00

Corey is a step ahead of this story and managed to not only twist the right screw, but made that remotely, and for free.

The WFFM issue

Everything started when, at my first project as new member of Nish Tech Inc, I had to install WFFM 8.2 rev. 170413 (Update-3) up above an existent solution. Starting from there, any MVC WFFM form were dying with the following error:

Error Rendering Controller: Sitecore.Forms.Mvc.Controllers.FormController, Sitecore.Forms.Mvc. Action: Index: Could not create controller: ‘Sitecore.Forms.Mvc.Controllers.FormController, Sitecore.Forms.Mvc’. The item being rendered is: ‘/sitecore/content/Website/Home/Community/Cincinnati’. The context item is: ‘/sitecore/content/Website/Home/Community/Cincinnati’. The current route url is: ‘{*pathInfo}’. This is the default Sitecore route which is set up in the ‘InitializeRoutes’ processor of the ‘initialize’ pipeline.

 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)

Inner Exception: Resolution of the dependency failed, type = “Sitecore.Forms.Mvc.Controllers.FormController”, name = “(none)”. Exception occurred while: while resolving. Exception is: InvalidOperationException – The current type, Sitecore.Forms.Mvc.Interfaces.IRepository`1[Sitecore.Forms.Mvc.Models.FormModel], is an interface and cannot be constructed. Are you missing a type mapping? ———————————————– At the time of the exception, the container was: Resolving Sitecore.Forms.Mvc.Controllers.FormController,(none) Resolving parameter “repository” of constructor Sitecore.Forms.Mvc.Controllers.FormController(Sitecore.Forms.Mvc.Interfaces.IRepository`1[[Sitecore.Forms.Mvc.Models.FormModel, Sitecore.Forms.Mvc, Version=8.2.0.0, Culture=neutral, PublicKeyToken=null]] repository, Sitecore.Forms.Mvc.Interfaces.IAutoMapper`2[[Sitecore.Forms.Mvc.Interfaces.IFormModel, Sitecore.Forms.Mvc, Version=8.2.0.0, Culture=neutral, PublicKeyToken=null],[Sitecore.Forms.Mvc.ViewModels.FormViewModel, Sitecore.Forms.Mvc, Version=8.2.0.0, Culture=neutral, PublicKeyToken=null]] mapper, Sitecore.Forms.Mvc.Interfaces.IFormProcessor`1[[Sitecore.Forms.Mvc.Models.FormModel, Sitecore.Forms.Mvc, Version=8.2.0.0, Culture=neutral, PublicKeyToken=null]] processor, Sitecore.WFFM.Abstractions.Shared.IAnalyticsTracker analyticsTracker) Resolving Sitecore.Forms.Mvc.Interfaces.IRepository`1[Sitecore.Forms.Mvc.Models.FormModel],(none)

 at Microsoft.Practices.Unity.UnityContainer.DoBuildUp(Type t, Object existing, String name, IEnumerable`1 resolverOverrides)
  at Microsoft.Practices.Unity.UnityContainer.Resolve(Type t, String name, ResolverOverride[] resolverOverrides)
  at Sitecore.Mvc.Controllers.SitecoreControllerFactory.CreateControllerInstance(RequestContext requestContext, String controllerName)
  at Sitecore.Mvc.Controllers.SitecoreControllerFactory.CreateController(RequestContext requestContext, String controllerName)

Inner Exception: The current type, Sitecore.Forms.Mvc.Interfaces.IRepository`1[Sitecore.Forms.Mvc.Models.FormModel], is an interface and cannot be constructed. Are you missing a type mapping?

 at Microsoft.Practices.ObjectBuilder2.DynamicMethodConstructorStrategy.ThrowForAttemptingToConstructInterface(IBuilderContext context)
  at lambda_method(Closure , IBuilderContext )
  at Microsoft.Practices.ObjectBuilder2.DynamicBuildPlanGenerationContext.<>c__DisplayClass1.b__0(IBuilderContext context)
  at Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy.PreBuildUp(IBuilderContext context)
  at Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context)
  at Microsoft.Practices.ObjectBuilder2.BuilderContext.NewBuildUp(NamedTypeBuildKey newBuildKey)
  at lambda_method(Closure , IBuilderContext )
  at Microsoft.Practices.ObjectBuilder2.DynamicBuildPlanGenerationContext.<>c__DisplayClass1.b__0(IBuilderContext context)
  at Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy.PreBuildUp(IBuilderContext context)
  at Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context)
  at Microsoft.Practices.Unity.UnityContainer.DoBuildUp(Type t, Object existing, String name, IEnumerable`1 resolverOverrides)

The greatness of Sitecore community

After some googling I found this article from Corey Smith, where he describes a similar issue after an upgrade, which he solved by moving his Dependency Injection declaration before the InitializeControllerFactory. I know that recent versions of WFFM are using Dependency Injection, so it sounded like a good clue to start my investigation.

But in my case we were using Unity Dependency Injection, nothing registered at Sitecore Pipeline, so I thought – why not asking Corey himself for an idea? He is a great guy, as per what we’ve seen during his presentation at the Sitecore Usergroup Brazil (video can be seen here).

What followed was a real lesson for me, breaking my paradigms of balance between personal and professional life, and showing to my amazed eyes how strong, powerful and great is the Sitecore community in general, and Corey Smith in particular.

Our investigation

It was 3rd July, I was stuck at the hotel in Cincinnati with my family and this issue to solve. Corey were safe at his home in Atlanta, at the convenient distance of a single click to interrupt the chat. We were texting like crazy thru Twitter private messages. Fortunately, we both had beers at our side, would you do without some?

We started focusing at the Unity Dependency Injection setup. Under my App_Start folder I had a class called UnityMvcActivator with following decorations above the namespace:

[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(UnityWebActivator), “Start”)]

[assembly: WebActivatorEx.ApplicationShutdownMethod(typeof(UnityWebActivator), “Shutdown”)]

namespace MyClient.Website.Core.App_Start

{

   public static class UnityWebActivator

   {

       public static void Start()

       {

Line in bold is specifically setting the start-up of Dependency Injection. That would be automatically invoking (at some point in the Application_Start event) the method Start(). The exact point, however, was a mystery for us, so we managed to increase a little of our control over this. Perhaps changing the order here would make any difference?

So we removed the line in bold, then registered the method Start as an Initialize Pipeline processor. For that, the Start signature had to change into a valid Process method, as seem below:

public void Process(PipelineArgs args)

That way we would be able to control the timing when the DI start-up would occur. Promising? I thought so! However unfortunately, no matter where the registration is made, before or after everything, still the same error was showing.

Root cause

After digging a bit more, Corey came up with the root cause, and a possible solution. Happens that the controller for WFFM forms (FormController), which is the affected class at the error message, has actually two constructors: one without any parameter

public FormController()

And a second one with more parameters

public FormController(IRepository<FormModel> repository, IAutoMapper<IFormModel, FormViewModel> mapper, IFormProcessor<FormModel> processor, IAnalyticsTracker analyticsTracker)

When Unity tries to instantiate this class it is automatically choosing the controller with most parameters. And that is making the whole thing blow up to the sky.

Temporary (quick) solution

The temporary solution we ended up doing was:

  1. Roll back the pipeline modification and allow Unity to registry itself again
  2. Add the following new line to UnityConfig, RegisterTypes method:

public class UnityConfig

{

       public static void RegisterTypes(IUnityContainer container)

       {

           // Workaround to solve WFFM issues

           container.RegisterType<FormController>(new InjectionConstructor());

What the line above does is to tell Unity to register, only at the FormController class, the constructor with no parameters. This, however, is an ad-hoc solution which brings a very important indagation: What else are we breaking in Sitecore? What other controllers and dependencies do we need to register?

“You will probably find out in production, I suppose” says Corey.

Appropriate (hard) solution

Best thing to do is to abandon Unity Dependency Injection at this project and have Sitecore’s built-in Dependency Injection (Microsoft.Extensions.DependencyInjectionto handle all injections at our system. We are not gaining anything using Unity at this project, but actually we are creating problems.

Sitecore’s OOTB Dependency Injection is shipped from factory with all proper Dependency Injection configurations. That means that all Sitecore modules play very nice with it, so the whole issue we are having with Unity, for instance, simply wouldn’t even happen at first place.  

Along with that, in Sitecore 8.2, we can do Dependency Injection into pipeline processors, which has always been a requirement at Nish Tech, and is also totally awesome!

Publicado em Bug fixing, Sitecore Community, WFFM

Leave a Reply

Your email address will not be published. Required fields are marked *

*

  Am Not Spammer

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>