解析JSON而无需创建大量的类

时间:2014-12-18 08:22:51

标签: entity-framework parsing json.net

我目前正在编写一个应该轮询大量API的服务,尽可能统一数据,并将其存储在我的数据库中。我宁愿不必为每个请求创建一个新类,也不想为我想要保存的每个数据子集创建一个新类。所以我选择使用匿名和动态类型。这造成了以下怪物;可能是因为我很长时间没有使用匿名/动态类型。我还应该注意到这个功能不起作用,但应该对我想要实现的目标给出一个很好的要点。

    public string GetActivities(ApplicationUser user)
    {
        //TODO: get statistics of today. If exists, overwrite.

        var date = DateTime.Today;
        var apiCall = String.Format("/1/user/-/activities/date/{0}.json", date.ToString("yyyy-MM-dd"));
        var request = new RestRequest(apiCall);
        var response = restClient.Execute(request);

        //If the response is not what we expected (and exception gets thrown in HandleResponse), rethrow the exception. 
        try
        {
            HandleResponse(response);
        }
        catch
        {
            throw;
        }

        //Create a dynamic object from the JSON response. This way we do not need to create a new class for each response.
        dynamic data = JsonConvert.DeserializeObject(response.Content);

        //Create a list to add anonymous objects to. We define the prototype in Select()
        var activities = Enumerable.Empty<dynamic>()
         .Select(r => new { 
             distance = 0, 
             duration = 0, 
             hasStartTime = false, 
             startTime = DateTime.Now, 
             calories = 0, 
             steps = 0 
         }).ToList();

        //Grab the data we need from the API response
        foreach(var a in data.activities)
        {
            var act = new
            {
                distance = a.distance,
                duration = a.duration,
                hasStartTime = a.hasStartTime,
                startTime = a.startTime,
                calories = a.calories,
                steps = a.steps
            };
            activities.Add(act);
        }

        List<Statistic> statistics = new List<Statistic>();

        foreach (var a in activities)
        {
            var parsedData = new { distance = "" };

            //Add the data we received as a JSON object to the object we store in the database.
            var statistic = new Statistic()
            {
                ID = Guid.NewGuid(),
                Device = context.Device.Where(d => d.Name == "Fitbit").Single(),
                Timestamp = DateTime.Today,
                Type = context.StatisticType.Where(s => s.Type == "calories_eaten").Single(),
                User = user,
                Value = JsonConvert.SerializeObject(parsedData)
            };

            statistics.Add(statistic);
        }

        //Save the newly added data to the database.
        context.Statistic.AddRange(statistics);

        context.SaveChanges();

        return null;
    }

考虑到这个功能已经变得怪异,还有其他选择吗?最好是我不需要创建大量课程。

2 个答案:

答案 0 :(得分:0)

你到底想要做什么?通过阅读您的代码,您似乎放弃了有关活动的所有数据。 JSON影响代码的唯一方法是活动数量。

这是:

var parsedData = new { distance = "" };

实际上应该这样说:

var parsedData = new { distance = a.distance };

如果您只对您阅读的JSON中的一个值感兴趣,我建议使用JSON.net LINQ会更简单。这是一个将JSON视为一堆字典的接口(称为&#34;对象&#34;与JS保持一致,对象实际上是一个字典)和数组,就像JSON一样。

JObject data = JObject.Parse(response.Content);
JArray activities = (JArray)data["activities"];
foreach (JToken activity in activities)
{
    JObject activityObject = (JObject)activity;
    JObject parsedData = new JObject();
    parsedData["distance"] = activityObject["distance"];
    var statistic = new Statistic()
    {
        ...
        Value = parsedData.ToString();
    }
    ...
}

答案 1 :(得分:0)

我可能会错过您要执行的操作,但如果您使用的是MVC,则无需创建空动态Enumerable。您应该能够将您带回的原始数据本身迭代到您可以在“模型”文件夹中创建的单个“活动”模型中:

public class Activity {
         public int distance { get; set; };
         public int duration { get; set; }; 
         public bool hasStartTime { get; set; }; 
         public DateTime startTime { get; set; }; 
         public int calories { get; set; };
         public int steps { get; set; };
}

然后:

List<Statistic> statistics = new List<Statistic>();
IEnumerable<Activity> data = JsonConvert.DeserializeObject(response.Content);

foreach(var a in data)
{
    statistics.Add( new Statistic()
    {
            ID = Guid.NewGuid(),
            Device = context.Device.Where(d => d.Name == "Fitbit").Single(),
            Timestamp = DateTime.Today,
            Type = context.StatisticType.Where(s => s.Type == "calories_eaten").Single(),
            User = user,
            Value = JsonConvert.SerializeObject(parsedData)
            Distance = a.distance,
            Duration = a.duration,
            StartTime = a.startTime,
            Calories = a.calories,
            Steps = a.steps
     });
}
return statistics; // or do whatever you were going to do with this, here