4

情况如下:

Silverlight 3 应用程序访问 asp.net 托管的 WCF 服务以获取要在网格中显示的项目列表。一旦列表被带到客户端,它就会被缓存在 IsolatedStorage 中。这是通过使用 DataContractSerializer 将所有这些对象序列化为一个流来完成的,该流然后被压缩然后加密。当应用程序重新启动时,它首先从缓存中加载(颠倒上述过程)并使用 DataContractSerializer.ReadObject() 方法反序列化对象。直到最近,所有这些在所有情况下都运行良好,整个“从缓存加载”路径(解密/解压缩/反序列化)最多需要数百毫秒。

在一些开发机器上,但不是所有机器(所有机器 Windows 7)上,反序列化过程 - 即对 ReadObject(stream) 的调用需要几分钟,似乎锁定了整个机器,但只有在 VS2008 的调试器中运行时。在调试器之外运行 Debug 配置代码没有问题。

看起来可疑的一件事是,当您打开异常停止时,您可以看到 ReadObject() 抛出许多 System.FormatException,表明数字格式不正确。当我关闭“只是我的代码”时,成千上万的代码会被转储到屏幕上。没有一个是未经处理的。这些都发生在从缓存中读回和在 Web 服务调用结束时反序列化以从 WCF 服务获取数据时。但是,这些相同的异常发生在我的笔记本电脑开发机器上,它根本没有遇到缓慢的问题。FWIW,我的笔记本电脑真的很旧,我的台式机是 4 核、6GB RAM 的野兽。

同样,除非在 VS2008 的调试器下运行,否则没有问题。其他人好像这个?有什么想法吗?

这是错误报告链接:https ://connect.microsoft.com/VisualStudio/feedback/details/539609/very-slow-performance-deserializing-using-datacontractserializer-in-a-silverlight-application-only-in-debugger

编辑:我现在知道 FormatExceptions 来自哪里。似乎它们是“设计使然” - 当我有双打被序列化时,它们会发生 double.NaN 以便 xml 看起来像 NaN ...似乎 DCS 试图将值解析为数字,但失败了有一个例外,然后它会寻找“NaN”等。人。并处理它们。我的问题不是这不起作用......它确实......只是它完全削弱了调试器。有谁知道如何配置调试器/vs2008sp1 以更有效地处理这个问题。

4

5 回答 5

2

卡登,

您可能需要考虑改用 XMLSerializer。这是我随着时间的推移确定的:

XMLSerializer 和 DataContractSerializer 类提供了一种将对象图序列化和反序列化到 XML 和从 XML 反序列化的简单方法。

主要区别在于:
1.
如果您使用 [XmlAttribute] 而不是 [XmlElement],XMLSerializer 的有效负载比 DCS 小得多
DCS 始终将值存储为元素
2.
DCS 是“选择加入”而不是“选择退出”
使用 DCS,您使用 [DataMember] 显式标记要序列化的内容
使用 DCS,您可以序列化任何字段或属性,即使它们被标记为受保护或私有
使用 DCS,您可以使用 [IgnoreDataMember] 让序列化程序忽略某些属性
使用 XMLSerializer 对公共属性进行序列化,并且需要对设置器进行反序列化
使用 XmlSerializer 您可以使用 [XmlIgnore] 让序列化程序忽略公共属性
3.请
注意!DCS.ReadObject 在反序列化期间不调用构造函数 如果
您需要执行初始化,DCS 支持以下回调挂钩:
[OnDeserializing]、[OnDeserialized]、[OnSerializing]、[OnSerialized]
(也可用于处理版本控制问题)

能够在两个序列化程序之间切换,您可以同时使用两组属性,如下所示:

[DataContract]
[XmlRoot]
    public class ProfilePerson : NotifyPropertyChanges
    {
[XmlAttribute]
[DataMember]
        public string FirstName { get { return m_FirstName; } set { SetProperty(ref m_FirstName, value); } }
        private string m_FirstName;
[XmlElement]
[DataMember]
        public PersonLocation Location { get { return m_Location; } set { SetProperty(ref m_Location, value); } }
        private PersonLocation m_Location = new PersonLocation(); // Should change over time
[XmlIgnore]
[IgnoreDataMember]
        public Profile ParentProfile { get { return m_ParentProfile; } set { SetProperty(ref m_ParentProfile, value); } }
        private Profile m_ParentProfile = null;

        public ProfilePerson()
        {
        }
    }

