В моем .Net Core API есть простой маршрут, который вручную обрабатывает экземпляр ODataQuerySettings
.Я с трудом пытаюсь вызвать этот API, используя класс DataServiceContext
из клиентского пакета OData.Можно ли даже использовать DataServiceContext
с простым маршрутизацией MVC с поддержкой OData?Или мне нужно будет предоставить данные другим способом, чтобы соответствовать более строгим стандартам OData?
Пример API
[AllowAnonymous]
[HttpGet("Products")]
public ActionResult<PageResult<IEnumerable<Product>>> GetData(
ODataQueryOptions<Product> oDataQueryOptions)
{
IEnumerable<Product> data = ProductService.GetData();
IQueryable results = data
.AsQueryable()
.Skip(oDataQueryOptions.Skip?.Value ?? 0)
.Take(oDataQueryOptions.Top?.Value ?? 3);
return new OkObjectResult(
new PageResult<object>(
results.Cast<object>(),
Request.GetNextPageLink(3),
data.Length));
}
При получении результатов с помощью этого API я получаюожидаемые значения:
- URL:
localhost/api/Products?$skip=1
- Результаты:
{
"items": [{
"id": 2,
"text": "Second"
}, {
"id": 3,
"text": "Third"
}, {
"id": 4,
"text": "Fourth"
}
],
"nextPageLink": "http://localhost/api/products?$skip=4",
"count":9
}
Потребительское приложение
Затем я приступил к созданиюпример клиентского приложения, использующего пакет Microsoft.OData.Client
NuGet (точнее, v7.5.1).
Вот как выглядит простой клиент:
class Product
{
public int Id { get; set; }
public string Text { get; set; }
}
class Program
{
static void Main()
{
var context = new DataServiceContext(new Uri("http://localhost/api"));
var results = context
.CreateQuery<Product>("products")
.Skip(1)
.ToList();
}
}
При вызове ToList
для извлечения/ материализуя результаты, я получаю следующее исключение:
System.InvalidOperationException: Ответная полезная нагрузка не является допустимой полезной нагрузкой ответа.Убедитесь, что элемент верхнего уровня является допустимым элементом Atom или JSON или принадлежит пространству имен 'http://docs.oasis -open.org / odata / ns / data '.
Похоже, это связано с тем, что я не возвращаю «стандартный ODATA» ответ, а вместо этого сырой json.
Затем я попытался использовать формат Json на DataServiceContext
, как это, но этоне помогло:
var context = new DataServiceContext(new System.Uri("http://localhost/api"));
context.Format.UseJson(CreateEdmModel())
...
private static IEdmModel CreateEdmModel()
{
var model = new EdmModel();
model.AddEntityType(typeof(Product).Namespace, nameof(Product));
return model;
}
Как я могу правильно получить результаты из API, используя DataServiceContext
из пользовательского приложения?Я вижу 2 варианта, но мне нужна помощь с обоими:
- Изменить потребителя, чтобы он работал с необработанным выводом Json
Это должно быть выполнимо, но теперь мне интересно, нужна ли мне дополнительная логика в клиенте (например, построение модели EDM), а также потеря некоторой функциональности, например, невозможность использования методов .GetAllPages
, которые автоматическиперебирать страницы в службе OData и объединять их.
Измените вывод самого API, чтобы он выдавал «ODATA-совместимый» Json Похоже, это приведет к наименьшему объему работы у потребителей.Но как мне это сделать, сохраняя ручную подкачку на месте (то есть я не могу использовать стандартные [EnableQuery]
с IQueryable
возвращаемыми значениями на чисто автоматическом маршруте, потому что мне нужно передать свойства OData в наш слой Dapper: ORM отсутствуетна месте здесь).Я знаю, что есть специальные схемы Json для OData, такие как «application / json; odata.metadata = минимальный», которые отличаются от того, что я сейчас выводю.
В прошлом я пользовался службами данных WCF и неНе помню, чтобы у меня была такая проблема: в то время я смог подключить DataServiceContext
к службе WCF без необходимости создавать специальные выходные форматы или даже создавать какие-либо модели Edm в клиенте.