JSON反序列化中的类型提示

本文关键字:类型 提示 反序列化 JSON | 更新日期: 2023-09-27 18:23:58

我一直在使用ASP.NET(asmx)WebService通过AJAX与服务器通信。我现在正在WebMethods中使用复杂类型。我的问题是,我的一个类有一个类型为接口的属性。

当串行化时,一切都很好,因为实例类型是已知的。取消序列化后,JSON转换器不知道要转换为的类型,因为它无法创建我的接口的实例。所以我看了一下类型提示,特别是多态性部分,我一直在努力让它发挥作用,但没有成功。

这是我的代码示例:

[WebService(Namespace = "http://tempuri.org/")] 
[ScriptService]
public class MyService : System.Web.Services.WebService {
    public MyService () { }
    [WebMethod(EnableSession = true)]
    [ScriptMethod]
    public void SaveThing(Thing myThing) 
    {
        //Do stuff
    }
}
public interface IItem : ISerializable
{
    int Id { get; }
    string Options { get; }
}
[DataContract(Namespace="MyNamespace", Name="Item")]
public class Item : IItem
{
    [DataMember]
    public string Url
    {
        get { return m_url; }
    }
}
[Serializable]
public class Thing
{
    public int Id { get; set; }
    public IItem MyItem { get; set; }
}

在序列化时,我得到了myThing (Thing)__type属性,但没有得到属性MyItem (Item)的属性。我试着通过操纵JSON并将其发送回来强制它,但我只得到了InvalidServiceOperation。我是不是在尝试一些不被允许的事情?MSDN文档似乎没有提到我不能使用类型提示来实例化接口,但它的示例确实暗示了类和派生类。

如果可能的话,我想继续使用属性进行序列化,而不是自定义代码,因为我认为它更整洁。尽管如此,仍对编码解决方案持开放态度。

JSON反序列化中的类型提示

好吧,经过更多的搜索和研究,我找到了一个解决方案,它没有我想要的那么整洁和漂亮,但它很有效。

首先,什么不起作用。所以我尝试使用ISerializable,用GetObjectData()和一个去序列化构造函数实现了我的类

[Serializable]
public class Thing : ISerializable
{
    public int Id { get; set; }
    public IItem MyItem { get; set; }
    public Thing(SerializationInfo info, StreamingContext context){
    {
        //Do deserialization and handle IItem object
    }
    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        //Do serialization
    }
}

现在我认为这不起作用,因为Thing的所有属性都在调用此构造函数之前被取消序列化,导致本机序列化程序试图取消我的接口的序列化。

关于什么起了作用。自定义JavascriptConverter进行救援。因此,我更改了Web服务,将字符串作为参数,而不是复杂对象(我不太喜欢这个位),然后实现了一个已知类型为IItemJavascriptConverter,以将取消序列化处理为一个具体的类。

public class ItemConverter : JavaScriptConverter
{
    public override IEnumerable<Type> SupportedTypes
    {
        get { return new List<Type>() { typeof(IItem) }; }
    }
    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    {
        throw new NotImplementedException();
    }
    public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
    {
        //If we are of type IItem
        if (dictionary.ContainsKey("Type")) //My check to make sure we are of type IItem
        {
            var factory = new ItemFactory();
            return factory.CreateItem((int)dictionary["Id"], (string)dictionary["Options"], (ItemTypes)dictionary["Type"]);
        }
        else
        {
            return null;
        }
    }
}
[WebService(Namespace = "http://tempuri.org/")] 
[ScriptService]
public class MyService : System.Web.Services.WebService {
    public MyService () { }
    [WebMethod(EnableSession = true)]
    [ScriptMethod]
    public void SaveThing(string myThing) 
    {
        //Get our custom converter
        var itemConverter = new ItemConverter();
        var serialiser = new JavaScriptSerializer();
        //Register it
        serialiser.RegisterConverters(new List<JavaScriptConverter>() { itemConverter });
        //Deserialise the dashboard
        var theThing = serialiser.Deserialize<Thing>(myThing);
        //Save
        theThing.Save();
    }
}

我希望这能帮助到一些人,如果有人有更优雅的解决方案,我很乐意看到他们。此外,在整个过程中,我不想对第三方库(如Json.NETNewtonSoft JSON等)有任何依赖。