另外,查看我的可以在两者之间切换的 Serializer 类:

using System;
using System.IO;
using System.Runtime.Serialization;
using System.Text;
using System.Xml;
using System.Xml.Serialization;

namespace ClassLibrary
{
    // Instantiate this class to serialize objects using either XmlSerializer or DataContractSerializer
    internal class Serializer
    {
        private readonly bool m_bDCS;

        internal Serializer(bool bDCS)
        {
            m_bDCS = bDCS;
        }

        internal TT Deserialize<TT>(string input)
        {
            MemoryStream stream = new MemoryStream(input.ToByteArray());
            if (m_bDCS)
            {
                DataContractSerializer dc = new DataContractSerializer(typeof(TT));
                return (TT)dc.ReadObject(stream);
            }
            else
            {
                XmlSerializer xs = new XmlSerializer(typeof(TT));
                return (TT)xs.Deserialize(stream);
            }
        }

        internal string Serialize<TT>(object obj)
        {
            MemoryStream stream = new MemoryStream();
            if (m_bDCS)
            {
                DataContractSerializer dc = new DataContractSerializer(typeof(TT));
                dc.WriteObject(stream, obj);
            }
            else
            {
                XmlSerializer xs = new XmlSerializer(typeof(TT));
                xs.Serialize(stream, obj);
            }

            // be aware that the Unicode Byte-Order Mark will be at the front of the string
            return stream.ToArray().ToUtfString();
        }

        internal string SerializeToString<TT>(object obj)
        {
            StringBuilder builder = new StringBuilder();
            XmlWriter xmlWriter = XmlWriter.Create(builder);
            if (m_bDCS)
            {
                DataContractSerializer dc = new DataContractSerializer(typeof(TT));
                dc.WriteObject(xmlWriter, obj);
            }
            else
            {
                XmlSerializer xs = new XmlSerializer(typeof(TT));
                xs.Serialize(xmlWriter, obj);
            }

            string xml = builder.ToString();
            xml = RegexHelper.ReplacePattern(xml, RegexHelper.WildcardToPattern("<?xml*>", WildcardSearch.Anywhere), string.Empty);
            xml = RegexHelper.ReplacePattern(xml, RegexHelper.WildcardToPattern(" xmlns:*\"*\"", WildcardSearch.Anywhere), string.Empty);
            xml = xml.Replace(Environment.NewLine + "  ", string.Empty);
            xml = xml.Replace(Environment.NewLine, string.Empty);
            return xml;
        }
    }
}
于 2010-03-08T05:48:57.103 回答
1

这是一个猜测,但我认为它在调试模式下运行缓慢,因为对于每个异常,它都会执行一些操作以在调试窗口中显示异常等。如果您在发布模式下运行,则不会执行这些额外步骤.

我从来没有这样做过,所以我真的不知道它会起作用,但是您是否尝试过将一个程序集设置为在发布模式下运行,而所有其他程序集都设置为调试?如果我是对的,它可能会解决你的问题。如果我错了,那么你只会浪费 1 或 2 分钟。

于 2010-03-16T15:42:22.437 回答
1

关于您的调试问题,您是否尝试过禁用异常助手?(工具 > 选项 > 调试 > 启用异常助手)。

另一点应该是 Debug > Exceptions 中的异常处理:您可以禁用 CLR 的用户未处理的东西,或者只取消选中 System.FormatException 异常。

于 2010-03-16T16:05:24.960 回答
1

好的 - 我找到了根本问题。这就是我在编辑中提到的主要问题。问题是在 xml 中,它正确地序列化了具有 double.NaN 值的双精度数。当分母为 0D 时,我使用这些值来表示“na”。示例:当平均权益为 0D 时,ROE(权益回报率 = 净收入 / 平均权益)将被序列化为:

<ROE>NaN</ROE> 

当 DCS 尝试对其进行反序列化时,显然它首先尝试读取数字,然后在失败时捕获异常,然后处理 NaN。问题是在调试模式下这似乎会产生很多开销。

解决方法:我把属性改成double了?并将其设置为 null 而不是 NaN。现在一切都在 DEBUG 模式下立即发生。感谢大家的帮助。

于 2010-03-17T05:13:11.730 回答
0

尝试禁用一些 IE 插件。就我而言,LastPass 工具栏杀死了我的 Silverlight 调试。每次在断点后与 Visual Studio 交互时,我的计算机都会冻结几分钟。

于 2011-11-03T14:29:08.883 回答