【问题标题】:web api json deserialization failureweb api json反序列化失败
【发布时间】:2012-07-19 07:00:46
【问题描述】:

我有一个在 web api 中使用的请求端点:

 public HttpResponseMessage Create(IList<SlideContent> l)
    {
        ...
    }

我将参数作为 json 发送,web api 将其序列化为 IList

幻灯片内容是:

public abstract class SlideItem
    {
       ...
    }

我有专门的课程

    public class TitleSlideItem : SlideItem
    {
        ...
    }


    public class ParagraphSlideItem : SlideItem
    {
       ...
    }

就像我不能调用 Create 函数,因为我得到了一个

缺少方法异常:无法创建抽象类

所以我不能反序列化 json 参数。如果我删除了抽象修饰符,那么我就没有专门的对象,每个对象的类型都是SlideContent。 我什至在 json 中放了注解,但也没有用。

如果我没记错的话,我将不得不为抽象类编写一个自定义活页夹,但我该怎么做呢?

此致,

佐利

【问题讨论】:

    标签: asp.net-mvc json asp.net-web-api


    【解决方案1】:

    一种可能性是将内置 JSON 序列化程序替换为使用 JSON.NET 的自定义格式化程序,如 following blog post 所示。

    public class JsonNetFormatter : MediaTypeFormatter
    {
        private JsonSerializerSettings _jsonSerializerSettings;
    
        public JsonNetFormatter(JsonSerializerSettings jsonSerializerSettings)
        {
            _jsonSerializerSettings = jsonSerializerSettings ?? new JsonSerializerSettings();
    
            // Fill out the mediatype and encoding we support
            SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));
            Encoding = new UTF8Encoding(false, true);
        }
    
        protected override bool CanReadType(Type type)
        {
            if (type == typeof(IKeyValueModel))
            {
                return false;
            }
    
            return true;
        }
    
        protected override bool CanWriteType(Type type)
        {
            return true;
        }
    
        protected override Task<object> OnReadFromStreamAsync(Type type, Stream stream, HttpContentHeaders contentHeaders, FormatterContext formatterContext)
        {
            // Create a serializer
            JsonSerializer serializer = JsonSerializer.Create(_jsonSerializerSettings);
    
            // Create task reading the content
            return Task.Factory.StartNew(() =>
            {
                using (StreamReader streamReader = new StreamReader(stream, Encoding))
                {
                    using (JsonTextReader jsonTextReader = new JsonTextReader(streamReader))
                    {
                        return serializer.Deserialize(jsonTextReader, type);
                    }
                }
            });
        }
    
        protected override Task OnWriteToStreamAsync(Type type, object value, Stream stream, HttpContentHeaders contentHeaders, FormatterContext formatterContext, TransportContext transportContext)
        {
            // Create a serializer
            JsonSerializer serializer = JsonSerializer.Create(_jsonSerializerSettings);
    
            // Create task writing the serialized content
            return Task.Factory.StartNew(() =>
            {
                using (JsonTextWriter jsonTextWriter = new JsonTextWriter(new StreamWriter(stream, Encoding)) { CloseOutput = false })
                {
                    serializer.Serialize(jsonTextWriter, value);
                    jsonTextWriter.Flush();
                }
            });
        }
    }
    

    然后在Application_Start 注册格式化程序时,您可以配置序列化程序以使用 JSON 中的类型信息:

    var formatters = GlobalConfiguration.Configuration.Formatters;
    formatters.Remove(formatters.XmlFormatter);
    formatters.Remove(formatters.JsonFormatter);
    
    var serializerSettings = new JsonSerializerSettings();
    serializerSettings.TypeNameHandling = TypeNameHandling.Objects;
    serializerSettings.Converters.Add(new IsoDateTimeConverter());
    formatters.Add(new JsonNetFormatter(serializerSettings));
    

    然后您可以发布以下 JSON:

    [
        { 
            "$type":"AppName.Models.TitleSlideItem, AppName",
            "Id":1,
            "Title":"some title" // this is a specific property of the TitleSlideItemclass
        },
        {
            "$type":"AppName.Models.ParagraphSlideItem, AppName",
            "Id":2,
            "Paragraph":"some paragraph" // this is a specific property of the ParagraphSlideItem class
        }
    ]
    

    将在此操作中成功反序列化:

    public HttpResponseMessage Post(IList<SlideItem> l)
    {
        ...
    }
    

    【讨论】:

      【解决方案2】:

      JsonFx 创建自定义绑定器。例如看看:

      https://code.google.com/p/jsonfx/source/browse/trunk/JsonFx/JsonFx.MvcTemplate/Global.asax.cs

      查看该文件中的 RegisterBinders() 函数和活页夹的源代码,或者只安装 JsonFx 并使用他们的 MVC 模板创建一个项目,看看他们是如何做到的,或者如果这对你有用,就使用他们的库。这就是我会做的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多