Asp.net web api 如何在web api OData查询中启用$select

Asp.net web api 如何在web api OData查询中启用$select,asp.net-web-api,odata,Asp.net Web Api,Odata,如何使web api能够提供可通过$select OData操作符查询的数据 我使用的是Web API 2.2(或Microsort.AspNet.WebApi 5.2.2),我没有使用EF,我的后端是异步的,不支持IQueryable。在传递给客户机之前,我不介意查询整个数据集并在web服务器上进行过滤 我下面的内容并不理想,因为它返回一个任务,但我不知道如何用另一种方式来做,事实上我根本不知道如何做 下面的代码可以工作,但是在使用$select时会抛出一个错误(我们称之为代码块A): 问题与

如何使web api能够提供可通过$select OData操作符查询的数据

我使用的是Web API 2.2(或Microsort.AspNet.WebApi 5.2.2),我没有使用EF,我的后端是异步的,不支持IQueryable。在传递给客户机之前,我不介意查询整个数据集并在web服务器上进行过滤

我下面的内容并不理想,因为它返回一个
任务
,但我不知道如何用另一种方式来做,事实上我根本不知道如何做

下面的代码可以工作,但是在使用$select时会抛出一个错误(我们称之为代码块A):


问题与任务无关

经过一些研究,问题在于A区的这行代码:

queryOptions.ApplyTo(result.AsQueryable()) as IQueryable<Cars>
在方法返回后,asp.net odata实现会自动应用过滤器

如果您希望在代码中应用查询选项,然后返回IQueryable以外的内容,则applyTo非常有用


关于块B中的序列化错误(在添加了application/json之后),我不知道

问题与任务无关

经过一些研究,问题在于A区的这行代码:

queryOptions.ApplyTo(result.AsQueryable()) as IQueryable<Cars>
在方法返回后,asp.net odata实现会自动应用过滤器

如果您希望在代码中应用查询选项,然后返回IQueryable以外的内容,则applyTo非常有用


关于块B中的序列化错误(在添加了application/json之后),我不知道

我发现了这种方法:

[启用查询]
公共异步任务GetCars()
{
//从上下文返回IQueryable,不执行对数据库的请求
返回wait Task.FromResult(_context.GetCarsQuery());
}

我发现了这种方法:

[启用查询]
公共异步任务GetCars()
{
//从上下文返回IQueryable,不执行对数据库的请求
返回wait Task.FromResult(_context.GetCarsQuery());
}

代码块A的错误是什么?对于代码块B(http 406),请快速查看@MarvinSmit,请参阅上面的更新问题和信息。感谢406上的信息,我在其中添加了application/json,它现在看起来像是一个序列化错误,类似于上面代码块a的错误。有趣的是,返回IQueryable时不会发生这种情况-只有在将其包装到任务中时才会发生。然而,由于我的后端是异步的,我有什么选择呢?解决方案可能是在IQueryable实现(la')的下面封装一个异步提供程序。工作太多了!虽然我不确定为什么在您的案例中,这是使用webapi的OData的“典型错误”。(尝试在任何OData端点上执行此操作;使用属性的$select并确保请求XML作为输出)。它只是不喜欢序列化“弱类型”对象。因此,JSON。但您正在请求JSON。()嘿@MarvinSmit,请看下面的@Fabians回答。它起作用了。但是,我将尝试指定application/json,并使用
query.ApplyTo
方法返回
async Task
。通过
async Task
执行此操作并不容易,尽管使用自定义格式化程序可能:代码块A的错误是什么?对于代码块B(http 406),请快速查看@MarvinSmit,请参阅上面的更新问题和信息。感谢406上的信息,我在其中添加了application/json,它现在看起来像是一个序列化错误,类似于上面代码块a的错误。有趣的是,返回IQueryable时不会发生这种情况-只有在将其包装到任务中时才会发生。然而,由于我的后端是异步的,我有什么选择呢?解决方案可能是在IQueryable实现(la')的下面封装一个异步提供程序。工作太多了!虽然我不确定为什么在您的案例中,这是使用webapi的OData的“典型错误”。(尝试在任何OData端点上执行此操作;使用属性的$select并确保请求XML作为输出)。它只是不喜欢序列化“弱类型”对象。因此,JSON。但您正在请求JSON。()嘿@MarvinSmit,请看下面的@Fabians回答。它起作用了。不过,我将尝试指定application/json,并使用
query.ApplyTo
方法返回
async Task
。通过
async Task
执行此操作并不容易,尽管使用自定义格式化程序可能会这样做:只需删除一些多余的代码行即可。谢谢@Fabian。我开始尝试返回
异步任务
,但由于某种原因,它没有序列化。仔细想想,这可能是因为Accept头。哦,你的解决方案是显而易见的,而且是成功的。只需删除一些多余的代码行即可。谢谢@Fabian。我开始尝试返回
异步任务
,但由于某种原因,它没有序列化。仔细想想,这可能是因为Accept头。哦,你的解决方案是显而易见的,它是成功的。
<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>
queryOptions.ApplyTo(result.AsQueryable()) as IQueryable<Cars>
[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();
     return result.AsQueryable();
 }
[EnableQuery]
public async Task<IQueryable<Cars>> GetCars()
{
    // return IQueryable<Cars> from context, do not perform request to database
    return await Task.FromResult(_context.GetCarsQuery());
}