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]"
}