C# 包络Odata响应

C# 包络Odata响应,c#,odata,.net-5,envelope,C#,Odata,.net 5,Envelope,我将Odata添加到我的项目中,以便可以使用url查询参数,如$filter。 对于演示类/控制器,输出现在如下所示: { "@odata.context": "https://localhost:5001/api/v1/$metadata#WeatherForecast", "value": [ { "Id": 1, "Date": "2021-

我将Odata添加到我的项目中,以便可以使用url查询参数,如
$filter
。 对于演示类/控制器,输出现在如下所示:

{
  "@odata.context": "https://localhost:5001/api/v1/$metadata#WeatherForecast",
  "value": [
    {
      "Id": 1,
      "Date": "2021-05-22T14:00:18.9513586+02:00",
      "TemperatureC": 36,
      "Summary": "Sweltering"
    },
    {
      "Id": 2,
      "Date": "2021-05-23T14:00:21.6231763+02:00",
      "TemperatureC": 44,
      "Summary": "Chilly"
    }
  ]
}
{
    "data": {
        "type": "WeatherForecast",
        "count": 2,
        "items" : [
            {
              "Id": 1,
              "Date": "2021-05-22T14:00:18.9513586+02:00",
              "TemperatureC": 36,
              "Summary": "Sweltering"
            },
            {
              "Id": 2,
              "Date": "2021-05-23T14:00:21.6231763+02:00",
              "TemperatureC": 44,
              "Summary": "Chilly"
            }
        ]
    },
    "error": null
}
到目前为止,一切都很好

使用我的API的前端团队现在想要信封之类的东西。。(这样叫吗?) 他们希望得到这样的结果:

{
  "@odata.context": "https://localhost:5001/api/v1/$metadata#WeatherForecast",
  "value": [
    {
      "Id": 1,
      "Date": "2021-05-22T14:00:18.9513586+02:00",
      "TemperatureC": 36,
      "Summary": "Sweltering"
    },
    {
      "Id": 2,
      "Date": "2021-05-23T14:00:21.6231763+02:00",
      "TemperatureC": 44,
      "Summary": "Chilly"
    }
  ]
}
{
    "data": {
        "type": "WeatherForecast",
        "count": 2,
        "items" : [
            {
              "Id": 1,
              "Date": "2021-05-22T14:00:18.9513586+02:00",
              "TemperatureC": 36,
              "Summary": "Sweltering"
            },
            {
              "Id": 2,
              "Date": "2021-05-23T14:00:21.6231763+02:00",
              "TemperatureC": 44,
              "Summary": "Chilly"
            }
        ]
    },
    "error": null
}
有没有可能我可以这样做?要么直接和OData,要么以其他方式?
我不能简单地更改返回类型,因为OData希望将
IQueryable
作为返回类型。这是我尝试过的,但Odata无法过滤。

问题是,你在上面发布的内容有效-这是Odata的信封响应。 信封意味着对象被包装在
odata
$odata
标记中,并包含json数组中的响应值:

“值”:[{..}{..}]

您的客户期望的是数据对象的一个信封式的简单列表,形式为

