Aleksandr Ivanov
Aleksandr Ivanov

Reputation: 2786

Nancy FX capitalizes keys in dictionaries on model binding

I'm trying to post a JSON to NancyFx. The JSON is the following:

{  
   "prop1": 1,
   "entries":{  
      "Entry1": 1,
      "entry2": 2
   }
}

On server side I created a corresponding model:

public class Model
{
    public int Prop1 { get; set; }
    public IDictionary<string, object> Entries { get; set; }
}

entries field in JSON has a dynamic structure, and because of that IDictionary<string, object> is used in the model.

And then I bind the model:

this.Bind<Model>();

Model is created successfully but problem is that in Entries dictionary both keys are in capital case. For me case is very important and I expect second key to be entry2, not Entry2.

I also tried to use JavaScriptConverter and JavaScriptPrimitiveConverter but in Deserialize method I get already capitalized data.

Any ideas oh how to fix that?

Upvotes: 4

Views: 544

Answers (2)

Sergej Popov
Sergej Popov

Reputation: 3021

A better option is to set JsonSettings from Bootstrapper

public class MyBootstrapper : DefaultNancyBootstrapper
{
    public MyBootstrapper () : base()
    {
        JsonSettings.RetainCasing = true;
    }
}

Implementing IModelBinder works, but it messes up other default binding settings.

Upvotes: 0

astreltsov
astreltsov

Reputation: 2061

For me this was solved by configuring JavascriptSerializer to retain casing.

Unfortunately I couldn't figure out a clean way to do this, but here's the hack I'm using for now.

    public class Model
    {
        public IDictionary<string, object> Entries { get; set; }
    }

    public class CustomModelBinder : IModelBinder
    {

        public bool CanBind(Type modelType)
        {
            return modelType == typeof(Model);
        }

        public object Bind(NancyContext context, Type modelType, object instance, BindingConfig configuration, params string[] blackList)
        {
            using (var sr = new StreamReader(context.Request.Body))
            {
                return (new JavaScriptSerializer() { RetainCasing = true }).Deserialize<Model>(sr.ReadToEnd());
            }
        }
    }

Nancy will pick up this binder at runtime, no need to explicitly register anything.

This solution is not ideal because it ignores some Nancy features like blacklists and possibly other binding configuration settings.

Upvotes: 2

Related Questions