如何为 OData Api 提供自定义媒体类型格式

Dan*_*iel 4 odata asp.net-web-api

我正在开发一个使用 ODataApiController 的 ASP.NET 应用程序。该应用程序通过查询数据并将其显示在表格中来向用户显示网格。我希望能够导出为多种不同的格式,包括 CSV 和自定义 XML 格式。理想情况下,我只会采用网格使用的相同 OData 查询,设置 Accepts 标头,然后返回 CSV 或 XML。

我创建了 MediaTypeFormatters 来做我需要的事情,但它们只适用于“常规”ApiController,而不是 ODataApiController。查看 github 中的代码,我看到 OData 有自己的 MediaTypeFormatter 方案来处理各种情况,并内置了 XML 和 JSON 格式器。但我看不到如何挂钩以提供自定义格式。我曾尝试继承 ODataMediaTypeFormatter,但在其上设置的断点从未命中。

我只对这里的输出格式感兴趣。如何扩展 OdataApi 以输出不同的格式?

Jan*_*mes 5

您也可以MediaTypeFormatter在 OData 查询上使用。只需在您的项目中添加一个继承MediaTypeFormatter. 然后在注册时将其添加到您的 WebApiConfig 文件中:

config.Formatters.Add(new JSONPFormatter(new QueryStringMapping("$format","jsonp","application/javascript")));
Run Code Online (Sandbox Code Playgroud)

如果您随后使用 查询您的实体,$format=jsonp它将以 JSONP 形式返回实体。您还可以使用 contenttype 请求它application/javascript以获取 JSONP 返回。

这是用于 JSONP 返回的 MediaFormatter 的完整示例。您可以根据需要轻松更改它:

using MyProject.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.ServiceModel.Syndication;
using System.Threading.Tasks;
using System.Web;
using System.Xml;
using Newtonsoft.Json;


namespace SMSIdent.Modules.Formatter
{
    /// <summary>
    /// Adds a $format=jsop to all odata query
    /// </summary>
    public class JSONPFormatter : MediaTypeFormatter
    {
        private readonly string jsMIME = "application/javascript";

        public JSONPFormatter()
        {
            SupportedMediaTypes.Add(new MediaTypeHeaderValue(jsMIME));
        }

        public JSONPFormatter(MediaTypeMapping mediaTypeMapping) : this() 
        {

            MediaTypeMappings.Add(mediaTypeMapping);
        }

        //THis checks if you can POST or PUT to this media-formater
        public override bool CanReadType(Type type)
        {
            return false;
        }

        //this checks if you can GET this media. You can exclude or include your Resources by checking for their types
        public override bool CanWriteType(Type type)
        {
            return true;
        }

        //This actually takes the data and writes it to the response 
        public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, System.Net.Http.HttpContent content, System.Net.TransportContext transportContext)
        {
            //you can cast your entity
            //MyType entity=(MyType) value;
            var callback=HttpContext.Current.Request.Params["callback"];
            return Task.Factory.StartNew(() =>
            {
                using (StreamWriter sw = new StreamWriter(writeStream))
                {
                    if (string.IsNullOrEmpty(callback))
                    {
                        callback = "values";
                    }
                    sw.Write(callback + "(" + JsonConvert.SerializeObject(value, Newtonsoft.Json.Formatting.None,
                        new JsonSerializerSettings
                        {
                            ReferenceLoopHandling = ReferenceLoopHandling.Ignore
                        }) + ")");
                }

            });
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:我使用的是 Web API 2。我不知道它是否也适用于 Web Api 1。