2014-01-09 3 views
0

У меня есть проблема в котором я хочу, чтобы создать поле JSON, где имя поля, как известно, во время выполнения, например:Json.Net выдает ошибку при создании моего обычая JsonConverter

{ "known_at_run_time": ["test","test","test"] } 

Так что я попытался реализации это так , но всякий раз, когда я запускаю свой модульный тест, я получаю сообщение о том, что мой пользовательский JsonConverter не может быть создан. Вот мой код:

TermFilter.cs

public enum ExecutionType { plain, fielddata, @bool, and, or } 

[JsonObject(MemberSerialization.OptIn)] 
public class TermFilter 
{ 
    #region PROPERTIES 
    private JsonTuple query; 

    private ExecutionType execution; 
    private string _execution; 

    private bool _cache; 
    #endregion 

    #region CONSTRUCTOR 
    public TermFilter() 
    { 
     try 
     { 
      this.query = null; 
      this.Execution = ExecutionType.plain; 
      this.Cache = true; 
     } 
     catch(Exception) 
     { 
      throw; 
     } 
    } 

    public TermFilter(ExecutionType execution) 
     : this() 
    { 
     try 
     { 
      this.Execution = execution; 
     } 
     catch (Exception) 
     { 
      throw; 
     } 
    } 

    public TermFilter(ExecutionType execution, bool cache) 
     : this(execution) 
    { 
     try 
     { 
      this.Cache = cache; 
     } 
     catch (Exception) 
     { 
      throw; 
     } 
    } 

    public TermFilter(string field, string[] terms) 
     :this() 
    { 
     try 
     { 
      this.Query = new JsonTuple(field, new HashSet<string>(terms)); 
     } 
     catch (Exception) 
     { 
      throw; 
     } 
    } 
    #endregion 

    #region GET/SET 

    //[JsonProperty(ItemConverterType = typeof(JsonTupleConverter))] 
    //[JsonProperty] 
    [JsonConverter(typeof(JsonTupleConverter))] 
    public JsonTuple Query 
    { 
     get { return query; } 
     set { query = value; } 
    } 

    public ExecutionType Execution 
    { 
     get { return execution; } 
     set 
     { 
      execution = value; 
      _execution = value.ToString(); 
     } 
    } 

    [JsonProperty(PropertyName = "execution")] 
    public string _Execution 
    { 
     get { return _execution; } 
     set { _execution = value; } 
    } 

    [JsonProperty(PropertyName = "_cache")] 
    public bool Cache 
    { 
     get { return _cache; } 
     set { _cache = value; } 
    } 
    #endregion 

    #region METHODS 
    public TermFilter AddTerm(string term) 
    { 
     try 
     { 
      if (!this.query.Data.Contains(term)) 
       this.query.Data.Add(term); 

      return this; 
     } 
     catch (Exception) 
     { 
      throw; 
     } 
    } 

    public string ToJson() 
    { 
     try 
     { 
      var settings = new JsonSerializerSettings(); 
      settings.TypeNameHandling = TypeNameHandling.Objects; 
      settings.Converters.Add(new JsonTupleConverter(new Type[] { typeof(JsonTuple) })); 
      settings.NullValueHandling = NullValueHandling.Ignore; 

      return JsonConvert.SerializeObject(this, settings); 

      //return JsonConvert.SerializeObject(this, Formatting.None, new JsonTupleConverter(typeof(JsonTuple))); 
      //return JsonConvert.SerializeObject(this, Formatting.None, new JsonConverter[] { new JsonTupleConverter(typeof(JsonTuple)), }); 

     } 
     catch (Exception) 
     { 
      throw; 
     } 
    } 
    #endregion 
} 

JsonTuple.cs

public class JsonTuple 
{ 
    #region PROPERTIES 
    private string field; 
    private HashSet<string> data; 
    #endregion 

    #region CONSTRUCTOR 
    public JsonTuple() 
    { 
     try 
     { 
      this.field = null; 
      this.data = null; 
     } 
     catch (Exception) 
     { 
      throw; 
     } 
    } 

    public JsonTuple(string field, HashSet<string> data) 
    { 
     try 
     { 
      this.field = field; 
      this.data = data; 
     } 
     catch (Exception) 
     { 
      throw; 
     } 
    } 
    #endregion 

    #region GET/SET 
    public string Field 
    { 
     get { return field; } 
     set { field = value; } 
    } 

    public HashSet<string> Data 
    { 
     get { return data; } 
     set { data = value; } 
    } 
    #endregion 

