Question

This is related to this question, but in this case it's not something I am returning but rather the model binding. I am using Postmark to handle incoming emails, which posts to a page with a JSON payload.

I have a model as below and an action that takes in this JSON payload (posted with application/json) and processes it.

public class EmailModel
{
    public IDictionary<string, string> Headers { get; set; }
    public string From { get; set; }
    public string Cc { get; set; }
    public string HtmlBody { get; set; }
    public string TextBody { get; set; }
    public string ReplyTo { get; set; }
    public string Tag { get; set; }
    public string To { get; set; }
    public string MessageID { get; set; }
    public string MailboxHash { get; set; }
    public string Subject { get; set; }
    public List<Attachment> Attachments { get; set; }
}

public class Attachment
{
    public string Content { get; set; }
    public int ContentLength { get; set; }
    public string ContentType { get; set; }
    public string Name { get; set; }

}

This works fine for small attachments, but for anything that exceeds the default maxJsonLength property causes an error in deserialization. ("Error during serialization or deserialization using the JSON JavaScriptSerializer. The length of the string exceeds the value set on the maxJsonLength property.") Because I want to accept image attachments, this means most images fail.

I've tried updating the web.config, but as per those other threads, this doesn't help for MVC controllers. I figure I can probably do what was mentioned in a custom IModelBinder, but I'm struggling with how to intercept the deserialization. (In other words, it still fails because the deserialization has happened already).

Any suggestions? I'm sure it's just something stupid that I'm missing....

Was it helpful?

Solution

You could write a custom JsonValueProviderFactory that uses Json.NET:

public sealed class JsonDotNetValueProviderFactory : ValueProviderFactory
{
   public override IValueProvider GetValueProvider(ControllerContext controllerContext)
   {
        if (controllerContext == null)
            throw new ArgumentNullException("controllerContext");

        if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
            return null;

        var reader = new StreamReader(controllerContext.HttpContext.Request.InputStream);
        var bodyText = reader.ReadToEnd();

        return String.IsNullOrEmpty(bodyText) ? null : new DictionaryValueProvider<object>(JsonConvert.DeserializeObject<ExpandoObject>(bodyText, new ExpandoObjectConverter()) , CultureInfo.CurrentCulture);
    }
}

and in your Application_Start:

ValueProviderFactories.Factories.Remove(ValueProviderFactories.Factories.OfType<JsonValueProviderFactory>().FirstOrDefault());
ValueProviderFactories.Factories.Add(new JsonDotNetValueProviderFactory());
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top