Десериализация Json с индексом

Я пытаюсь десериализовать ответ JSon из веб-службы, но я не знаю, как это сделать.

Вот пример:

{
    "0": {
        "course_info": {
            "course_id": 3,
            "code": "",
            "course_name": "Fiches Docebo",
            "course_description": "<p>Fiches pratiques Docebo<\/p>",
            "status": "2",
            "selling": "0",
            "price": "",
            "subscribe_method": "2",
            "course_edition": "0",
            "course_type": "elearning",
            "sub_start_date": "",
            "sub_end_date": "",
            "date_begin": "0000-00-00",
            "date_end": "0000-00-00",
            "course_link": ""
        }
    },
    "1": {
        "course_info": {
            "course_id": 5,
            "code": "prout",
            "course_name": "Prout",
            "course_description": "<p style=\"text-align: justify;\">Prout<\/p>",
            "status": "2",
            "selling": "0",
            "price": "",
            "subscribe_method": "2",
            "course_edition": "0",
            "course_type": "elearning",
            "sub_start_date": "",
            "sub_end_date": "",
            "date_begin": "0000-00-00",
            "date_end": "0000-00-00",
            "course_link": ""
        }
    },
    "success": true
}

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

Я пытаюсь так:

public class ListCoursesResponse
{
    public bool? success { get; set; }
    public Dictionary<String,Course> courses { get; set; }
}

но это не работает

Я не знаю, как объяснить RestSharp, что первые узлы - это числа от 1, 2, 3 до последнего узла...

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

Я использую десериализатор RestSharp.

РЕДАКТИРОВАТЬ: есть курс класса

[DeserializeAs(Name = "course_info")]    
public class Course
{
    [DeserializeAs(Name = "course_id")]
    public long? Id { get; set; }
    [DeserializeAs(Name = "course_name")]
    public string Name { get; set; }
    public string Code { get; set; }
    [DeserializeAs(Name = "course_description")]
    public string Description { get; set; }
    [DeserializeAs(Name = "course_edition")]
    public Boolean? IsEditable { get; set; }
    [DeserializeAs(Name = "course_link")]
    public string Url { get; set; }
    [DeserializeAs(Name = "course_type")]
    public string Type { get; set; }
    [DeserializeAs(Name = "date_begin")]
    public string BeginDate { get; set; }
    [DeserializeAs(Name = "date_end")]
    public string EndDate { get; set; }
    public string Price { get; set; }
    [DeserializeAs(Name = "selling")]
    public Boolean? IsSalable { get; set; }
    public int? Status { get; set; }
    [DeserializeAs(Name = "sub_start_date")]
    public string SubscriptionStartDate { get; set; }
    [DeserializeAs(Name = "sub_end_date")]
    public string SubscriptionStopDate { get; set; }
    [DeserializeAs(Name = "subscribe_method")]
    public int? SubscriptionMethod { get; set; }
}

РЕДАКТИРОВАТЬ 2: Есть, как я называю библиотеку

public ListCoursesResponse ListCourses(int? categoryId = null)
{
    if (categoryId != null)
    {
        List<KeyValuePair<String, Object>> list = new List<KeyValuePair<string, object>>();
        list.Add(new KeyValuePair<String, Object>("category", categoryId));
        return Execute<ListCoursesResponse>(String.Format("{0}/{1}", _course, "listCourses"), list.ToArray());
    }

    return Execute<ListCoursesResponse>(String.Format("{0}/{1}", _course, "listCourses"));
}

public T Execute<T>(string resource, params KeyValuePair<String, Object>[] parameters) where T : new()
{
    var client = new RestClient();

    client.AddHandler("text/html",  new RestSharp.Deserializers.JsonDeserializer());

    client.BaseUrl = DoceboApiUrl;

    var requestUrl = DoceboApiUrl;
    if (!requestUrl.EndsWith("/"))
        requestUrl += "/";

    requestUrl += resource;

    var req = new RestRequest(RestSharp.Method.POST);
    req.Resource = resource;

    // Parameters Management
    if (parameters != null)
        foreach (KeyValuePair<String, Object> kvp in parameters)
            req.AddParameter(new Parameter() { Name = kvp.Key, Value = kvp.Value, Type = ParameterType.GetOrPost });

    client.Authenticator = new DoceboAuthenticator(ApiKey, ApiSecret, req.Parameters);

    var response = client.Execute<T>(req);

    if (response.ErrorException != null)
    {
        const string message = "Error retrieving response.  Check inner details for more info.";
        throw new ApplicationException(message, response.ErrorException);
    }

    return response.Data;
}

