在Asp.Net的Web API Deserialising JSON来派生类型 [英] Deserialising Json to derived types in Asp.Net Web API

查看:81
本文介绍了在Asp.Net的Web API Deserialising JSON来派生类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我打电话给我的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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