{“数据”:{[{..}{..}},“错误”:..}

如果要获取普通列表,则必须相应地使用$select attr,例如:


。/api/home/GetSomeList?$select=param1,param2,param3

问题是,你在上面发布的内容有效-这是Odata的信封响应。 信封意味着对象被包装在
odata
$odata
标记中,并包含json数组中的响应值:

“值”:[{..}{..}]

您的客户期望的是数据对象的一个信封式的简单列表,形式为

{“数据”:{[{..}{..}},“错误”:..}

如果要获取普通列表,则必须相应地使用$select attr,例如:


。/api/home/GetSomeList?$select=param1、param2、param3
有几种方法可以实现这一点,但在我直接回答问题之前,我必须提到,如果您自定义api返回的响应。一些OData集成(例如PowerBI、OData客户端等)可能由于非常规响应格式而无法按预期工作。但是,如果您不打算将任何OData客户机与API集成,这对您来说应该不是问题

另一件事是,您可能应该与公司的前端开发人员进行讨论,只有在他们收到响应中的非成功状态代码时才查找错误。并且他们应该期望REST标准错误响应(即)。他们建议的回应方式在美国更为普遍

回到主题,要定制OData响应,可以通过控制器的动作方法来实现

public IActionResult Get(ODataQueryOptions<WeatherForecast> odataOptions)
    {
        var data = odataOptions.ApplyTo(_dbContext.Forecasts);
        var odataFeature = HttpContext.ODataFeature();

        var response = new WeatherApiEnvelope()
        {
            Data = new WeatherApiDataEnvelope()
            {
                Count = odataFeature.TotalCount,
                Items = data,
                Type = odataFeature.Path.GetEdmType().AsElementType().FullTypeName()
            }
        };

        return Ok(response);
    }
在这里,我在第一个索引中插入我的自定义OutputFormatter,使其在现有ODataOutputFormatter之前运行,这不会删除现有ODataOutputFormatter,但会覆盖它,因为它将首先运行以处理请求


注意:在这种情况下,在AddController之前调用AddOData()非常重要。而且我的格式化程序的实现只是为了演示,您应该处理更多的情况(例如,检查空值、处理错误、使用序列化选项等等)。

有几种方法可以实现这一点,但在我直接回答问题之前,我必须提一下,如果您自定义API返回的响应。一些OData集成(例如PowerBI、OData客户端等)可能由于非常规响应格式而无法按预期工作。但是,如果您不打算将任何OData客户机与API集成,这对您来说应该不是问题

另一件事是,您可能应该与公司的前端开发人员进行讨论,只有在他们收到响应中的非成功状态代码时才查找错误。并且他们应该期望REST标准错误响应(即)。他们建议的回应方式在美国更为普遍

回到主题,要定制OData响应,可以通过控制器的动作方法来实现

public IActionResult Get(ODataQueryOptions<WeatherForecast> odataOptions)
    {
        var data = odataOptions.ApplyTo(_dbContext.Forecasts);
        var odataFeature = HttpContext.ODataFeature();

        var response = new WeatherApiEnvelope()
        {
            Data = new WeatherApiDataEnvelope()
            {
                Count = odataFeature.TotalCount,
                Items = data,
                Type = odataFeature.Path.GetEdmType().AsElementType().FullTypeName()
            }
        };

        return Ok(response);
    }
在这里,我在第一个索引中插入我的自定义OutputFormatter,使其在现有ODataOutputFormatter之前运行,这不会删除现有ODataOutputFormatter,但会覆盖它,因为它将首先运行以处理请求


注意:在这种情况下,在AddController之前调用AddOData()非常重要。此外,我的格式化程序实现仅用于演示,您应该处理更多情况(例如,检查空值、处理错误、使用序列化选项等)

ehm。。这只会减少odata中的属性。$select不会在其周围添加“数据”和“错误”。看来我需要把他们的开源项目交给我自己做…嗯。。这只会减少odata中的属性。$select不会在其周围添加“数据”和“错误”。看起来我需要自己完成他们的开源项目……OData已经是一个信封形式,它不是GraphQL信封,但已经包装好了。一个简单的转换通常应用于消费端。但是,您可以在OData生成响应消息后添加中间件来转换响应。最终,您将被要求实现不同的媒体类型格式,因此,无论您使用何种解决方案,都应该要求客户端发送特定的头以启用此行为数据已在信封形式中,它不是GraphQL信封,但已被包装。一个简单的转换通常应用于消费端。但是,您可以在OData生成响应消息后添加中间件来转换响应。最终,您会被要求实现不同的媒体类型格式,因此无论您使用何种解决方案,都应该要求客户端发送特定的头以启用此功能。感谢您的详细回复。我也是这样走的。我不确定这是不是一个好方法,但它奏效了。这是一件很棒的事情,
ODataFeature
不知道这一点。谢谢,所以我接受t