在Asp.Net的Web API Deserialising JSON来派生类型 [英] Deserialising Json to derived types in Asp.Net Web API
问题描述
我打电话给我的WebAPI的方法与模型发送,我想匹配(或绑定)一个JSON。
I'm calling a method of my WebAPI sending a json that I would like to match (or bind) with a model.
在控制器我有这样一个方法:
In the controller I have a method like:
public Result Post([ModelBinder(typeof(CustomModelBinder))]MyClass model);
MyClass的',给出至极作为参数是一个抽象类。我想,在根据通过JSON的类型,正确继承的类实例化。
'MyClass', wich is given as a parameter is an abstract class. I would like that at, depending of the type of json passed, the correct inherited class is instantiated.
要实现它,我想实现一个自定义的粘合剂。问题是,(我不知道这是很基本的,但我无法找到任何东西),我不知道如何检索进来请求的原始JSON(或更好的,某种序列化的)。
To achieve it, I'm trying to implement a custom binder. The problem is that (I don't know if it's very basic but I can't find anything) I don't know how to retrieve the raw Json (or better, some kind of serialization) that comes in the request.
我见:
- actionContext.Request.Content
不过,所有方法都公开为异步。我不知道是谁这符合与生成模式传递给控制器的方法...
But all methods are exposed as async. I don't know who this fits with passing the generate model to the controller method...
非常感谢!
推荐答案
您不需要自定义模型粘合剂。你也不需要请求管道淤泥约。
You don't need a custom model binder. Nor do you need to muck about with the request pipeline.
看看这个其他SO:<一href=\"http://stackoverflow.com/questions/8030538/how-to-implement-custom-jsonconverter-in-json-net-to-deserialize-a-list-of-base\">How实现自定义JsonConverter在JSON.NET反序列化基类的List对象。
我用这个作为我自己的解决方案,以同样的问题奠定了基础。
I used this as the basis for my own solution to the same problem.
与出发的 JsonCreationConverter&LT; T&GT;
在引用SO(略作修改,以解决与响应类型的序列化的问题):
Starting off with the JsonCreationConverter<T>
referenced in that SO (slightly modified to fix issues with serialization of types in responses):
public abstract class JsonCreationConverter<T> : JsonConverter
{
/// <summary>
/// this is very important, otherwise serialization breaks!
/// </summary>
public override bool CanWrite
{
get
{
return false;
}
}
/// <summary>
/// Create an instance of objectType, based properties in the JSON object
/// </summary>
/// <param name="objectType">type of object expected</param>
/// <param name="jObject">contents of JSON object that will be
/// deserialized</param>
/// <returns></returns>
protected abstract T Create(Type objectType, JObject jObject);
public override bool CanConvert(Type objectType)
{
return typeof(T).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType,
object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
// Load JObject from stream
JObject jObject = JObject.Load(reader);
// Create target object based on JObject
T target = Create(objectType, jObject);
// Populate the object properties
serializer.Populate(jObject.CreateReader(), target);
return target;
}
public override void WriteJson(JsonWriter writer, object value,
JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
现在你可以用你的注释类型 JsonConverterAttribute
,指着Json.Net到自定义转换器:
And now you can annotate your type with the JsonConverterAttribute
, pointing Json.Net to a custom converter:
[JsonConverter(typeof(MyCustomConverter))]
public abstract class BaseClass{
private class MyCustomConverter : JsonCreationConverter<BaseClass>
{
protected override BaseClass Create(Type objectType,
Newtonsoft.Json.Linq.JObject jObject)
{
//TODO: read the raw JSON object through jObject to identify the type
//e.g. here I'm reading a 'typename' property:
if("DerivedType".Equals(jObject.Value<string>("typename"))
return new DerivedClass();
else
return new DefaultClass();
//now the base class' code will populate the returned object.
}
}
}
public class DerivedClass : BaseClass {
public string DerivedProperty { get; set; }
}
public class DefaultClass : BaseClass {
public string DefaultProperty { get; set; }
}
现在你可以使用基本类型作为参数:
Now you can use the base type as a parameter:
public Result Post(BaseClass arg) {
}
如果我们要发布:
And if we were to post:
{ typename: 'DerivedType', DerivedProperty: 'hello' }
然后 ARG
将是一个实例 DerivedClass
,但如果我们发布:
Then arg
would be an instance of the DerivedClass
, but if we posted:
{ DefaultProperty: 'world' }
然后你会得到的一个实例 DefaultClass
。
我相信,使用 TypeNameHandling.Auto/All
按JotaBe信奉并非总是理想的解决方案。这很可能是在这种情况下 - 但我个人不会做,除非:
I do believe that using the TypeNameHandling.Auto/All
espoused by JotaBe is not always the ideal solution. It might well be in this case - but personally I won't do it unless:
- 我的API的只会的要由我或我的团队 使用
- 我不关心有一个双兼容的XML的端点
- My API is only ever going to be used by me or my team
- I don't care about having a dual XML-compatible endpoint
在Json.Net TypeNameHandling.Auto
或所有
的使用,Web服务器将开始发送类型名称格式为 MyNamespace.MyType,MyAssemblyName
。
When Json.Net TypeNameHandling.Auto
or All
are used, your web server will start sending out type names in the format MyNamespace.MyType, MyAssemblyName
.
我在,我认为这是一个安全问题评论说。有人提到一些文档,我从微软阅读制成了这一点。它没有提到任何更多的,似乎,但是我还是觉得这是一个有效的关注。我不 曾经的希望名称空间限定的类型名称和程序集名称暴露给外界。它增加我的攻击面。所以,是的,我不能让对象
属性/参数我的API类型,但谁又能说我的网站的其余部分是完全免费的洞?谁在说未来的端点不暴露利用类型名称的能力?只是因为它更容易,为什么冒这个险?
I have said in comments that I think this is a security concern. Mention was made of this in some documentation I read from Microsoft. It's not mentioned any more, it seems, however I still feel it's a valid concern. I don't ever want to expose namespace-qualified type names and assembly names to the outside world. It's increasing my attack surface. So, yes, I can not have Object
properties/parameters my API types, but who's to say the rest of my site is completely hole-free? Who's to say a future endpoint doesn't expose the ability to exploit type names? Why take that chance just because it's easier?
此外 - 如果你正在写一个'适当'的API,即专门为第三方消费,不只是为自己,你正在使用的Web API,那么你很可能希望利用JSON / XML内容类型处理(最低)。看看你想多远,写文档,很容易消耗,这是指以不同的XML和JSON格式的所有API类型。
Also - if you are writing a 'proper' API, i.e. specifically for consumption by third-parties and not just for yourself, and you're using Web API, then you're most likely looking to leverage the JSON/XML content-type handling (as a minimum). See how far you get trying to write documentation that's easy to consume, which refers to all your API types differently for XML and JSON formats.
通过覆盖JSON.Net如何理解的类型名称,你可以把两成线,使得XML / JSON之间的选择主叫方完全基于味道,而不是因为类型名称更容易记住一个或其他。
By overriding how JSON.Net understands the type names, you can bring the two into line, making the choice between XML/JSON for your caller purely based on taste, rather than because the type names are easier to remember in one or the other.
这篇关于在Asp.Net的Web API Deserialising JSON来派生类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!