2015-05-28 35 views
5

Nie mogę powiązać JSON z Dictionary<string,string> w Nancy.Powiązanie modelu ze Słownikiem <ciąg, ciąg> w Nancy

Trasa:

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

    return Response.AsJson(dictionary); 
}; 

zwraca następujące JSON, zgodnie z oczekiwaniami:

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

Gdy próbuję i pisać dokładnie ten JSON z powrotem do tej trasy:

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

I uzyskać wyjątek:

Wartość "[Hello, world]" nie jest typu "System.String" i nie można użyć w tej ogólnej kolekcji.

Czy można powiązać z Dictionary<string,string> przy użyciu domyślnego wiązania modelu Nancys, a jeśli tak, to co tu robię źle?

Odpowiedz

5

Nancy nie ma built-in converter dla słowników. Z tego powodu trzeba by użyć BindTo<T>() jak tak

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

który użyje CollectionConverter. Problem ze robi to jak to będzie tylko dodać wartości ciągów, więc jeśli wyślesz

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

swój wynik będzie zawierał tylko klucza hello.

Jeśli chcesz uchwycić wszystkie wartości jako ciągi znaków, nawet jeśli nie są one dostarczane jako takie, musisz użyć niestandardowego IModelBinder.

Spowoduje to konwersję wszystkich wartości na ciągi znaków i zwróci wartość 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; 
    } 
} 

Nancy automatycznie zarejestruje to za Ciebie i będziesz mogła wiązać swoje modele w normalny sposób.

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