Как включить веб-api для предоставления данных, которые можно запросить с помощью оператора $ select OData?
Я использую Web API 2.2 (или Microsort.AspNet.WebApi 5.2.2) Я не использую EF, а мой backend асинхронен и не поддерживает IQueryable. Я не возражаю прокомментировать весь набор данных и фильтрацию на веб-сервере перед тем, как перейти к клиенту.
То, что у меня ниже, не является идеальным, потому что оно возвращает Task<IQuerable...>
, однако я не знаю, как это сделать по-другому, и на самом деле не знаю, как это сделать вообще.
Следующий код работает, однако выдает ошибку при использовании $ выбора (назовем его кодовый блок А):
[EnableQuery(HandleNullPropagation = HandleNullPropagationOption.True)]
public async Task<IQueryable<Cars>> GetCars(ODataQueryOptions<Cars> queryOptions)
{
// validate the query.
try
{
queryOptions.Validate(_validationSettings);
}
catch (ODataException ex)
{
throw new HttpRequestException(ex.Message);
}
var result = await _context.GetCarsAsync();
var queryableResult = queryOptions.ApplyTo(result.AsQueryable()) as IQueryable<Cars>;
return queryableResult;
}
Следующий код не работает и возвращает 406 (назовем его блок кода B):
[EnableQuery(HandleNullPropagation = HandleNullPropagationOption.True)]
public async Task<IQueryable> GetCars(ODataQueryOptions<Cars> queryOptions)
{
// validate the query.
try
{
queryOptions.Validate(_validationSettings);
}
catch (ODataException ex)
{
throw new HttpRequestException(ex.Message);
}
var result = await _context.GetCarsAsync();
var queryableResult = queryOptions.ApplyTo(result.AsQueryable());
return queryableResult;
}
Я думаю, последний код не работает, потому что он не возвращает сильно типизированный объект и какой-то образом сериализация двигатель не может справиться с этим. Я пытался это сделать, и я также попытался заменить Cars
в блоке A кода dynamic
, чтобы включить $ select, но не работает.
Так два вопроса:
Есть ли способ, чтобы позволить $ выбрать, учитывая мой бэкенд не поддерживает IQueryable? (Не врываясь в сам интерфейс IQueryable)
Что такое «правильный» способ сделать это, не возвращая
Task<IQuerable...>
?
UPDATE - @Marvin Smit (Ошибка - код Блок А при использовании $ выбора)
Полная ошибка при попытке спроецировать код блока А с помощью $ выберите ниже. Пример /Cars?$select=NumberPlate
В основном это ошибка сериализации (что-то связано с переносом IQueryable в задачу?). Помещение точки останова показывает, что данные были успешно извлечены и спроектированы после queryOptions.ApplyTo(...
, и ошибка возникает только после возвращения.
<m:error xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
<m:code/>
<m:message xml:lang="en-US">An error has occurred.</m:message>
<m:innererror>
<m:message>
The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'.
</m:message>
<m:type>System.InvalidOperationException</m:type>
<m:stacktrace/>
<m:internalexception>
<m:message>Cannot serialize a null 'feed'.</m:message>
<m:type>
System.Runtime.Serialization.SerializationException
</m:type>
<m:stacktrace>
at System.Web.Http.OData.Formatter.Serialization.ODataFeedSerializer.WriteObjectInline(Object graph, IEdmTypeReference expectedType, ODataWriter writer, ODataSerializerContext writeContext)
at System.Web.Http.OData.Formatter.Serialization.ODataFeedSerializer.WriteObject(Object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext)
at System.Web.Http.OData.Formatter.ODataMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, HttpContent content, HttpContentHeaders contentHeaders)
at System.Web.Http.OData.Formatter.ODataMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at System.Web.Http.WebHost.HttpControllerHandler.
<WriteBufferedResponseContentAsync>d__1b.MoveNext()
</m:stacktrace>
</m:internalexception>
</m:innererror>
</m:error>
Что ошибка для блока кода А? для кода B (http 406) можно быстро просмотреть http://stackoverflow.com/questions/14251851/what-is-406-not-acceptable-response-in-http –
@MarvinSmit, см. обновленный вопрос с информацией, приведенной выше , Спасибо за информацию о 406, я добавил приложение/json к этому, и похоже, что теперь это ошибка сериализации, аналогичная приведенной выше для блока кода A. Забавно это не происходит при возврате IQueryable - только когда вы завершаете это в задаче. Однако, как мой back-end асинхронный, какой у меня выбор? Решением может быть завершение реализации IQueryable (a la 'http://blogs.msdn.com/b/alexj/archive/2010/03/01/tip-55-how-to-extend-an-iqueryable-by -wrapping-it.aspx) с асинхронным провайдером. Слишком много работы! –
SDK
Хотя я не уверен, почему в вашем случае это «типичная ошибка» для OData с webapi. (попробуйте сделать это на любой конечной точке OData, используйте $ select of property и убедитесь, что вы запрашиваете XML в качестве вывода). Это просто не нравится сериализация «слабо типизированных» объектов. Следовательно, JSON. Но вы просите JSON. (http://stackoverflow.com/questions/27925062/web-api-with-odata-v4-throwing-exception-on-select) –