我目前正在编写一个服务,该服务应该轮询多个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;
}
考虑到这个功能已经变得很可怕,有没有替代方案?最好是我不需要创建大量类的类。
你到底想做什么?从读取代码来看,您似乎丢弃了有关活动的所有读取数据。JSON 影响代码的唯一方式是活动数。
是这样的:
var parsedData = new { distance = "" };
其实应该这样说:
var parsedData = new { distance = a.distance };
如果您只对读取的 JSON 中的一个值感兴趣,我建议在 LINQ JSON.net 更简单。这是一个将JSON视为一堆字典(与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();
}
...
}
我可能错过了您要执行的操作,但是如果您使用的是MVC,则无需创建空的动态枚举。 您应该能够将带回的原始数据本身迭代到您可以在"模型"文件夹中创建的单个"活动"模型中:
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