Привязка модели к словарю в Нанси


Я не могу привязать JSON к Dictionary<string,string> в Нэнси.

Этот маршрут:

Get["testGet"] = _ =>
{
    var dictionary = new Dictionary<string, string>
    {
         {"hello", "world"},
         {"foo", "bar"}
    };

    return Response.AsJson(dictionary);
};

Возвращает следующий JSON, как и ожидалось:

{
    "hello": "world",
    "foo": "bar"
}

Когда я пытаюсь отправить этот точный JSON обратно на этот маршрут:

Post["testPost"] = _ =>
{
    var data = this.Bind<Dictionary<string, string>>();
    return null;
};

Я получаю исключение:

Значение "[Hello, world] "не относится к типу" System.Строка " и не может будет использоваться в этой общей коллекции.

Можно ли привязать к Dictionary<string,string>, используя привязку модели по умолчанию Nancys, и если да, то что я здесь делаю неправильно?

1 5

1 ответ:

У Нэнси нетвстроенного преобразователя для словарей. Из-за этого вам придется использовать BindTo<T>() Вот так

var data = this.BindTo(new Dictionary<string, string>());

Который будет использовать CollectionConverter. Проблема в том, что это будет только добавлять строковые значения, поэтому если вы отправите

{
    "hello": "world",
    "foo": 123
}

Ваш результат будет содержать только ключ hello.

Если вы хотите записать все значения в виде строк, даже если они не представлены как таковые, то вам нужно будет использовать пользовательский IModelBinder.

Это преобразует все значения в строки и возвращают a Dictionary<string, string>.

public class StringDictionaryBinder : IModelBinder
{
    public object Bind(NancyContext context, Type modelType, object instance, BindingConfig configuration, params string[] blackList)
    {
        var result = (instance as Dictionary<string, string>) ?? new Dictionary<string, string>();

        IDictionary<string, object> formData = (DynamicDictionary) context.Request.Form;

        foreach (var item in formData)
        {
            var itemValue = Convert.ChangeType(item.Value, typeof (string)) as string;

            result.Add(item.Key, itemValue);
        }

        return result;
    }

    public bool CanBind(Type modelType)
    {
        // http://stackoverflow.com/a/16956978/39605
        if (modelType.IsGenericType && modelType.GetGenericTypeDefinition() == typeof (Dictionary<,>))
        {
            if (modelType.GetGenericArguments()[0] == typeof (string) &&
                modelType.GetGenericArguments()[1] == typeof (string))
            {
                return true;
            }
        }

        return false;
    }
}

Нэнси автоматически зарегистрирует это для вас, и вы можете связать свои модели, как обычно.

var data1 = this.Bind<Dictionary<string, string>>();
var data2 = this.BindTo(new Dictionary<string, string>());