c# - JSON 反序列化中的类型提示

标签 c# .net json deserialization datacontract

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

当序列化时,一切都很好,因为实例类型是已知的。反序列化 JSON 转换器不知道要转换成的类型,因为它无法创建我的接口(interface)的实例。所以我看了一下Type Hinting特别是多态部分,我一直在努力让它工作,但没有成功。

这是我的代码示例:

[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 文档似乎没有提到我不能使用实例化类型提示反序列化到接口(interface),但它的示例确实暗示了类和派生类。

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

最佳答案

是的,经过更多的搜索和研究,我想出了一个解决方案,它不像我想要的那样整洁和漂亮,但它有效。

首先是什么不起作用。所以我尝试使用 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 的所有属性都被反序列化,导致 native 序列化程序尝试反序列化我的接口(interface)。

关于什么起作用了。自定义 JavascriptConverter 来拯救。所以我更改了我的 web 服务以将字符串作为参数而不是复杂的对象(我不太喜欢这一点),然后实现了一个 JavascriptConverter 具有已知类型的 IItem 将反序列化处理为具体类。

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 等。

关于c# - JSON 反序列化中的类型提示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25992192/

相关文章:

javascript - 时间未通过 moment.js 正确转换为本地时间

c# - 应用程序洞察中自定义对象的属性在哪里

c# - 如何使用 C# 播放 mp3 ...没有第三个 dll

c# - 如何将二进制 blob 编码为 Unicode blob?

c# - 获取系统命名空间中的所有类型

javascript - 使用 grunt-json-bake 将多个 json 文件编译成一个

java - 解码数组不会给我任何值

c# - 捕获所有内部异常详细信息的最佳做法是什么?

c# - 获取未设置为对象实例的对象引用的空引用对象的类型

json - 防止所有用户删除特定的cloudformation堆栈