WCF データ サービスから Web API odata v4 への移行に非常に苦労しています。私は次の問題で立ち往生しています:
odata Web API は @odata.bind をサポートしていないようです。
次のリンクを見つけました:
https://github.com/OData/WebApi/issues/158ODataEntityDeserializer
誰かが次のような独自の派生クラス
を実装することを提案しました:
public class ExtendedODataEntityDeserializer : ODataEntityDeserializer
{
public ExtendedODataEntityDeserializer(ODataDeserializerProvider deserializerProvider) : base(deserializerProvider)
{
}
public override void ApplyNavigationProperty(
object entityResource,
ODataNavigationLinkWithItems navigationLinkWrapper,
IEdmEntityTypeReference entityType,
ODataDeserializerContext readContext)
{
base.ApplyNavigationProperty(entityResource, navigationLinkWrapper, entityType, readContext);
foreach (var childItem in navigationLinkWrapper.NestedItems)
{
var entityReferenceLink = childItem as ODataEntityReferenceLinkBase;
if (entityReferenceLink != null)
{
var navigationPropertyName = navigationLinkWrapper.NavigationLink.Name;
Uri referencedEntityUrl = entityReferenceLink.EntityReferenceLink.Url;
if (!referencedEntityUrl.IsAbsoluteUri)
{
referencedEntityUrl = new Uri(readContext.Request.RequestUri, referencedEntityUrl);
}
var linkedEntities = (Model.LinkedEntityCollection)entityResource;
linkedEntities.Add(navigationPropertyName, referencedEntityUrl);
}
}
}
}
LinkedEntityCollection は、辞書として機能するエンティティ クラスの基本クラスです (MyEntity : LinkedEntityCollection
実装は簡単です)。
public class ExtendedODataDeserializerProvider : ODataDeserializerProvider
{
private static ExtendedODataDeserializerProvider _instance = null;
private ExtendedODataDeserializerProvider()
{
_instance = this;
}
public static ExtendedODataDeserializerProvider Instance
{
get { return _instance ?? new ExtendedODataDeserializerProvider(); }
}
public override ODataEdmTypeDeserializer GetEdmTypeDeserializer(Microsoft.OData.Edm.IEdmTypeReference edmType)
{
return DefaultODataDeserializerProvider.Instance.GetEdmTypeDeserializer(edmType);
}
public override ODataDeserializer GetODataDeserializer(Microsoft.OData.Edm.IEdmModel model, Type type, System.Net.Http.HttpRequestMessage request)
{
return new ExtendedODataEntityDeserializer(DefaultODataDeserializerProvider.Instance);
}
}
http 構成への登録:
public static void Register(HttpConfiguration config)
{
ODataModelBuilder builder = new ODataConventionModelBuilder();
// registering entities: builder.EntitySet<T>("EntityName") ...
ODataBatchHandler batchHandler = new DefaultODataBatchHandler(new HttpServer(config));
batchHandler.MessageQuotas.MaxOperationsPerChangeset = 10;
batchHandler.MessageQuotas.MaxPartsPerBatch = 10;
var odataFormatters = ODataMediaTypeFormatters.Create(DefaultODataSerializerProvider.Instance, ExtendedODataDeserializerProvider.Instance);
config.Formatters.Clear();
config.Formatters.AddRange(odataFormatters);
config.MapODataServiceRoute(routeName: "Central", routePrefix: "Odata", model: builder.GetEdmModel(), batchHandler: batchHandler);
}
ただし、このハックを使用すると、次の記事で説明されているようなエンティティ間のリンクを作成する機能が失われます: http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/ odata-v4/entity-relations-in-odata-v4
「@odata.id」は解析されず、関数内のエンティティであると見なされますODataEntityDeserializer.Read
。私はWeb APIにかなり慣れていないので、ここで根本的に何かが欠けているのかもしれません(config.Formatters.Clear()
少し厳しいようです)。または、@odata.bind をサポートする他の回避策はありますか?
この機能が近い将来実装される可能性はありますか?
アップデート
ハックが機能しました。問題は、代わりに派生ExtendedODataDeserializerProvider
して、それに応じてデシリアライザーを返す必要があることでした:DefaultODataDeserializerProvider
ODataDeserializerProvider
public override ODataDeserializer GetODataDeserializer(
Microsoft.OData.Edm.IEdmModel model,
Type type,
System.Net.Http.HttpRequestMessage request)
{
if (type == typeof(ODataActionParameters) ||
type == typeof(ODataUntypedActionParameters) ||
type == typeof(Uri))
{
return base.GetODataDeserializer(model, type, request);
}
return new ExtendedODataEntityDeserializer(DefaultODataDeserializerProvider.Instance);
}
残る問題: asp.net webapi odata で @odata.bind がサポートされるのはいつですか?