Правильный способ вызова вложенного Expand() из.NET OData 4 Client

проблема

В сервисе OData 4 в Web API, как правильно называть вложенные $ расширения из клиента.NET? Мы используем OData Client Generator. Вернемся к предыдущим службам данных WCF со службой OData 3, которые мы могли бы назвать .Expand("Customers/Orders"), В веб-API с OData 4 мы больше не можем этого делать и получаем следующее, если вы попытаетесь .Expand("Customers/Orders"):

Запрос, указанный в URI, недопустим. Найден путь, пересекающий несколько навигационных> свойств. Пожалуйста, перефразируйте запрос так, чтобы каждый путь расширения содержал только тип> сегменты и свойства навигации.

Временное решение

Мы можем обойти эту проблему, вызывая функцию расширения так: .Expand("Customers($expand=Orders)"), В не вложенных сценариях с расширением $ мне нравится поддержка лямбды .Expand(d => d.Customers), Есть ли в клиенте.NET OData 4 правильный способ вызова вложенных расширений без неудачной магической строки .Expand("Customers($expand=Orders)")? Если нет, то будет ли работать более чистый шаблон строк, такой как "Клиенты / Заказы"? Благодарю.

2 ответа

Решение

В OData v4 недопустимо расширять несколько уровней, например то, что вы упомянули в вопросе: .Expand("Клиенты / Заказы"). Я не думаю, что клиент будет поддерживать такой API. Вот что в ABNF http://docs.oasis-open.org/odata/odata/v4.0/os/abnf/odata-abnf-construction-rules.txt:

expand            = '$expand' EQ expandItem *( COMMA expandItem )
expandItem        = STAR [ ref / OPEN levels CLOSE ]
                  / expandPath
                    [ ref   [ OPEN expandRefOption   *( SEMI expandRefOption   ) CLOSE ]
                    / count [ OPEN expandCountOption *( SEMI expandCountOption ) CLOSE ]
                    /         OPEN expandOption      *( SEMI expandOption      ) CLOSE 
                    ]
expandPath        = [ qualifiedEntityTypeName "/" ] 
                    *( ( complexProperty / complexColProperty ) "/" [ qualifiedComplexTypeName "/" ] )
                    navigationProperty 
                    [ "/" qualifiedEntityTypeName ]

Запрос, который вы хотите отправить:

GET http://host/service/Customers/Orders

право?

Согласно протоколу OData:

Чтобы запросить связанные объекты в соответствии с определенным отношением, клиент отправляет запрос GET на URL-адрес запроса исходного объекта, после которого следует косая черта и имя свойства навигации, представляющего отношение.

Таким образом, такой запрос не поддерживается, так как "Заказчики" до "/ Заказы" - это имя набора сущностей, а не одного объекта. Вы можете написать только вложенное расширение, например:

GET http://host/service/Customers(1)/Orders

Что соответствует следующим фрагментам кода с использованием OData V4 Code Generator:

var orders = context.Customers.ByKey(new Dictionary<string, object>() { { "ID", 1 } }).Orders.Execute();

И вам нужно пройти через всех клиентов, чтобы получить все их заказы.

Небольшое расширение для этого:

        public static DataServiceQuery<TSource> Expand<TSource,TNavigation,TExpand>(this DataServiceQuery<TSource> dataServiceQuery, Expression<Func<TSource, DataServiceCollection<TNavigation>>> expression,  Expression<Func<TNavigation,TExpand>> navigation)
    {
        var expressionName = (expression.Body as System.Linq.Expressions.MemberExpression).Member.Name;
        var navigationName = (navigation.Body as System.Linq.Expressions.MemberExpression).Member.Name;


        return dataServiceQuery.Expand($"{expressionName}($expand={navigationName})");
    }

Теперь у вас есть intellisense и проверка типов

Другие вопросы по тегам