2 ответа

Я уверен, что это худший способ обработать этот запрос, но вот мое отвратительное решение:

public ListCoursesResponse ListCourses(int? categoryId = null)
{
    Dictionary<String, Object> dico = null;

    if (categoryId != null)
    {
        List<KeyValuePair<String, Object>> list = new List<KeyValuePair<string, object>>();
        list.Add(new KeyValuePair<String, Object>("category", categoryId));
        dico = Execute<Dictionary<String, Object>>(String.Format("{0}/{1}", _course, "listCourses"), list.ToArray());
    }

    dico = Execute<Dictionary<String, Object>>(String.Format("{0}/{1}", _course, "listCourses"));

    return dicoToResponse(dico);
}

А также:

    private ListCoursesResponse dicoToResponse(Dictionary<String, Object> dico)
    {
        ListCoursesResponse coursesResponse = new ListCoursesResponse();

        coursesResponse.success = (Boolean)dico.First(x => x.Key == "success").Value;

        if (coursesResponse.success == true)
        {
            dico.Remove("success");
            foreach (Dictionary<String, Object> v in dico.Values)
            {
                Course course = new Course();

                Dictionary<String, Object> values = (Dictionary<String, Object>)v["course_info"];
                foreach (String key in values.Keys)
                {
                    switch (key)
                    {
                        case "course_id" :
                            course.Id = (long)values[key];
                            break;
                        case "code":
                            course.Code = (string)values[key];
                            break;
                        case "course_name" :
                            course.Name = (string)values[key];
                            break;
                        case "course_description" :
                            course.Description = (string)values[key];
                            break;
                        case "status" :
                            course.Status = (string)values[key];
                            break;
                        case "selling" :
                            course.IsSalable = (string)values[key] == "0" ? false : true;
                            break;
                        case "price" :
                            course.Price = (string)values[key];
                            break;
                        case "subscribe_method" :
                            course.SubscriptionMethod = (string)values[key];
                            break;
                        case "course_edition" :
                            course.IsEditable = (string)values[key] == "0" ? false : true;
                            break;
                        case "course_type" :
                            course.Type = (string)values[key];
                            break;
                        case "sub_start_date" :
                            course.SubscriptionStartDate = (string)values[key];
                            break;
                        case "sub_end_date" :
                            course.SubscriptionEndDate = (string)values[key];
                            break;
                        case "date_begin" :
                            course.BeginDate = (string)values[key];
                            break;
                        case "date_end" :
                            course.EndDate = (string)values[key];
                            break;
                        case "course_link" :
                            course.Url = (string)values[key];
                            break;
                    }
                }

                coursesResponse.courses.Add(course);
            }
        }

return coursesResponse;
}

Прокси классы (ListCoursesResponse пишется так, как вы хотели, остальные генерируются из json с json2csharp.com):

public class ListCoursesResponse
{
    public bool? success { get; set; }
    public Dictionary<String, Course> courses { get; set; }
}

public class Course
{
    public CourseInfo course_info { get; set; }
}

public class CourseInfo
{
    public int course_id { get; set; }
    public string code { get; set; }
    public string course_name { get; set; }
    public string course_description { get; set; }
    public string status { get; set; }
    public string selling { get; set; }
    public string price { get; set; }
    public string subscribe_method { get; set; }
    public string course_edition { get; set; }
    public string course_type { get; set; }
    public string sub_start_date { get; set; }
    public string sub_end_date { get; set; }
    public string date_begin { get; set; }
    public string date_end { get; set; }
    public string course_link { get; set; }
}

Десериализация:

var parsed = JObject.Parse(input);
var result = new
    ListCoursesResponse
        {
            success = parsed["success"].Value<bool?>(),
            courses =
                parsed.Properties()
                      .Where(prop => prop.Name != "success")
                      .ToDictionary(prop => prop.Name, 
                                    prop => prop.Value.ToObject<Course>())
        };
Другие вопросы по тегам