Malformed querystring breaks Sitecore Experience Forms (Value cannot be null. Parameter name: key)

We noticed a bug in Sitecore Experience Forms 9.0.2: when you access a page that has a form passing wrong query string parameters, the system responds with a Runtime Error.

The Error…

For instance, the following url:
==> http://local.myclient.com/myform?good=1&bad

Because the query string parameter “bad” does not have a corresponding value, accessing this page will result in a error like this:

Server Error in ‘/’ Application.


Value cannot be null.
Parameter name: key

Description: An unhandled exception occurred.

Exception Details: System.ArgumentNullException: Value cannot be null.
Parameter name: key

Source Error:

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.


Stack Trace:

[ArgumentNullException: Value cannot be null.
Parameter name: key]
   System.ThrowHelper.ThrowArgumentNullException(ExceptionArgument argument) +49
   System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add) +14789605
   System.Linq.Enumerable.ToDictionary(IEnumerable`1 source, Func`2 keySelector, Func`2 elementSelector, IEqualityComparer`1 comparer) +283
   Sitecore.ExperienceForms.Mvc.Pipelines.RenderForm.SetFormParameters.Process(RenderFormEventArgs args) +639
   (Object , Object ) +14
   Sitecore.Pipelines.CorePipeline.Run(PipelineArgs args) +484
   Sitecore.Pipelines.DefaultCorePipelineManager.Run(String pipelineName, PipelineArgs args, String pipelineDomain, Boolean failIfNotExists) +236
   Sitecore.Pipelines.DefaultCorePipelineManager.Run(String pipelineName, PipelineArgs args, String pipelineDomain) +22
   Sitecore.Mvc.Pipelines.PipelineService.RunPipeline(String pipelineName, TArgs args) +195
   Sitecore.Mvc.Pipelines.PipelineService.RunPipeline(String pipelineName, TArgs args, Func`2 resultGetter) +161
   Sitecore.ExperienceForms.Mvc.Html.HtmlExtensions.BeginRenderRouteForm(HtmlHelper htmlHelper, FormViewModel model, Boolean isPost) +301
   ASP._Views_FormBuilder_Form_cshtml.Execute() in D:GitADMIsrcFeatureADMI.JobsFormscodeobjCodeGenViewsFormBuilderForm.cshtml:6
   System.Web.WebPages.WebPageBase.ExecutePageHierarchy() +252
   System.Web.Mvc.WebViewPage.ExecutePageHierarchy() +148
   System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage) +122
   System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context) +375
   System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList`1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult) +88
   System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList`1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult) +775
   System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList`1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult) +775
   System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList`1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult) +775
   System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext controllerContext, IList`1 filters, ActionResult actionResult) +81
   System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +701

Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.7.3282.0


 

…The root cause…

Decompiling the “Sitecore.ExperienceForms.Mvc.dll” shows exactly where the issue happens: one of the processors at the <forms.renderForm>, more precisely the “Sitecore.ExperienceForms.Mvc.Pipelines.RenderForm.SetFormParameters” processor, is missing a simple null check.

 

…And the fix!

Of course, I have tried to extend the original class, to apply my fix in a more “surgical” way. However, due to a private property, we will need to re-implement the whole class.

The fix is very simple and will only require a class and a config patch.

STEP 1 – Create the new SetFormParameters processor

Here is how your processor class should look like. The code is fully commented to show exactly what has been modified and what is simply copied/pasted from the original class.

using System.Collections.Generic;
using System.Linq;
using System.Web.Routing;
using Sitecore.Diagnostics;
using Sitecore.ExperienceForms;
using Sitecore.ExperienceForms.Mvc.Pipelines.RenderForm;
using Sitecore.Mvc.Configuration;
using Sitecore.Mvc.Pipelines;

namespace MyProject.Pipelines.Forms
{
 /// <summary>
 /// Pipeline that implements a fix for Sitecore.ExperienceForms.Mvc.Pipelines.RenderForm.SetFormParameters
 /// The fix is basically a null check in a LINQ expression, but due to a private property
 /// we are forced to re-implement the whole class in order apply the fix
 /// </summary>
 public class SetFormParameters : MvcPipelineProcessor<RenderFormEventArgs>
 {
    /// <summary>
    /// This is the private property that we need to re-implement
    /// </summary>
    private readonly IQueryStringProvider _queryStringProvider;

    /// <summary>
    /// Constructor is identical to the original class
    /// </summary>
    /// <param name="queryStringProvider"></param>
    public SetFormParameters(IQueryStringProvider queryStringProvider)
    {
       Assert.ArgumentNotNull((object) queryStringProvider, nameof (queryStringProvider));
       this._queryStringProvider = queryStringProvider;
    }

    /// <summary>
    /// This is where the fix is applied - whole method is identical to original
    /// except for the LINQ expression in the end of the file
    /// </summary>
    /// <param name="args"></param>
    public override void Process(RenderFormEventArgs args)
    {
       Assert.ArgumentNotNull((object) args, nameof (args));
       args.FormHtmlId = args.HtmlHelper.AttributeEncode(args.HtmlHelper.ViewData.TemplateInfo.GetFullHtmlFieldId(args.ViewModel.ItemId));
       args.Attributes = new Dictionary<string, object>()
       {
          {
             "enctype",
             (object) "multipart/form-data"
          },{
             "id",
             (object) args.FormHtmlId
          },{
             "data-sc-fxb",
             (object) args.ViewModel.ItemId
          }
       };
       if (!string.IsNullOrEmpty(args.ViewModel.CssClass))
          args.Attributes.Add("class", args.ViewModel.CssClass);
       args.QueryString = new RouteValueDictionary(
          _queryStringProvider.QueryParameters.AllKeys
             .Where(p=>p!=null) // <--- The fix itself is here
             .ToDictionary(key => key,
                key => (object) _queryStringProvider.QueryParameters[key]));
                args.RouteName = MvcSettings.SitecoreRouteName;
    }
 }
}

STEP 2 – Register your processor to make it load instead of the original one

And of course, let’s register the processor using the following config patch:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
 <sitecore>
 
 <forms.renderForm>
 <processor type="MyProject.Pipelines.Forms.SetFormParameters, MyProject" resolve="true" 
 patch:instead="processor[@type='Sitecore.ExperienceForms.Mvc.Pipelines.RenderForm.SetFormParameters, Sitecore.ExperienceForms.Mvc']"/>
 </forms.renderForm>

 </pipelines>
 </sitecore>
</configuration>

 

Is this officially recognized as a bug?

Yes, it a known bug, registered with the public reference number 324457 (More information about public reference numbers can be found here: https://kb.sitecore.net/articles/853187)

This bug was resolved in Sitecore 9.3, as can be seen in the release notes:
https://dev.sitecore.net/Downloads/Sitecore%20Experience%20Platform/93/Sitecore%20Experience%20Platform%2093%20Initial%20Release/Release%20Notes

 

“​​​​If you use a query string that contains parameter without a value to open a page that contains a form, the form is not rendered​.”

Publicado em Experience Forms, Sitecore 9

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>