поддержка @odata.bind в веб-API asp.net (ссылка на существующий объект во время публикации)

Мне очень трудно перейти со службы данных WCF на веб-api odata v4. Я застрял в следующем вопросе:

Веб-API odata не поддерживает @odata.bind.

Я нашел следующую ссылку: https://github.com/OData/WebApi/issues/158 Кто-то предложил реализовать собственный производный класс ODataEntityDeserializer следующим образом:

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. Может быть, я что-то принципиально упускаю здесь, так как я новичок в веб-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);
 }

Итак, остается вопрос: когда мы получим поддержку @odata.bind в asp.net webapi odata?


person Jeldrik    schedule 16.06.2015    source источник
comment
Я нахожусь в ситуации, когда у меня есть собственный сериализатор, и я хочу его зарегистрировать. Я использую config.Formatters.InsertRange(0,mycustomformatter). Однако это не сработает, если я не выполню Clear() до этого. У меня к вам вопрос: вы все таки очищаете перед добавлением форматтера или нашли альтернативный способ?   -  person Randa Sbeity    schedule 15.04.2016
comment
Я все еще использую его, как описано выше (очистить, а затем добавить форматтеры). Единственное изменение, которое я внес с тех пор, заключается в добавлении JsonMediaTypeFormatter и XmlMediaTypeFormatter в коллекцию Formatter. Поскольку это работает для меня, я перестал искать альтернативное решение.   -  person Jeldrik    schedule 15.04.2016


Ответы (1)


Пытаюсь ответить

Итак, остается вопрос: когда мы получим поддержку @odata.bind в asp.net webapi odata?

Кажется, в следующем репо есть функция, связанная с этим. Тем не менее, проблема отмечена как имеющая слабое влияние. https://github.com/OData/WebApi/milestones/vNext и, следовательно, нет возможности узнать, когда эта функция будет реализована.

person Magnus Karlsson    schedule 28.06.2015
comment
Спасибо за это. Было бы здорово, если бы кто-нибудь из команды веб-апиодата aps.net мог сделать заявление по этому поводу. Я считаю эту функцию весьма актуальной, особенно если вам необходимо перенести существующую службу данных WCF. - person Jeldrik; 29.06.2015
comment
@Jeldrik Я думаю, они ответят в репозитории GitHub, если вы создадите новую проблему, в которой изложите свою проблему. Удачи тебе! - person Magnus Karlsson; 29.06.2015
comment
Спасибо еще раз. На github уже есть открытая проблема (github.com/OData/WebApi/issues/158) практически без ответа от команды веб-API asp.net. Кажется, эта функция была запланирована для версии 5.6 и в настоящее время отложена для версии 5.7 (но я все еще настроен скептически). - person Jeldrik; 29.06.2015