如果进程环境太大,如何避免XmlSerializer失败?

发布于 2024-09-12 14:10:14 字数 2668 浏览 2 评论 0原文

上周我遇到了一个奇怪的问题。对 new XMLSerializer(typeof(MyType)) 的调用因外部异常而崩溃,告诉我 csc.exe 无法执行。 经过一番调查后,我发现只有当进程环境大小达到“临界”限制时才会发生此异常。我创建了一个小示例应用程序来验证这个原因。

namespace EnvironmentTester
{
    public class Program
    {
        private static void Main(string[] args)
        {
            FillProcessEnvironmentBlock(false);
            SerializeDataObject();
        }

        private static void SerializeDataObject()
        {
            var dto = new DataObject {Name = "MyDto"};

            try
            {
                var xmlSerializer = new XmlSerializer(dto.GetType()); // throws exception
                xmlSerializer.Serialize(TextWriter.Null, dto);

                Console.WriteLine("No exception occured.");
            }
            catch(Exception e)
            {
                Console.WriteLine("Exception occured : " + e.GetType());
            }

            Console.ReadKey();
        }

        private static void FillProcessEnvironmentBlock(bool fillToMax)
        {
            var currentEnvVarIndex = 0;
            var environmentSize = GetEnvironmentSize();

            int criticalEnvironmentSize = fillToMax ? 30692 : 30691;

            while (environmentSize < criticalEnvironmentSize)
            {
                var envVarName = "Env" + currentEnvVarIndex;
                var envVarValueLength = (criticalEnvironmentSize - environmentSize - envVarName.Length - 2) % 32000;
                Environment.SetEnvironmentVariable(envVarName, new string('a', envVarValueLength));
                currentEnvVarIndex++;
                environmentSize = GetEnvironmentSize();
            }
        }

        private static int GetEnvironmentSize()
        {
            var envVars = Environment.GetEnvironmentVariables();
            int environmentSize = 0;


            foreach (string envKey in envVars.Keys)
            {
                environmentSize += envKey.Length;
            }

            foreach (string envVar in envVars.Values)
            {
                environmentSize += envVar.Length;
            }

            environmentSize += 2*envVars.Keys.Count; // add the '=' and the '\0'

            return environmentSize;
        }

        public class DataObject
        {
            [XmlAttribute("ObjectName")]
            public string Name { get; set; }
        }
    }
}

如果使用参数 false 调用 FillProcessEnvironmentBlock ,则未达到临界大小,如果使用 true 调用,则会抛出ExternalException。我在两台不同的WindowsXP 32位SP2机器上进行了测试,结果相同。

我知道调用 csc.exe 来创建用于读/写 xml 文件的临时程序集。但不知道为什么进程环境太大的话csc.exe的调用会失败。

有谁知道这个异常的原因?我该如何解决这个问题(如果我不想编写自己的 xml 序列化)?是否存在因流程环境太大而导致的其他已知问题?

I ran into a strange problem last week. A call to new XMLSerializer(typeof(MyType)) crashed with an ExternalException, telling me that csc.exe could not be executed.
After some investigation I found that this exception only occurs if the process environment size reaches a "critical" limit. I created a little sample application to verify that reason.

namespace EnvironmentTester
{
    public class Program
    {
        private static void Main(string[] args)
        {
            FillProcessEnvironmentBlock(false);
            SerializeDataObject();
        }

        private static void SerializeDataObject()
        {
            var dto = new DataObject {Name = "MyDto"};

            try
            {
                var xmlSerializer = new XmlSerializer(dto.GetType()); // throws exception
                xmlSerializer.Serialize(TextWriter.Null, dto);

                Console.WriteLine("No exception occured.");
            }
            catch(Exception e)
            {
                Console.WriteLine("Exception occured : " + e.GetType());
            }

            Console.ReadKey();
        }

        private static void FillProcessEnvironmentBlock(bool fillToMax)
        {
            var currentEnvVarIndex = 0;
            var environmentSize = GetEnvironmentSize();

            int criticalEnvironmentSize = fillToMax ? 30692 : 30691;

            while (environmentSize < criticalEnvironmentSize)
            {
                var envVarName = "Env" + currentEnvVarIndex;
                var envVarValueLength = (criticalEnvironmentSize - environmentSize - envVarName.Length - 2) % 32000;
                Environment.SetEnvironmentVariable(envVarName, new string('a', envVarValueLength));
                currentEnvVarIndex++;
                environmentSize = GetEnvironmentSize();
            }
        }

        private static int GetEnvironmentSize()
        {
            var envVars = Environment.GetEnvironmentVariables();
            int environmentSize = 0;


            foreach (string envKey in envVars.Keys)
            {
                environmentSize += envKey.Length;
            }

            foreach (string envVar in envVars.Values)
            {
                environmentSize += envVar.Length;
            }

            environmentSize += 2*envVars.Keys.Count; // add the '=' and the '\0'

            return environmentSize;
        }

        public class DataObject
        {
            [XmlAttribute("ObjectName")]
            public string Name { get; set; }
        }
    }
}

If FillProcessEnvironmentBlock is called with parameter false, the critical size is not reached, if it's called with true, the ExternalException is thrown. I tested it on two different WindowsXP 32bit SP2 machines, with the same result.

I know that csc.exe is called to create a temporary assembly used to read/write the xml file. But I don't know why the call to csc.exe fails if the process environment is too large.

Does anyone know the reason for this exception? And how can I work around it (if I don't want to write my own xml serialization)? Are there any other known problems causeed by a process environment that's too large?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

潇烟暮雨 2024-09-19 14:10:14

您可以使用 Sgen 工具或 MSBuild 预编译序列化程序Sgen 任务

You can precompile serializers using Sgen tool or MSBuild Sgen task

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文