    #region METHODS 
    public string ToJson() 
    { 
     try 
     { 
      return JsonConvert.SerializeObject(this, Formatting.None, new JsonTupleConverter(typeof(JsonTuple))); 
     } 
     catch (Exception) 
     { 
      throw; 
     } 
    } 
    #endregion 
} 

JsonTupleConverter.cs

public class JsonTupleConverter : JsonConverter 
{ 
    private readonly Type[] _types; 

    public JsonTupleConverter(params Type[] types) 
    { 
     try 
     { 
      _types = types; 
     } 
     catch (Exception) 
     { 
      throw; 
     } 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     try 
     { 
      JToken t = JToken.FromObject(value); 

      if (t.Type != JTokenType.Object) 
      { 
       t.WriteTo(writer); 
      } 
      else if (!_types.Any(_t => _t == value.GetType())) 
      { 
       serializer.Serialize(writer, value); 
      } 
      else 
      { 
       JsonTuple tuple = (JsonTuple)value; 
       if ((tuple != null) && (tuple.Field != null) && (tuple.Data != null)) 
       { 
        JToken entityToken = null; 
        if (tuple.Data != null) 
         entityToken = JToken.FromObject(tuple.Data); 

        JObject o = new JObject(); 
        o.AddFirst(new JProperty(tuple.Field, entityToken)); 
        o.WriteTo(writer); 
       } 
      } 
     } 
     catch (Exception) 
     { 
      throw; 
     } 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     throw new NotImplementedException("Unnecessary because CanRead is false. The type will skip the converter."); 
    } 

    public override bool CanRead 
    { 
     get { return false; } 
    } 

    public override bool CanConvert(Type objectType) 
    { 
     return _types.Any(t => t == objectType); 
    } 
} 

Test.cs

[TestMethod] 
public void TermFieldSertialization() 
{ 
    try 
    { 
     TermFilter filter = new TermFilter("test.field", new string[] {"test1", "test2", "test3"}); 
     Assert.IsNotNull(filter); 

     string sampleJson = filter.ToJson(); 
     Assert.IsNotNull(sampleJson); 
    } 
    catch (Exception) 
    { 
     throw; 
    } 
} 

Что я делаю неправильно? Любая информация поможет.

+0

При отправке кода, создающего такую ​​ошибку, лучше всего уменьшить код до минимума, необходимого для воспроизведения ошибки. Видя стену кода, вы сможете заставить многих потенциальных ответчиков игнорировать ваш вопрос. –

+0

Выберите лучший заголовок вопроса. Просто повторяющиеся теги и/или имя класса без какой-либо другой информации обычно считаются неприемлемыми для SO.Заголовок вопроса должен быть однострочным * сводкой * его содержимого - так же, как и с темами электронной почты. –

ответ

1

Во-первых, попробуйте удалить атрибут [JsonConverter] из Query свойство вашего TermFilter класса. Вам это не нужно, потому что свойство Query является JsonTuple, и вы уже передаете экземпляр своего JsonTupleConverter методу JsonConvert.SerializeObject() внутри вашего метода ToJson(), указав, что он может обрабатывать JsonTuples. Это избавит вас от ошибки.

Однако есть еще одна проблема. Кажется, что вы намерены получить свойство Query для сериализации в JSON, но, как сейчас, это не произойдет. Это связано с тем, что вы отметили свой класс TermFilter[JsonObject(MemberSerialization.OptIn)], а свойство Query не имеет атрибута [JsonProperty], чтобы сигнализировать, что вы хотите, чтобы это свойство было включено в выход. Вам нужно будет добавить [JsonProperty("query")], чтобы исправить это. Как только вы это сделаете, вы должны получить ожидаемый результат.

В стороне, вам не нужно ломать исключения, если вы только намерены бросить их снова, не делая ничего с ними. Я вижу этот шаблон повсюду в вашем коде. Вместо этого просто не используйте try/catch; он делает то же самое и сделает ваш код намного более кратким. Только поймайте исключение, если вы собираетесь его обрабатывать.

+0

Спасибо за совет! – MrX

1

Я думаю, что ваше исключение происходит потому, что JsonTupleConverter не имеет конструктора без параметров.

public JsonTupleConverter() { } 

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

Возможно, вам следует просто сериализовать его как словарь? Например.

var myDict = new Dictionary<string, List<string>> 
{ 
    { "known_at_run_time", new List<string> { "test","test","test" } } 
}; 
string ser = JsonConvert.SerializeObject(myDict); 
// ser is {"known_at_run_time":["test","test","test"]} 
Смежные вопросы