本周的挑战本质上是从网络中获取Json数据,并将其反序列化为对象。我没有太多的时间用于这个项目,所以我所拥有的是非常基本的:它在WPF ListView中显示所有pokemons的名称:

下面是窗口的代码:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var service = new PokemonApp.Web.Pokedex();
var pokemons = service.SelectAllPokemonReferences().OrderBy(pokemon => pokemon.Name);
DataContext = new MainWindowViewModel { References = pokemons };
}
}正如您已经猜到的,有趣的代码在Pokedex类中:
public class Pokedex
{
public IEnumerable<ResourceReference> SelectAllPokemonReferences()
{
string jsonResult = GetJsonResult(PokeDexResultBase.BaseUrl + "pokedex/1/");
dynamic pokemonRefs = JsonConvert.DeserializeObject(jsonResult);
ICollection<ResourceReference> references = new List<ResourceReference>();
foreach (var pokeRef in pokemonRefs.pokemon)
{
string uri = PokeDexResultBase.BaseUrl + pokeRef.resource_uri.ToString();
references.Add(new ResourceReference
{
Name = pokeRef.name,
ResourceUri = new Uri(uri)
});
}
return references;
}
private static string GetJsonResult(string url)
{
string result;
WebRequest request = HttpWebRequest.Create(url);
request.ContentType = "application/json; charset=utf-8";
try
{
using (var response = request.GetResponse())
using (var stream = response.GetResponseStream())
using (var reader = new StreamReader(stream))
{
result = reader.ReadToEnd();
}
}
catch (Exception exception)
{
result = string.Empty;
// throw?
}
return result;
}
}ResourceReference类没有什么特别之处:
public class ResourceReference
{
public string Name { get; set; }
public Uri ResourceUri { get; set; }
}这些非常基本的代码为更复杂的对象奠定了基础:
public abstract class PokeDexResultBase : IPokeDexUri
{
private readonly string _controller;
protected PokeDexResultBase(string controller)
{
_controller = string.IsNullOrEmpty(controller) ? BaseUrl : controller;
}
public static string BaseUrl { get { return "http://pokeapi.co/api/v1/"; } }
public int Id { get; set; }
public Uri ResourceUri { get; set; }
public DateTime Created { get; set; }
public DateTime Modified { get; set; }
public virtual string Url { get { return BaseUrl + _controller + (Id == 0 ? string.Empty : Id.ToString()); } }
}这个基类是由API中具有Id的所有东西继承的:
public class Pokemon : PokeDexResultBase
{
public Pokemon() : base("pokemon/") { }
public string Name { get; set; }
public ICollection<ResourceReference> Abilities { get; set; }
public ICollection<ResourceReference> EggGroups { get; set; }
public ICollection<PokemonEvolution> Evolutions { get; set; }
public ICollection<PokemonMove> Moves { get; set; }
public ICollection<PokemonType> Types { get; set; }
public int Attack { get; set; }
public int CatchRate { get; set; }
public int Defense { get; set; }
public int EggCycles { get; set; }
public string EvolutionYield { get; set; }
public int ExperienceYield { get; set; }
public string GrowthRate { get; set; }
public int Happiness { get; set; }
public string Height { get; set; }
public int HitPoints { get; set; }
public string MaleFemaleRatio { get; set; }
public int SpecialAttack { get; set; }
public int SpecialDefense { get; set; }
public string Species { get; set; }
public int Speed { get; set; }
public int Total { get; set; }
public string Weight { get; set; }
}
public class PokemonEvolution
{
public int Level { get; set; }
public string Method { get; set; }
public Uri ResourceUri { get; set; }
public string ToPokemonName { get; set; }
}还有其他涉及的类,但是它们没有什么可回顾的,它们非常类似于Pokemon类。
在扩展代码时,我将向Pokedex类添加更多方法,该类将使用GetJsonResult方法。
我是否很好地分析了API --我的意思是,这段代码是否是反序列化pokemons的坚实基础,并最终使它们能够相互对抗?还有什么可以做得更好呢?有挑剔的人吗?
发布于 2013-12-21 18:06:46
如果像ResourceReference这样的类在包装API方面是有意义的,那么从UI的角度来看,这就像在UI层中使用POCO:如果数据是通过实体框架从数据库获得的,那么这段代码将显示实体。这是一个基本的实现,但是如果目标是使它成为一个可扩展的“框架”实现,则应该有一个ViewModel类供UI显示,它独立于WebAPI提供的对象;ViewModel不关心ResourceUri --这个属性不是要显示的,而是用于查询API的管道,不属于UI。
就Pokedex服务类而言,它看起来可以工作,但是它应该返回ViewModel对象供UI使用,静态GetJsonResult方法可以封装在自己的类中,它将是一个基于HTTP的实现,该实现的作用是获取数据--可能有一个基于SqlServer的实现在数据库中执行同样的任务,其思想是将数据与其数据源分离.但这可能是过头了。
在POCO类中使用Uri增加了不必要的复杂性:它们可以与普通字符串一样保持不变,所以这段代码:
字符串uri = PokeDexResultBase.BaseUrl + pokeRef.resource_uri.ToString();
然后可以这样跳过无用的.ToString()调用:
string uri = PokeDexResultBase.BaseUrl + pokeRef.resource_uri;PokeDexResultBase.BaseUrl静态字符串属性作为Pokedex类的静态属性可能更好,然后它将使PokeDexResultBase与Pokedex紧密耦合,这在某种程度上是有意义的。
此外,为了保持一致性,类PokeDexResultBase应该被称为PokedexResultBase。
发布于 2014-04-22 23:59:58
实际上,我最终在反序列化中采用了这种方法。
// Pocos for deserializing
public class PocoAnswer
{
PocoItem item {get; set;}
}
public class PocoItem
{
String name {get; set; }
DateTime birthday {get; set; }
}
// Model for binding
public ItemModel
{
public readonly PocoItem item; // I wish this to stay private, but json serializer cant get it then
public ItemModel(PocoItem _item)
{
item = _item;
}
[JsonIgnore] // No need to store runtime generated data
public FormattedInfoString // This is used for binding
{
get
{
return String.Format("My amazing custom string contains name {0} and birth {1}, item.Name, item.Birthday.ToString("yy-mm");
}
}
}当我从服务器得到答案时,我把它推到绑定项中
var result = JsonConvert.DeserializeObject<PocoAnswer>(resultString);
BindableModel = new ItemModel(result.answer.item);然后在xaml中
<TextBlock Text={Binding BindableModel.FormattedInfoString} \>https://codereview.stackexchange.com/questions/37866
复制相似问题