ServiceStack.Text json deserialization создает неправильный объект вместо того, чтобы метать недопустимую строку ввода json

Когда я пытаюсь десериализовать эту недопустимую строку json (}] отсутствует в конце):

[{"ExtId":"2","Name":"VIP sj�lland","Mobiles":["4533333333","4544444444"]

Сделав это:

var result = JsonSerializer.DeserializeFromString<T>(str);    

Deserializer ServiceStack json принимает строку, но создает неправильный объект, потому что в итоге я получаю объект С#, имеющий следующие значения:

ExtId : "2"                                      // ok fine.
Name: "VIP sj�lland"                            // ok fine
Mobiles: ["4533333333","4544444444", "544444444"]// Aarg! An array with 3 objects ?!? 
                                                 // There were only two in the JSON string.

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

JsConfig.ThrowOnDeserializationError = true; 

перед вызовом DeserializeFromString, но исключение не было выбрано. В январе я задал этот вопрос Configure ServiceStack.Text, чтобы выбросить недействительный JSON, и ответ заключался в том, что ServiceStack предпочитает resilence и что я могу сделать запрос на перенос в GitHub.

Это все еще так? И кто-нибудь сделал это уже, избавив меня от неприятностей? В противном случае, у меня очень строгий график, поэтому, если у кого-то есть какой-то код или предложения о том, как создать флаг опции для того, чтобы заставить ServiceStack выбрасывать ошибки десериализации, ответьте здесь, чтобы я мог сделать это быстрее.

Ответы

Ответ 1

Это разрешено в ServiceStack.Text v4 +, который по умолчанию не заполняет неполные коллекции, например:

public class Poco
{
    public string ExtId { get; set; }
    public string Name { get; set; }
    public string[] Mobiles { get; set; }
}

var json = "[{\"ExtId\":\"2\",\"Name\":\"VIP sj�lland\",\"Mobiles\":[\"4533333333\",\"4544444444\"]";

var dto = json.FromJson<Poco[]>();

Assert.That(dto[0].ExtId, Is.EqualTo("2"));
Assert.That(dto[0].Name, Is.EqualTo("VIP sj�lland"));
Assert.That(dto[0].Mobiles, Is.Null);

Или, если это предпочтителен, можно выполнить ошибку:

JsConfig.ThrowOnDeserializationError = true;

Assert.Throws<SerializationException>(() => 
    json.FromJson<Poco[]>());

Ответ 2

С# немного придирчив, когда дело доходит до JSON. Следующее будет действительным! Обратите внимание: у меня нет анонимного массива объектов в качестве элемента по умолчанию.

{
    "ExtItem": [
        {
            "ExtId": "2",
            "Name": "VIPsj�lland",
            "Mobiles": [
                "4533333333",
                "4544444444"
            ]
        }
    ]
}

Если я создаю POCO из этого, я получаю

public class Rootobject
{
    public Extitem[] ExtItem { get; set; }
}

public class Extitem
{
    public string ExtId { get; set; }
    public string Name { get; set; }
    public string[] Mobiles { get; set; }
}

Я лично использую метод расширения для строки

public static class Extensions
{
    public  static bool DeserializeJson<T>(this String str, out T item)
    {
        item = default(T);
        try
        {
            item = new JavaScriptSerializer().Deserialize<T>(str);
            return true;
        }
        catch (Exception ex)
        {
            return false;
        }
    }
}

Это позволит мне написать:

Rootobject ext;
const string validJson = @"
{
    ""ExtItem"": [
        {
            ""ExtId"":""2"",
            ""Name"":""VIPsj�lland"",
            ""Mobiles"":[
                ""4533333333"",
                ""4544444444""
            ]
        }
    ]
}";
if (validJson.DeserializeJson(out ext))
{ //valid input 
    // following would print 2 elements : 4533333333, 4544444444
    Console.WriteLine(string.Join(", ", ext.ExtItem.First().Mobiles)); 
} //invalid input

Ответ 3

Я попробовал это, если у меня возникло исключение, когда я пропустил} в конце.

В С# формат для JSON: { "name", "value" } not [{ "name", "value" }].

class M
        {
            public string ExtId { get; set; }
            public string Name { get; set; }
            public List<string> Mobiles { get; set; }
        }

string str = "{\"ExtId\":\"2\",\"Name\":\"VIP\",\"Mobiles\":[\"4533333333\",\"4544444444\"]";

M m = JsonConvert.DeserializeObject<M>(str);

Когда вы запустите это, вы получите сообщение об ошибке, поскольку отсутствует.

Использование:

string str = "{\"ExtId\":\"2\",\"Name\":\"VIP\",\"Mobiles\":[\"4533333333\",\"4544444444\"]}";

Объект десериализован.

Вы можете увидеть JSON этого объекта:

string s = JsonConvert.SerializeObject(m);

Ответ 4

Я просто использую Newtonsoft.Json T JsonConvert.DeserializeObject<T>(string value) и генерирует исключение;

Если я использую object JsonConvert.DeserializeObject(string value) этот, он создает правильный объект, просто поместив отсутствующий }]

Я обнаружил, что это очень надежная и быстрая библиотека.