代码之家  ›  专栏  ›  技术社区  ›  adrianm

webapi odata中的大型json参数

  •  1
  • adrianm  · 技术社区  · 10 年前

    我得到了一个WebApiOData服务,我需要一个操作来获取任意的json参数。

    有没有办法将类似JObject的东西作为OData操作参数? action.Parameter<JObject>() 不起作用。

    复杂类型“Newtonsoft.Json.Linq”。“JContainer”通过属性“Parent”对自身进行了引用。不允许复杂类型的递归循环。

    它使用字符串参数工作,但这意味着所有请求的两端都需要进行不必要的转换。json可能也很大(100kb+),所以我认为它会给大对象堆施加压力,使其使用字符串。

    1 回复  |  直到 10 年前
        1
  •  1
  •   lencharest    10 年前

    OData服务通常是强类型的,因此您必须尽力克服Web API从JSON到CLR类型的内置映射。

    首先,定义一个读取JToken的新媒体类型格式化程序。请注意正在使用的自定义媒体类型。

    public class RawJsonMediaTypeFormatter : MediaTypeFormatter
    {
        private static readonly MediaTypeHeaderValue _customMediaType = 
            MediaTypeHeaderValue.Parse("application/prs.adrianm+json");
    
        public RawJsonMediaTypeFormatter() : base()
        {
            this.Intialize();
        }
    
        protected RawJsonMediaTypeFormatter(MediaTypeFormatter formatter) : base(formatter)
        {
            this.Intialize();
        }
    
        protected void Intialize()
        {
            this.SupportedMediaTypes.Add(_customMediaType);
        }
    
        public override MediaTypeFormatter GetPerRequestFormatterInstance(Type type, HttpRequestMessage request, MediaTypeHeaderValue mediaType)
        {
            if (type == typeof(JToken) && mediaType.MediaType == _customMediaType.MediaType)
            {
                return this;
            }
    
            return base.GetPerRequestFormatterInstance(type, request, mediaType);
        }
    
        public override bool CanReadType(Type type)
        {
            return type == typeof(JToken);
        }
    
        public override bool CanWriteType(Type type)
        {
            return false;
        }
    
        public override Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger)
        {
            return this.ReadFromStreamAsync(type, readStream, content, formatterLogger, default(CancellationToken));
        }
    
        public override Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger, CancellationToken cancellationToken)
        {
            object result;
    
            using (var reader = new JsonTextReader(new StreamReader(readStream)))
            {
                result = JToken.ReadFrom(reader);
            }
    
            return Task.FromResult(result);
        }
    }
    

    作为Web API注册的一部分,将自定义格式化程序的实例添加到HttpConfiguration并声明OData操作。注意,动作参数的类型是香草 object .

            config.Formatters.Clear();
            config.Formatters.AddRange(ODataMediaTypeFormatters.Create());
            config.Formatters.Add(new RawJsonMediaTypeFormatter());
    
            var builder = new ODataConventionModelBuilder();
            var arbitraryJsonAction = builder.Action("ArbitraryJson");
            arbitraryJsonAction.Parameter<object>("json");
            arbitraryJsonAction.Returns<string>();
    

    为操作添加控制器方法。

        [HttpPost]
        [ODataRoute("ArbitraryJson")]
        public IHttpActionResult ArbitraryJson(JToken json)
        {
            return this.Ok(json.ToString());
        }
    

    在客户端上,记得设置 Content-Type 到由自定义格式化程序处理的自定义媒体类型:

    POST http://host/ArbitraryJson
    Content-Type: application/prs.adrianm+json
    
    [1, 2, {"foo": true }]
    

    响应有效载荷应如下所示:

    {
      "@odata.context": "http://host/$metadata#Edm.String",
      "value": "[\r\n  1,\r\n  2,\r\n  {\r\n    \"foo\": true\r\n  }\r\n]"
    }