Harvest APIを使用していて、エンティティをできるだけ簡単に自動的にマッピングしようとしています。残念ながら、_GET /projects
_のようなリクエストを実行すると、次のような結果が生成されます。
_[{
project: {
name: "Test"
}
},
{
project: {
name: "Test 2"
}]
_
RestSharpでは、これを直接行うことはできません。
_client.Execute<List<Project>>(request)
_
Project
というプロパティを探すためです。そのため、そのプロパティを持つ別のクラスを作成し、次のように呼び出す必要があります。
_client.Execute<List<ProjectContainer>>(request)
_
すべてのエンティティに対して「コンテナ」クラスを作成したくないので、すべてのクラスで使用できる1つのクラスを作成するための賢い解決策を見つけました。
_public class ListContainer<T> where T : IHarvestEntity
{
public T Item { get; set; }
}
_
ただし、もちろん、デシリアライザはエンティティ名(または「プロジェクト」)をプロパティItem
にマップする必要があることを理解していません。 Restsharpのドキュメントでは、[DeserializeAs(Name = "CustomProperty")]
を使用して、このプロパティにマップするフィールドをデシリアライザに指示できることがわかりました。ただし、属性は定数のみを許可します。つまり、次のことはできません。
_[DeserializeAs(Name = typeof(T).FullName)]
public T Item { get; set; }
_
誰かがこれに対する賢い解決策を知っていますか?それで、10の異なるコンテナークラスを作成する必要はありませんか?
Jsonに相当するXPathを使用することをお勧めします。 Json.NETを使用すると、文字列を parse して動的オブジェクトを作成できます。
SelectToken を使用すると、値をクエリしたり、 Linq を使用したりできます。
コードは次のようになります(テストしていません)。
// execute the request
RestResponse response = client.Execute(request);
var content = response.Content; // raw content as string
JObject o = JObject.Parse(content);
IList<string> projectNames = o.SelectToken("project").Select(s => (string)s.name).ToList();
パスをコーディングしたり、パスを構成したりできます。
---編集---
以下は、json文字列をプロジェクトのリストに変換してテストした例です。
var projects = JArray.Parse(response.Content).Select(r => new Project(r["project"]["name"].Value<string>())).ToList();
本当にシンプルに保つには、List<dynamic>
し、ワンライナーで名前でプロパティにアクセスします。
var names = client.Execute<List<dynamic>>(request).Data.Select(
item => item["project"]["name"]).ToList(); // list of names
これで十分でない場合は、独自のマッパーを即興で作成し、たとえば、 Project
インスタンス:
var projects = client.Execute<List<dynamic>>(request).Data.Select(
item => Map<Project>(item)).ToList(); // list of Project instances
Map
メソッドは次のようになります
public T Map<T>(dynamic item) where T : class
{
// inline for clarity
var mappings = new Dictionary<Type,Func<dynamic,object>>
{
{ typeof(Project), map => new Project(map["project"]["name"]) }
};
return (T)mappings[typeof(T)].Invoke(item);
}
与えられたProject
は次のように定義されます
public class Project
{
public Project(string name)
{
Name = name;
}
public string Name { get; set; }
}