OData服务通常是强类型的,因此您必须竭尽全力克服Web API内置的从JSON到CLR类型的映射。
首先,定义一个读取JTokens的新媒体类型格式程序。请注意正在使用的自定义媒体类型。
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行动。请注意,动作参数的类型是vanilla 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]"
}
非常很好的答案。希望我能为你的努力做更多努力。对于不同的内容类型的需求可能是一种破坏我的情况,但我明确地从你的帖子中学到了很多东西。谢谢。 – adrianm
你可以尝试使用带有额外参数的'application/json'。例如,'application/json; format = raw'。 – lencharest