Sitecore

Sitecore 7, MVC, JSON-Serialization and maxJsonLength


Since Sitecore 7 and MVC there is a problem with JSON-Serialization, if you use aliases and set the data source to a folder with a large amount of items (in my case approx. 2000 items).

I can’t switch to item buckets at the moment, because  a console application fetches products from a customer url , create items and push them to a Sitecore data storage.

If you want to add a new alias and choose a linked item, nothing happened. A short view in console reveals the problem:

Object {statusCode: 500, error: Object}

error: Object
message: "Error during serialization or deserialization using the JSON JavaScriptSerializer. The length of the string exceeds the value set on the maxJsonLength property."
__proto__: Object

statusCode: 500

Hmmmkay! Almighty Google has a lot of hits if you search for the problem, up to custom JsonValueProvider or configuration examples, but none of them worked for me. Together with Sitecore support we found a solution for that: A custom JsonSerializer, a PreprocessRequest-Pipeline and a .config-file which should be placed in App_Config/Include. Here is the code:

JsonSerializer

using System;
using System.Globalization;
using System.Web.Script.Serialization;
using Sitecore.Configuration;
using Sitecore.Diagnostics;
using Sitecore.ItemWebApi.Serialization;

namespace SitecoreContrib.Serialization
{
  public class JsonSerializer : ISerializer
  {
    public string SerializedDataMediaType
    {
      get { return "application/json"; }
    }

    public string Serialize(object value)
    {
      Assert.ArgumentNotNull(value, "value");
      var scriptSerializer = new JavaScriptSerializer { MaxJsonLength = 2097152 };
      var setting = Settings.GetSetting("JsonSerialization.MaxLength");
      int result;
      if (!string.IsNullOrEmpty(setting) && !scriptSerializer.MaxJsonLength.ToString(CultureInfo.InvariantCulture).Equals(setting, StringComparison.InvariantCultureIgnoreCase) && int.TryParse(setting, out result))
      {
        scriptSerializer.MaxJsonLength = result;
      }
      return scriptSerializer.Serialize(value);
    }
  }
}

The PreprocessRequest-Pipeline


using System;
using System.Web;
using Sitecore.Diagnostics;
using Sitecore.ItemWebApi;
using Sitecore.Pipelines.PreprocessRequest;
using Sitecore.Support.ItemWebApi.Serialization;
using Sitecore.Text;
using Sitecore.Web;

namespace SitecoreContrib.Serialization.Pipelines.PreprocessRequest
{
  public class RewriteUrl
  {
    public virtual void Process(PreprocessRequestArgs arguments)
    {
      Assert.ArgumentNotNull(arguments, "arguments");
      try
      {
        var localPath = arguments.Context.Request.Url.LocalPath;
        if (!localPath.StartsWith("/-/item/")) {
          return;
        }
        var context = new Sitecore.ItemWebApi.Context
        {
          Serializer = new JsonSerializer(),
          Version = GetVersion(localPath)
        };
        Sitecore.ItemWebApi.Context.Current = context;
        Rewrite(arguments.Context);
      }
      catch (Exception ex)
      {
        Logger.Error(ex);
      }
    }

    private static int GetVersion(string path)
    {
      Assert.ArgumentNotNull(path, "path");
      var str = path.TrimStart(new char[1] {'/'}).Split(new char[1] {'/' })[2];
      Assert.IsTrue(str.StartsWith("v"), "Version token is wrong.");
      int result;
      Assert.IsTrue(int.TryParse(str.Replace("v", string.Empty), out result), "Version not recognized.");
      return result;
    }

    private static void Rewrite(HttpContext context)
    {
      Assert.ArgumentNotNull(context, "context");
      var url = context.Request.Url;
      var strArray1 = url.LocalPath.TrimStart(new char[1] {'/'}).Split(new char[1] {'/'});
      var length = strArray1.Length - 3;
      var strArray2 = new string[length];
      Array.Copy(strArray1, 3, strArray2, 0, length);
      var str1 = string.Format("/{0}", string.Join("/", strArray2));
      var str2 = url.Query.TrimStart(new char[1] {'?'});
      WebUtil.RewriteUrl(new UrlString
      {
        Path = str1,
        Query = str2
      }.ToString());
    }
  }
}

The .config-file

<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:set="http://www.sitecore.net/xmlconfig/set">
  <sitecore>
    <pipelines>
      <initialize>
        <processor type="Sitecore.Pipelines.Loader.ShowVersion, Sitecore.Kernel">
          <assemblies>
            <assembly id="SitecoreContrib.Serialization">/bin/SitecoreContrib.Serialization</assembly>
          </assemblies>
        </processor>
      </initialize>
      <preprocessRequest>
        <processor type="SitecoreContrib.Serialization.Pipelines.PreprocessRequest.RewriteUrl, SitecoreContrib.Serialization" patch:instead="*[@type='Sitecore.ItemWebApi.Pipelines.PreprocessRequest.RewriteUrl, Sitecore.ItemWebApi']" />
      </preprocessRequest>
    </pipelines>
    <settings>
      <!-- JsonSerialization.MaxLength
           Specifies the maximum length of JSON strings which can be serialized by the JsonSerializer.
           Value is specified in bytes. Default value: 2097152 (2 MB)
      -->
      <setting name="JsonSerialization.MaxLength" value="2147483647" />
    </settings>
  </sitecore>
</configuration>

Gotcha! From now you can configure the maxJsonLength-property for your needs.

Happy coding!

Best regards Dirk