WebAPI 2 スタックで JSON.NET をデフォルトのシリアライザーとして使用しようとしています。JsonMediaTypeFormatter を実装し、その中でデータのシリアル化/デシリアル化に JSON.NET シリアライザーを使用し、このメディア タイプ フォーマッタを使用するために JsonContentNegotiator を作成しました。OData クエリを除いてすべて正常に動作します。アクション メソッドに [Queryable] メタデータを追加すると、応答オブジェクトにはメタデータ情報が含まれず、エンティティのリストのみが含まれます。
小さな例。私のアクションメソッド:
[Queryable]
public async Task<PageResult<RuleType>> GetRuleType(ODataQueryOptions<RuleType> options)
{
var ret = await _service.ListRuleTypesAsync(options);
return new PageResult<RuleType>(
ret,
Request.GetNextPageLink(),
Request.GetInlineCount());
}
デフォルトの OData シリアル化を使用し、ルール タイプ (例: .../odata/RuleType?$inlinecount=allpages&$skip=0&$top=1
) でクエリを呼び出すと、メタデータ情報と count プロパティを含む従来の OData 応答が返されます。
odata.metadata ".../odata/$metadata#RuleType"
odata.count "2"
value
0 {
Id: 1
Name: "General"
Code: "General"
Notes: null
}
(一部のフィールドはスキップされていますが、Notes プロパティには null 値があります) ただし、シリアライザーとしてJsonContentNegotiator
withを追加するとJsonMediaTypeFormatter
、エンティティのリストのみが返されます。
[
{
"Id": 1,
"Name": "General",
"Code": "General"
}
]
(Notes フィールドはここにはありませんNullValueHandling.Ignore
。) さらに、[Queryable]
アクション メソッドで属性を削除すると、別の結果が得られます。
{
"Items": [
{
"Id": 1,
"Name": "General",
"Code": "General"
}
],
"Count": 2
}
この場合、Count は受け取りましたが、メタデータはまだありません。また、odata 応答プロパティ名はデフォルトとはまったく異なります。
頭が混乱しています。Web アプリのどの部分でも、JSON.NET をシリアライザーとして使用したいだけです (いくつかの厳しい制限があるため)。どうすればいいでしょうか?
ベストアンサー1
私はすでに自分の問題を理解し、解決策を見つけました。ODataはODataMediaTypeFormatterから継承された個別のメディアタイプフォーマッタを使用します。また、ODataはシリアル化とデシリアル化に異なるフォーマッタを使用します。この動作を置き換えるには、ODataDeserializerProviderクラスおよび/またはODataSerializerProviderクラスの子孫を実装し、それらのクラスをHttpConfiguration.Formattersコレクションに追加する必要があります。
var odataFormatters = ODataMediaTypeFormatters
.Create(new MyODataSerializerProvider(), new MuODataDeserializerProvider());
config.Formatters.AddRange(odataFormatters);
小さなデシリアライゼーション プロバイダーの例:
public class JsonODataDeserializerProvider : ODataDeserializerProvider
{
public override ODataEdmTypeDeserializer GetEdmTypeDeserializer(IEdmTypeReference edmType)
{
var kind = GetODataPayloadKind(edmType);
return new JsonODataEdmTypeDeserializer(kind, this);
}
private static ODataPayloadKind GetODataPayloadKind(IEdmTypeReference edmType)
{
switch (edmType.TypeKind())
{
case EdmTypeKind.Entity:
return ODataPayloadKind.Entry;
case EdmTypeKind.Primitive:
case EdmTypeKind.Complex:
return ODataPayloadKind.Property;
case EdmTypeKind.Collection:
IEdmCollectionTypeReference collectionType = edmType.AsCollection();
return collectionType.ElementType().IsEntity() ? ODataPayloadKind.Feed : ODataPayloadKind.Collection;
default:
return ODataPayloadKind.Entry;
}
}
public override ODataDeserializer GetODataDeserializer(IEdmModel model, Type type, HttpRequestMessage request)
{
var edmType = model.GetEdmTypeReference(type);
return edmType == null ? null : GetEdmTypeDeserializer(edmType);
}
}
ODataデシリアライザー:
public class JsonODataEdmTypeDeserializer : ODataEdmTypeDeserializer
{
public JsonODataEdmTypeDeserializer(ODataPayloadKind payloadKind) : base(payloadKind)
{
}
public JsonODataEdmTypeDeserializer(ODataPayloadKind payloadKind, ODataDeserializerProvider deserializerProvider) : base(payloadKind, deserializerProvider)
{
}
public override object Read(ODataMessageReader messageReader, Type type, ODataDeserializerContext readContext)
{
var data = readContext.Request.Content.ReadAsStringAsync().Result;
return JsonConvert.DeserializeObject(data, type);
}
}
また、このクラスは内部クラスであるため、GetEdmTypeReference() および GetEdmType() メソッドを使用して、WebAPI OData ソース コードから EdmLibsHelper クラスをプロジェクトに追加しました。