Michael's

focus on architecture & hi-performance

用XmlSerializer序列化陷阱

实际上有点标题党了哈,但实际上这个bug从.net 2.0一直到现在都是存在的,而且m$也从来没有真正解决过,先看段测试代码

 

namespace TestMDA
{
    class Program
    {
        static void Main(string[] args)
        {
            People p = new People()
            {
                Age = 1,
                Name = "Michael"
            };

            AppDomain.CurrentDomain.AssemblyResolve += (sender, e) =>
                {
                    Console.WriteLine(e.Name);
                    return null;
                };

            using (FileStream fs = new FileStream("test.txt", FileMode.Create))
            {
                XmlSerializer xs = new XmlSerializer(typeof(People)); //throw MDA binding fail here
                xs.Serialize(fs, p);
            }

            Console.ReadLine();
        }
    }

    public class People
    {
        public int Age { get; set; }
        public string Name { get; set; }
    }
}

 

上面这段代码无论通过VS05抑或VS08编译之后,运行都会输出

 

TestMDA.XmlSerializers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
TestMDA.XmlSerializers

 

但是实际上序列化依然可以照常进行……

 

更诡异的事实是,如果修改相对应的namespace,例如 namespace ABC {…},就会输出

 

ABC.XmlSerializers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
ABC.XmlSerializers

 

----------------------- 分割线------------------------

 

为什么提到这个话题呢?我们现在进行着的一个项目中某些代码使用了XML序列化方式,随着程序的运行就会看到类似上面这种日志……苦思不得结果,找遍了引用程序集也没看到对应的dll或exe,想想既然无大碍就暂时没去深究,不过这几天刚好项目要做一个部署分发,在测试时刚好也发现类似问题,遂google之,发现2007年帖子一枚

https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=304095&wa=wsignin1.0

 

m$的说法是这个是by design的,不过直到现在.net 3.5也有这毛病,我也就不奢望啥了…

 

ps.当时应该是beta版本的VS,遇到这种情况会抛出异常,还好现在不会抛异常,但是也很郁闷 :)

posted on 2010-03-25 22:10 m.s 阅读(1422) 评论(8) 编辑 收藏

Feedback

#1楼 2010-03-25 22:39 Jeffrey Zhao      

我怎么就没有看懂……  回复 引用 查看   

#2楼 2010-03-25 22:52 木鱼      

我记得XML序列化是会生成临时程序集的.  回复 引用 查看   

#3楼[楼主] 2010-03-25 23:11 micYng      

引用木鱼:我记得XML序列化是会生成临时程序集的.


哪里可以看到临时程序集?  回复 引用 查看   

#4楼 2010-03-25 23:42 木鱼      

@micYng
临时程序集....好像是内存中吧,没仔细研究,有空研究一下
用Reflector可以看到生成过程的,临时程序集是以 System.Xml.Serialization.TempAssembly 为蓝本的.
 回复 引用 查看   

#5楼 2010-03-25 23:47       

运行都会输出 这个怎么解? 在console看到?

那么是因为微软在代码里面添加了Trace.Write()/ Debug.Write()???

既然没有抛exception,其他就是debug信息了。不知道为啥lz连这些都记录。

 回复 引用 查看   

#6楼 2010-03-26 07:04 eaglet      

下面是 XmlSerializer 的构造函数源代码,构造时确实会产生一个临时的程序集,而且这个临时程序集会被存放到一个静态的cache 数据结构中,下次再有相同的 defaultNamespace 则直接从cache 中取出程序集。

        /// <include file='doc\XmlSerializer.uex' path='docs/doc[@for="XmlSerializer.XmlSerializer6"]/*' /> 
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public XmlSerializer(Type type) : this(type, (string)null) { 
        }
 
        /// <include file='doc\XmlSerializer.uex' path='docs/doc[@for="XmlSerializer.XmlSerializer1"]/*' /> 
        /// <devdoc>
        ///    <para>[To be supplied.]</para> 
        /// </devdoc>
        public XmlSerializer(Type type, string defaultNamespace) {
            if (type == null)
                throw new ArgumentNullException("type"); 
            this.mapping = GetKnownMapping(type, defaultNamespace);
            if (this.mapping != null) { 
                this.primitiveType = type; 
                return;
            } 
            tempAssembly = cache[defaultNamespace, type];
            if (tempAssembly == null) {
                lock (cache) {
                    tempAssembly = cache[defaultNamespace, type]; 
                    if (tempAssembly == null) {
                        XmlSerializerImplementation contract; 
                        Assembly assembly = TempAssembly.LoadGeneratedAssembly(type, defaultNamespace, out contract); 
                        if (assembly == null) {
                            // need to reflect and generate new serialization assembly 
                            XmlReflectionImporter importer = new XmlReflectionImporter(defaultNamespace);
                            this.mapping = importer.ImportTypeMapping(type, null, defaultNamespace);
                            tempAssembly = GenerateTempAssembly(this.mapping, type, defaultNamespace);
                        } 
                        else {
                            // we found the pre-generated assembly, now make sure that the assembly has the right serializer 
                            // try to avoid the reflection step, need to get ElementName, namespace and the Key form the type 
                            this.mapping = XmlReflectionImporter.GetTopLevelMapping(type, defaultNamespace);
                            tempAssembly = new TempAssembly(new XmlMapping[] { this.mapping }, assembly, contract); 
                        }
                    }
                    cache.Add(defaultNamespace, type, tempAssembly);
                } 
            }
            if (mapping == null) { 
                mapping = XmlReflectionImporter.GetTopLevelMapping(type, defaultNamespace); 
            }
        } 

 回复 引用 查看   

#7楼 2010-03-26 11:18 cokkiy      

第一,没看懂;
第二,MS都说了是by design的,你还说是bug,难道你不知道by design的意思吗?
 回复 引用 查看   

#8楼[楼主] 2010-03-26 14:17 micYng      

引用cokkiy:
第一,没看懂;
第二,MS都说了是by design的,你还说是bug,难道你不知道by design的意思吗?


1.看不懂是因为你水平不行,建议你多写点代码再来喷
2.厄,我看过你写的e文邮件了,建议你再多学点英语  回复 引用 查看   

导航

统计信息

News

搜索

 
 

常用链接

我的标签

随笔分类

随笔档案

文章分类

相册

.Net Enterprise Library

.Net Remoting

ASP.NET

Blog Friends:)

C# category

C# forum&blogs

C# Toolkit

CodeSmith Usages

cPP related

Design Pattern

Opensource project

Pervious Blog

Useful tip

积分与排名

最新评论

阅读排行榜

评论排行榜

推荐排行榜