【问题标题】:Web Api with OData v4 throwing exception on $select带有 OData v4 的 Web Api 在 $select 上抛出异常
【发布时间】:2015-03-11 13:57:04
【问题描述】:

我正在使用最新版本的 WebApi 和 OData,一切都已设置为正常工作。唯一的问题是当我尝试使用 $select 时。

它会抛出以下错误

  Object of type 'System.Linq.EnumerableQuery`1[System.Web.OData.Query.Expressions.SelectExpandBinder+SelectAll`1[WebApplication1.Controllers.Person]]' cannot be converted to type 'System.Collections.Generic.IEnumerable`1[WebApplication1.Controllers.Person]'.

我查看了文档,他们的建议是在控制器中的 Get 方法之上使用 [Queryable] 或在 WebApiConfig 中使用 config.EnableQuerySupport 并且这些都不是可用的选项。我目前正在使用[EnableQuery]

编辑

OdataController:

    using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.OData;
using System.Xml.Serialization;

namespace WebApplication1.Controllers
{
    public class PeopleController : ODataController
    {
        // GET api/values
        [EnableQuery]
        public IQueryable<Person> Get()
        {
            return new Person[] { new Person()
            {
                Id = 1,
                FirstName = "Testing",
                LastName = "2"
            },  new Person()
            {
                Id = 2,
                FirstName = "TestTest",
                LastName = "3"
            } }.AsQueryable();
        }

        // GET api/values/5
        public Person Get(int id)
        {
            return new Person()
            {
                Id = 3,
                FirstName = "Test",
                LastName = "1"
            };
        }

        // POST api/values
        public void Post([FromBody]Person value)
        {
        }

        // PUT api/values/5
        public void Put(int id, [FromBody]Person value)
        {
        }

        // DELETE api/values/5
        public void Delete(int id)
        {
        }
    }

    public class Person
    {
        [Key]
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
}

WebApiConfig

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
using System.Web.OData;
using System.Web.OData.Builder;
using System.Web.OData.Extensions;
using System.Web.OData.Formatter;
using WebApplication1.Controllers;

namespace WebApplication1
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services

            // Web API routes
            config.MapHttpAttributeRoutes();

            var odataFormatters = ODataMediaTypeFormatters.Create();
            config.Formatters.InsertRange(0, odataFormatters);

            ODataModelBuilder builder = new ODataConventionModelBuilder();
            builder.EntitySet<Person>("People");
            config.AddODataQueryFilter();
            config.MapODataServiceRoute(
            routeName: "ODataRoute",
            routePrefix: "api",
            model: builder.GetEdmModel());

        }
    }
}

更新 2

似乎只在以 xml 格式检索数据时抛出错误。 Json 似乎可以工作

【问题讨论】:

  • 请显示 OData 控制器和操作代码。
  • Atom 格式已从 Web API OData V4 中淘汰。
  • 感谢 Shems 的更新。我有同样的问题,因为我可以在我的情况下使用 $format=JSON 来为我解决它。

标签: asp.net odata asp.net-web-api asp.net-web-api2


【解决方案1】:

找到了解决办法。它并不完美,但它确实有效!

也许它对某人有用,因为我已经花了几个小时的研究和尝试。

步骤 #1 创建自定义 xml 格式化程序:

public class CustomXmlFormatter : MediaTypeFormatter
{
    private JsonMediaTypeFormatter jFormatter = null;
    public CustomXmlFormatter(JsonMediaTypeFormatter jFormatter)
    {
        SupportedMediaTypes.Add(new System.Net.Http.Headers.MediaTypeHeaderValue("application/xml"));
        this.jFormatter = jFormatter;
    }

    public override bool CanReadType(Type type)
    {
        return false;
    }

    public override bool CanWriteType(Type type)
    {
        return true;
    }
    public override Task WriteToStreamAsync(Type type, object value, System.IO.Stream writeStream, System.Net.Http.HttpContent content, System.Net.TransportContext transportContext)
    {
        return Task.Factory.StartNew(() =>
        {
            using (MemoryStream ms = new MemoryStream())
            {
                var tsk = jFormatter.WriteToStreamAsync(type, value, ms, content, transportContext);
                tsk.Wait();
                ms.Flush();
                ms.Seek(0, SeekOrigin.Begin);

                var xDoc = XDocument.Load(JsonReaderWriterFactory.CreateJsonReader(ms, new XmlDictionaryReaderQuotas()));

                using (XmlWriter xw = XmlWriter.Create(writeStream))
                {
                    xDoc.WriteTo(xw);
                }

            }
        });
    }
}

步骤 #2 在启动部分注册它:

        var formatters = ODataMediaTypeFormatters.Create();
        var jsonFormatter = config.Formatters.JsonFormatter;
        var customXmlFormatter = new CustomXmlFormatter(jsonFormatter);

        customXmlFormatter.AddQueryStringMapping("$format", "cxml", "application/xml");
        config.Formatters.Add(customXmlFormatter);

把它当作 http://url..../actionName?$format=cxml&$select=ObjectName,ObjectId

【讨论】:

    【解决方案2】:

    这是 System.Net.Formatting Nuget 包中 XmlMediaTypeFormatter 类的已知限制。 JSON 格式化程序的实现确实支持 $select 和 $expand 命令,但是当内容协商确定应返回 XML 时,这些命令不可用。

    如果您需要返回 XML 格式的响应,您应该考虑实现 OData 端点(而不是 WebAPI 端点)。可以在此处找到有关如何完成此操作的更多信息:

    http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/supporting-odata-query-options

    【讨论】:

      猜你喜欢
      • 2014-05-15
      • 2013-01-02
      • 1970-01-01
      • 1970-01-01
      • 2015-04-15
      • 1970-01-01
      • 1970-01-01
      • 2015-05-20
      • 2016-06-12
      相关资源
      最近更新 更多