【问题标题】:Object serializable for AJAX, WCF and ViewState可用于 AJAX、WCF 和 ViewState 的对象序列化
【发布时间】:2010-06-30 12:32:18
【问题描述】:

考虑下面的类和结构

public class Entity {
    public IdType Id {get;set;}
    public string Data {get;set;}
}

[TypeConverter(IdTypeConverter))]
public struct IdType {
    ... any data ...
}

IdTypeConverter 可以将 IdType 结构体从字符串转换为字符串。

现在,我希望这个类可以为 AJAX、WCF 和 ViewState 序列化。 senario 可以是一个 WCF Web 服务,它以 Entity[] 数组的形式提供给 DataSource。还有一个绑定到数据源的自定义控件,将此类保存到它的 ViewState 并将数据发送到客户端代码。

这可以通过简单地向所有序列化类型添加 [Serializable] 属性来轻松实现。但我不希望 IdType 被序列化,而是被转换为字符串。因此 JSON 表示应该是

{ 'Id'=>'StringRepresentationOfId', 'Data'=>'foo' }

类似地,这将是 WCF 和 ViewState 的最佳序列化。

另一种解决方案是编写另一个类

public class JsonEntity {
    public JsonEntity(Entity from) {
        Id = from.Id;
        Data = from.Data;
    }
    public string Id {get;set;}
    public string Data {get;set;}
}

并将其用于 JsonSerialization。但我不喜欢这样,因为这意味着向客户端发送数据的控件知道实体类型。

实际的问题是:是否可以在不破坏 WCF 和 ViewState 序列化的情况下使用属性自定义 JsonSerialization?

编辑: 像“那不可能”这样的答案会让我满意,因为我会停止尝试。

【问题讨论】:

    标签: c# asp.net ajax json serialization


    【解决方案1】:

    根据我的阅读,用于 ViewState 序列化的 LosFormatter 类会检查给定对象是否存在 TypeConverter 并使用它,因此您应该了解那里。

    This article 描述了如何创建自己的 JavaScriptConverter 来执行自定义序列化。您必须实现的 Serialize 方法返回 IDictionary<string, object>,因此您可能必须为您的 Entity 类而不是您的 IdType 结构创建一个 JavaScriptConverter 类。下面是一个例子,虽然我还没有机会测试它:

    注意:我帖子中的示例只是查找 IdType 的关联 TypeConverter 以便将其转换为字符串,但除非有特定原因这样做,否则您最好调用特定函数(例如覆盖ToString) 直接返回字符串表示,而不是像我的示例代码那样查找 TypeConverter。

    public class EntityJsonConverter : System.Web.Script.Serialization.JavaScriptConverter
    {
        public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
        {
            throw new NotImplementedException();
        }
    
        public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
        {
            if (obj == null)
                throw new ArgumentNullException("obj");
    
            Entity entity = obj as Entity;
            if (entity != null)
            {
                var values = new Dictionary<string, object>();
                TypeConverter idTypeConverter = TypeDescriptor.GetConverter(entity.Id);
                if (idTypeConverter != null)
                {
                    if (idTypeConverter.CanConvertTo(typeof(string)))
                        values.Add("Id", idTypeConverter.ConvertTo(entity.Id, typeof(string)));
                    else
                        throw new SerializationException(string.Format("The TypeConverter for type \"{0}\" cannot convert to string.", this.GetType().FullName));
                }
                else
                    throw new SerializationException(string.Format("Unable to find a TypeConverter for type \"{0}\".", this.GetType().FullName));
    
                values.Add("Data", serializer.Serialize(entity.Data));
    
                return values;
            }
            else
                throw new ArgumentException(string.Format("Expected argument of type \"{0}\", but received \"{1}\".", typeof(Entity).FullName, obj.GetType().FullName), "obj");
        }
    
        public override IEnumerable<Type> SupportedTypes
        {
            get { yield return typeof(Entity); }
        }
    }
    

    如果您还想要为 XML 序列化描述的行为,您可以让 IdType 结构实现 IXmlSerializable 接口。下面是一个使用为 IdType 结构定义的 TypeConverter 的 WriteXml 方法实现示例:

        void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer)
        {
            TypeConverter converter = TypeDescriptor.GetConverter(this);
            if (converter != null)
            {
                if (converter.CanConvertTo(typeof(string)))
                    writer.WriteString(converter.ConvertTo(this, typeof(string)) as string);
                else
                    throw new SerializationException(string.Format("The TypeConverter for type \"{0}\" cannot convert to string.", this.GetType().FullName));
            }
            else
                throw new SerializationException(string.Format("Unable to find a TypeConverter for type \"{0}\".", this.GetType().FullName));
        }
    

    【讨论】:

    • 这个 JavaScriptConverter 类型看起来不错。是否有一个属性告诉 JsonSerializer 使用自定义 JavaScriptConverter?
    • 我认为这没有属性,但请查看nayyeri.net/custom-json-serialization-in-asp-net-ajax 的文章。它展示了如何在配置文件中注册 JavaScriptConverter。不过,我还没有机会验证这些。
    【解决方案2】:

    另一个类似于为序列化创建代理类的解决方案是使用[NonSerialized()] 属性。

    IdType 可以是不可序列化的,并且可以将另一个可序列化的字符串属性实现为代理(这将 - 在获取或设置时 - 分配给 IdType/从 IdType 读取)。

    使用面向方面的编程,解决方案甚至可以看起来很优雅。

    【讨论】:

    • 当然!到目前为止,这是解决 json 部分的唯一解决方案,避免了序列化数据的控件必须在编译时知道类型。虽然我不喜欢我的数据实体上的额外公共字段。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多