c #JavaScriptConverter - 如何反序列化自定义属性?

时间:2011-11-07 11:17:36

标签: c# javascript json serialization

我有一个已经被序列化为JSON的类,我正在尝试将其反序列化为一个对象。

e.g。

public class ContentItemViewModel
{
    public string CssClass { get; set; }
    public MyCustomClass PropertyB { get; set; }
}

简单属性(CssClass)将反序列化:

 var contentItemViewModels = ser.Deserialize<ContentItemViewModel>(contentItems);

但是PropertyB收到错误......

我们添加了一个JavaScriptConverter:

  ser.RegisterConverters(new List<JavaScriptConverter>{ publishedStatusResolver});

但是当我们将'MyCustomClass'添加为'SupportedType'时,从未调用Deserialize方法。但是,当我们将ContentItemViewModel作为SupportedType时,则会调用Deserialize。

我们有一个当前的解决方案,看起来像这样:

class ContentItemViewModelConverter : JavaScriptConverter
{

    public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
    {
        var cssClass =  GetString(dictionary, "cssClass"); //I'm ommitting the GetString method in this example...           
        var propertyB= GetString(dictionary, "propertyB");

        return new ContentItemViewModel{    CssClass = cssClass , 
                                            PropertyB = new MyCustomClass(propertyB)}
    }

    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    {
        throw new Exception("Only does the Deserialize");
    }

    public override IEnumerable<Type> SupportedTypes
    {
        get
        {
            return new List<Type>
                {
                    typeof(ContentItemViewModel)
                };
        }
    }
}

但我们更喜欢仅反序列化MyCustomClass的简单解决方案,因为ViewModel上还有许多其他字段,每次更改/添加属性时都必须编辑此转换器。 ...

有没有办法反序列化MyCustomClass类型的JUST PropertyB?

感谢您的帮助!

2 个答案:

答案 0 :(得分:0)

您是否考虑过使用DatacontractJsonSerializer

[DataContract]
public class MyCustomClass
{
    [DataMember]
    public string foobar { get; set; }
}

[DataContract]
public class ContentItemViewModel
{
    [DataMember]
    public string CssClass { get; set; }
    [DataMember]
    public MyCustomClass PropertyB { get; set; }
}

class Program
{
    static void Main(string[] args)
    {

        ContentItemViewModel model = new ContentItemViewModel();
        model.CssClass = "StackOver";
        model.PropertyB = new MyCustomClass();
        model.PropertyB.foobar = "Flow";

        //Create a stream to serialize the object to.
        MemoryStream ms = new MemoryStream();

        // Serializer the User object to the stream.
        DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(ContentItemViewModel));
        ser.WriteObject(ms, model);
        byte[] json = ms.ToArray();
        ms.Close();
        string s=  Encoding.UTF8.GetString(json, 0, json.Length);


        Console.ReadLine();
    }
}

如果MyCustomClass有派生词,则将所有可能的类添加到 DatacontractJsonSerializer.KnownTypes

答案 1 :(得分:0)

对于所有这些可能值得的东西,但我偶然发现同样的问题,解决方案是解串器没有得到关于你反序列化的类的线索,除非你给他必要的信息。

在顶层,它知道Deserialize&lt;&gt;()的类型参数中的类型。这就是为什么ContentItemViewModel的转换器有效。对于嵌套对象,它需要__type属性和JavaScriptTypeResolver。

var ser = new JavaScriptSerializer(new SimpleTypeResolver());
ser.RegisterConverters(myconverters);
MyClass myObject = new MyClass();
string json = ser.Serialize(myObject);
    // set a breakpoint here to see what has happened
ser.Deserialize<MyClass>(json);

TypeResolver为每个序列化对象添加__type属性。您可以编写使用短名称的自定义类型解析程序。在此示例中,我使用.net中的SimpleTypeResolver“简单地”将完全限定的类型名称存储为__type。反序列化时,JavaScriptDeserializer找到__type并向TypeResolver询问正确的类型。然后它知道一个类型,并且可以调用已注册的JavaScriptConverter.Deserialize方法。

如果没有TypeResolver,则会将对象反序列化为Dictionary,因为JavaScriptSerializer没有任何类型信息。

如果你不能在你的json字符串中提供__type属性,我认为你需要首先反序列化为Dictionary,然后添加一个“猜测步骤”来解释字段以找到正确的类型。然后,您可以使用JavaScriptSerializer的ConvertToType方法将字典复制到对象的字段和属性中。

如果您需要使用ASP.NET提供的JavaScriptSerializer并且无法创建自己的JavaScriptSerializer,请从JavaScriptSerializer的.ctor帮助中考虑此部分:

异步通信层用于从客户端脚本调用Web服务的JavaScriptSerializer实例使用特殊类型解析程序。此类型解析程序将可以反序列化的类型限制为Web服务的方法签名中定义的类型,或者应用了GenerateScriptTypeAttribute的类型。您无法以编程方式修改此内置类型解析程序。

也许GenerateScriptType属性可以帮助您。但我不知道这里需要什么类型的__type属性。