Ilungasoft Framework: 由Emit带来的序列化问题——IEntity的序列化支持范例[源码][04/08修正]
本文主要探讨关于Ilungasoft Framework中动态Entity的序列化问题。如果您之前也关注过Ilungasoft Framework,您一定会被其Entity定义格式的简单所吸引,用户只需要定义实体类的接口(框架提供生成工具)。不过,这样的使用上的简洁性,也就带来了实体类序列化时的部分限制。这里,Teddy将基于一个新的Sample,客观地讨论,使用.Net框架提供的默认序列化类序列化基于本框架的Entity的多种情形。关于Ilungasoft Framework的更多文章索引及版本更新,您可以访问:Ilungasoft Framework官方首页。
更正:本文最初的论述有一些错误,在双鱼座的指点下,只需将emit动态生成的程序集加载到AppDomain就能使Sample3中所有的序列化和反序列化正确运行!请注意下文中划去的文字和红色的更正文字。
下载
首先,您可以从这里下载最新版本的Ilungasoft Framework和全部示例的源码。本文所谈论的范例位于您下载的压缩包内的dist/Sample3目录。
最新的版本号为:v1.2 build 0407
Update:
1) Add a new Web Serial Number Validator Web Custom Control;
2) Add an Entity Serialize Helper Class SerializeHelper under Framework.Common;
3) Fix several little bugs.
示例
在列举示例代码之前,先列举在最新的版本中新增的一个类SerializeHelper.cs的代码,该类封装简化了常用的序列化方法,并且将在示例中被反复调用。
SerializeHelper.cs
 SerializeHelper Code
SerializeHelper Code
以上代码,比较简单,主要就是封装了XmlSerializer和SoapFormatter这两个类,最常用的操作,下面会结合示例进行说明。
下面就是我们的示例的代码:
Entities.cs
Default.aspx
 Default Page Html Code
Default Page Html Code
Default.aspx.cs
好了,代码就是这些,我来分析一下。首先,如果您已经下载,并在vs IDE中打开示例源码,请注意Default.aspx中的红色的按钮,红色表示按钮代表的使用方式会出错。
更正:经过代码更正,如果您下载的是v1.2.1 build 0408,那么Sample3中所有的序列化和反序列化方式都能正确运行。
让我们一个一个按钮来看:
1、Basic Single Entity和Basic Entity Array是两个最常用的功能,即使用XmlSerializer对单个的Entity实例或Entity[]数组进行序列化。这两个功能是完全正常的,推荐大家使用,自行运行示例程序查看生成的Xml。
2、Soap Single Entity和Soap Entity Array就开始有问题了。如果您运行示例,他会正常显示序列化后的结果。但是非常遗憾,反序列化将不能正常运行,因为我们的Entity,如这里的User,用户实际上只定义了interface,具体的User类,有框架在运行时通过Emit的方式生成,而SoapFormatter内部默认实现是在后台构造编译一个dll来处理反序列化的,他会试图在文件系统查找定义了Entity的程序集,但是很遗憾,这个程序集只存在内存中,不会在文件系统中,因此就会运行出错。
更正:经过代码更正,默认的Soap序列化完全能够正确执行了,因为将emit的动态程序集加入了AppDomain,反序列化时就不会有找不到动态程序集的问题了。
3、我们再来看看下一个倒霉鬼Complex Default Soap。
更正:Complex Default Soap也不再倒霉了,完全都能运行正常了!
首先,我们看看程序要序列化的对象UserAndGroup,Entities.cs Line32-37。它是一个包含了一个User和一个Group[]数组的复合类。如果使用,XmlSerializer来序列化,很遗憾,会失败,因为,XmlSerializer傻乎乎的只会判断声明的类型,他发现声明的类型如User是一个interface,所以就不允许序列化。如果具体的Entity类型可以直接访问,我们知道,可以通过为Field设置XmlElemenAtttribute属性类指定具体的Entity类型,但是很遗憾,这个类型我们只能通过Entityfactory<IEntityType>.GetDynamicEntityType()获得,但XmlElemenAtttribute只接受常量类型作为参数。
那么,SoapFormatter可不可以序列化呢?可以的!但是,就如之前的两个倒霉鬼一样,反序列化时会出错——找不到动态程序集。
4、现在剩下最后一个Complex Custom Soap了,同样是Soap,只要我们的组合类型UserAndGroup2实现ISerializable接口,那么SoapFormatter将不会调用其默认的序列化逻辑,转而调用自定义的序列化逻辑。请看Entities.cs Line 49-65. 注意,对于序列化和反序列化,分别由一个函数GetObjectData和一个包含同样参数列表的构造函数对应。也就是说,当序列化发生时,GetObjectData会被调用执行自定义的序列化,而反序列化时,构造函数被执行。SerializeHelper.LoadField等辅助函数用以简化自定义序列化过程,非常简单就不多解释了。
很幸运,通过这种方式,我们序列化和反序列化复合类UserAndGroup2的目的成功的达到了。
小结
讨论了这么久,我们有什么收获呢?
1、首先,确认了一点,Ilungasoft Framework下的Entity、Entity Array和复合类型,都可以进行序列化和反序列化,但是并不是所有.Net Framework提供的序列化方式都能支持。
2、要序列化对象,推荐调用SerializeHelper中定义的helper函数,参照范例。
3、如果类型基于Emit生成,那么注意,必须将emit动态生成的程序集加载到AppDomain,否则,.Net Framework中预定义的那些通过在后台动态编译的函数可能会不能正确运行。
4、功能实现中的任何便利,可能都会有代价,应注意取舍。
5、还有一点前面没提到的,SoapFormatter不支持泛型类型的的序列化,不知为什么微软不支持,还是当前版本没来得及加上。
补充:那么,文中更增了那么多,到底怎样将emit生成的动态程序集加载到AppDomain呢?
只需要这样:
好了,讨论就到这儿。欢迎各位,尤其是对序列化经验丰富的朋友多提提意见和建议,看看怎样进一步改进、简化本框架下的序列化支持。
Enjoy!
更正:本文最初的论述有一些错误,在双鱼座的指点下,只需将emit动态生成的程序集加载到AppDomain就能使Sample3中所有的序列化和反序列化正确运行!请注意下文中划去的文字和红色的更正文字。
下载
首先,您可以从这里下载最新版本的Ilungasoft Framework和全部示例的源码。本文所谈论的范例位于您下载的压缩包内的dist/Sample3目录。
最新的版本号为:v1.2 build 0407
Update:
1) Add a new Web Serial Number Validator Web Custom Control;
2) Add an Entity Serialize Helper Class SerializeHelper under Framework.Common;
3) Fix several little bugs.
示例
在列举示例代码之前,先列举在最新的版本中新增的一个类SerializeHelper.cs的代码,该类封装简化了常用的序列化方法,并且将在示例中被反复调用。
SerializeHelper.cs
 SerializeHelper Code
SerializeHelper Code以上代码,比较简单,主要就是封装了XmlSerializer和SoapFormatter这两个类,最常用的操作,下面会结合示例进行说明。
下面就是我们的示例的代码:
Entities.cs
 1 using System;
using System;
2 using System.Data;
using System.Data;
3 using System.Configuration;
using System.Configuration;
4 using System.Web;
using System.Web;
5 using System.Web.Security;
using System.Web.Security;
6 using System.Web.UI;
using System.Web.UI;
7 using System.Web.UI.WebControls;
using System.Web.UI.WebControls;
8 using System.Web.UI.WebControls.WebParts;
using System.Web.UI.WebControls.WebParts;
9 using System.Web.UI.HtmlControls;
using System.Web.UI.HtmlControls;
10 using System.Xml.Serialization;
using System.Xml.Serialization;
11 using System.Runtime.Serialization;
using System.Runtime.Serialization;
12 using Ilungasoft.Framework.Common;
using Ilungasoft.Framework.Common;
13 using System.Security.Permissions;
using System.Security.Permissions;
14
15 public interface Group : IEntity
public interface Group : IEntity
16 {
{
17 int ID { get; set; }
    int ID { get; set; }
18 string Title { get; set; }
    string Title { get; set; }
19 string Description { get; set; }
    string Description { get; set; }
20 System.DateTime CreateTime { get; set; }
    System.DateTime CreateTime { get; set; }
21 int ParentID { get; set; }
    int ParentID { get; set; }
22 }
}
23
24 public interface User : IEntity
public interface User : IEntity
25 {
{
26 int ID { get; set; }
    int ID { get; set; }
27 string Name { get; set; }
    string Name { get; set; }
28 bool Gender { get; set; }
    bool Gender { get; set; }
29 double Salary { get; set; }
    double Salary { get; set; }
30 }
}
31
32 [Serializable]
[Serializable]
33 public class UserAndGroup
public class UserAndGroup
34 {
{
35 public User SomeUser;
    public User SomeUser;
36 public Group[] SomeGroups;
    public Group[] SomeGroups;
37 }
}
38
39 [Serializable]
[Serializable]
40 public class UserAndGroup2 : ISerializable
public class UserAndGroup2 : ISerializable
41 {
{
42 public User SomeUser;
    public User SomeUser;
43 public Group[] SomeGroups;
    public Group[] SomeGroups;
44
45 public UserAndGroup2()
    public UserAndGroup2()
46 {
    {
47 }
    }
48
49 ISerializable Members
    ISerializable Members
66 }
}
 using System;
using System;2
 using System.Data;
using System.Data;3
 using System.Configuration;
using System.Configuration;4
 using System.Web;
using System.Web;5
 using System.Web.Security;
using System.Web.Security;6
 using System.Web.UI;
using System.Web.UI;7
 using System.Web.UI.WebControls;
using System.Web.UI.WebControls;8
 using System.Web.UI.WebControls.WebParts;
using System.Web.UI.WebControls.WebParts;9
 using System.Web.UI.HtmlControls;
using System.Web.UI.HtmlControls;10
 using System.Xml.Serialization;
using System.Xml.Serialization;11
 using System.Runtime.Serialization;
using System.Runtime.Serialization;12
 using Ilungasoft.Framework.Common;
using Ilungasoft.Framework.Common;13
 using System.Security.Permissions;
using System.Security.Permissions;14

15
 public interface Group : IEntity
public interface Group : IEntity16
 {
{17
 int ID { get; set; }
    int ID { get; set; }18
 string Title { get; set; }
    string Title { get; set; }19
 string Description { get; set; }
    string Description { get; set; }20
 System.DateTime CreateTime { get; set; }
    System.DateTime CreateTime { get; set; }21
 int ParentID { get; set; }
    int ParentID { get; set; }22
 }
}23

24
 public interface User : IEntity
public interface User : IEntity25
 {
{26
 int ID { get; set; }
    int ID { get; set; }27
 string Name { get; set; }
    string Name { get; set; }28
 bool Gender { get; set; }
    bool Gender { get; set; }29
 double Salary { get; set; }
    double Salary { get; set; }30
 }
}31

32
 [Serializable]
[Serializable]33
 public class UserAndGroup
public class UserAndGroup34
 {
{35
 public User SomeUser;
    public User SomeUser;36
 public Group[] SomeGroups;
    public Group[] SomeGroups;37
 }
}38

39
 [Serializable]
[Serializable]40
 public class UserAndGroup2 : ISerializable
public class UserAndGroup2 : ISerializable41
 {
{42
 public User SomeUser;
    public User SomeUser;43
 public Group[] SomeGroups;
    public Group[] SomeGroups;44

45
 public UserAndGroup2()
    public UserAndGroup2()46
 {
    {47
 }
    }48

49
 ISerializable Members
    ISerializable Members66
 }
}Default.aspx
 Default Page Html Code
Default Page Html CodeDefault.aspx.cs
 1 using System;
using System;
2 using System.Data;
using System.Data;
3 using System.Configuration;
using System.Configuration;
4 using System.Web;
using System.Web;
5 using System.Web.Security;
using System.Web.Security;
6 using System.Web.UI;
using System.Web.UI;
7 using System.Web.UI.WebControls;
using System.Web.UI.WebControls;
8 using System.Web.UI.WebControls.WebParts;
using System.Web.UI.WebControls.WebParts;
9 using System.Web.UI.HtmlControls;
using System.Web.UI.HtmlControls;
10 using Ilungasoft.Framework.Common;
using Ilungasoft.Framework.Common;
11
12 public partial class _Default : Ilungasoft.Framework.Web.UI.Page
public partial class _Default : Ilungasoft.Framework.Web.UI.Page 
13 {
{
14 private User user = null;
    private User user = null;
15 private Group group = null;
    private Group group = null;
16 private UserAndGroup userAndGroup;
    private UserAndGroup userAndGroup;
17 private UserAndGroup2 userAndGroup2;
    private UserAndGroup2 userAndGroup2;
18
19 protected void Page_Load(object sender, EventArgs e)
    protected void Page_Load(object sender, EventArgs e)
20 {
    {
21 if (!IsPostBack)
        if (!IsPostBack)
22 {
        {
23 SerialNumberValidator1.Create();
            SerialNumberValidator1.Create();
24 }
        }
25
26 user = EntityFactory<User>.CreateObject();
        user = EntityFactory<User>.CreateObject();
27 user.ID = 1;
        user.ID = 1;
28 user.Name = "teddy";
        user.Name = "teddy";
29 user.Salary = 1000;
        user.Salary = 1000;
30
31 group = EntityFactory<Group>.CreateObject();
        group = EntityFactory<Group>.CreateObject();
32 group.ID = 2;
        group.ID = 2;
33 group.Title = ".net group";
        group.Title = ".net group";
34
35 userAndGroup = new UserAndGroup();
        userAndGroup = new UserAndGroup();
36 userAndGroup.SomeUser = user;
        userAndGroup.SomeUser = user;
37 userAndGroup.SomeGroups = new Group[] { group, group, group };
        userAndGroup.SomeGroups = new Group[] { group, group, group };
38
39 userAndGroup2 = new UserAndGroup2();
        userAndGroup2 = new UserAndGroup2();
40 userAndGroup2.SomeUser = user;
        userAndGroup2.SomeUser = user;
41 userAndGroup2.SomeGroups = new Group[] { group, group, group };
        userAndGroup2.SomeGroups = new Group[] { group, group, group };
42 }
    }
43
44 protected void btnBasicSerializeEntity_Click(object sender, EventArgs e)
    protected void btnBasicSerializeEntity_Click(object sender, EventArgs e)
45 {
    {
46 TextBox1.Text = SerializeHelper.Serialize(user);
        TextBox1.Text = SerializeHelper.Serialize(user);
47 User _user = SerializeHelper.Deserialize<User>(EntityFactory<User>.GetDynamicEntityType(), TextBox1.Text);
        User _user = SerializeHelper.Deserialize<User>(EntityFactory<User>.GetDynamicEntityType(), TextBox1.Text);
48 }
    }
49 protected void btnBasicSerializeEntityArray_Click(object sender, EventArgs e)
    protected void btnBasicSerializeEntityArray_Click(object sender, EventArgs e)
50 {
    {
51 TextBox1.Text = SerializeHelper.SerializeArray(new User[] { user, user, user });
        TextBox1.Text = SerializeHelper.SerializeArray(new User[] { user, user, user });
52 User[] _users = SerializeHelper.Deserialize<User[]>(EntityFactory<User>.GetDynamicEntityType().MakeArrayType(), TextBox1.Text);
        User[] _users = SerializeHelper.Deserialize<User[]>(EntityFactory<User>.GetDynamicEntityType().MakeArrayType(), TextBox1.Text);
53 }
    }
54 protected void btnSoapSerializeEntity_Click(object sender, EventArgs e)
    protected void btnSoapSerializeEntity_Click(object sender, EventArgs e)
55 {
    {
56 TextBox1.Text = SerializeHelper.SoapSerialize(user);
        TextBox1.Text = SerializeHelper.SoapSerialize(user);
57 //error when deserialize
        //error when deserialize
58 //User _user = SerializeHelper.SoapDeserialize<User>(TextBox1.Text);
        //User _user = SerializeHelper.SoapDeserialize<User>(TextBox1.Text);
59 }
    }
60 protected void btnSoapSerializeEntityArray_Click(object sender, EventArgs e)
    protected void btnSoapSerializeEntityArray_Click(object sender, EventArgs e)
61 {
    {
62 TextBox1.Text = SerializeHelper.SoapSerialize(new User[] { user, user, user });
        TextBox1.Text = SerializeHelper.SoapSerialize(new User[] { user, user, user });
63 //error when deserialize
        //error when deserialize
64 //User[] _users = SerializeHelper.SoapDeserialize<User[]>(TextBox1.Text);
        //User[] _users = SerializeHelper.SoapDeserialize<User[]>(TextBox1.Text);
65 }
    }
66 protected void btnComplexSoapDefault_Click(object sender, EventArgs e)
    protected void btnComplexSoapDefault_Click(object sender, EventArgs e)
67 {
    {
68 TextBox1.Text = SerializeHelper.SoapSerialize(userAndGroup);
        TextBox1.Text = SerializeHelper.SoapSerialize(userAndGroup);
69 //error when deserialize
        //error when deserialize
70 //UserAndGroup _userAndGroup = SerializeHelper.SoapDeserialize<UserAndGroup>(TextBox1.Text);
        //UserAndGroup _userAndGroup = SerializeHelper.SoapDeserialize<UserAndGroup>(TextBox1.Text);
71 }
    }
72 protected void btnComplexSoapCustom_Click(object sender, EventArgs e)
    protected void btnComplexSoapCustom_Click(object sender, EventArgs e)
73 {
    {
74 TextBox1.Text = SerializeHelper.SoapSerialize(userAndGroup2);
        TextBox1.Text = SerializeHelper.SoapSerialize(userAndGroup2);
75 UserAndGroup2 _userAndGroup2 = SerializeHelper.SoapDeserialize<UserAndGroup2>(TextBox1.Text);
        UserAndGroup2 _userAndGroup2 = SerializeHelper.SoapDeserialize<UserAndGroup2>(TextBox1.Text);
76 }
    }
77 protected void btnCheckSerialNumber_Click(object sender, EventArgs e)
    protected void btnCheckSerialNumber_Click(object sender, EventArgs e)
78 {
    {
79 if (SerialNumberValidator1.CheckSN(TextBox2.Text))
        if (SerialNumberValidator1.CheckSN(TextBox2.Text))
80 {
        {
81 Response.Write(ClientScriptFactory.WrapScriptTag(ClientScriptFactory.PopAlert("Serial Number Correct!")));
            Response.Write(ClientScriptFactory.WrapScriptTag(ClientScriptFactory.PopAlert("Serial Number Correct!")));
82 }
        }
83 else
        else
84 {
        {
85 Response.Write(ClientScriptFactory.WrapScriptTag(ClientScriptFactory.PopAlert("Serial Number Error!")));
            Response.Write(ClientScriptFactory.WrapScriptTag(ClientScriptFactory.PopAlert("Serial Number Error!")));
86 }
        }
87 }
    }
88 }
}
 using System;
using System;2
 using System.Data;
using System.Data;3
 using System.Configuration;
using System.Configuration;4
 using System.Web;
using System.Web;5
 using System.Web.Security;
using System.Web.Security;6
 using System.Web.UI;
using System.Web.UI;7
 using System.Web.UI.WebControls;
using System.Web.UI.WebControls;8
 using System.Web.UI.WebControls.WebParts;
using System.Web.UI.WebControls.WebParts;9
 using System.Web.UI.HtmlControls;
using System.Web.UI.HtmlControls;10
 using Ilungasoft.Framework.Common;
using Ilungasoft.Framework.Common;11

12
 public partial class _Default : Ilungasoft.Framework.Web.UI.Page
public partial class _Default : Ilungasoft.Framework.Web.UI.Page 13
 {
{14
 private User user = null;
    private User user = null;15
 private Group group = null;
    private Group group = null;16
 private UserAndGroup userAndGroup;
    private UserAndGroup userAndGroup;17
 private UserAndGroup2 userAndGroup2;
    private UserAndGroup2 userAndGroup2;18

19
 protected void Page_Load(object sender, EventArgs e)
    protected void Page_Load(object sender, EventArgs e)20
 {
    {21
 if (!IsPostBack)
        if (!IsPostBack)22
 {
        {23
 SerialNumberValidator1.Create();
            SerialNumberValidator1.Create();24
 }
        }25

26
 user = EntityFactory<User>.CreateObject();
        user = EntityFactory<User>.CreateObject();27
 user.ID = 1;
        user.ID = 1;28
 user.Name = "teddy";
        user.Name = "teddy";29
 user.Salary = 1000;
        user.Salary = 1000;30

31
 group = EntityFactory<Group>.CreateObject();
        group = EntityFactory<Group>.CreateObject();32
 group.ID = 2;
        group.ID = 2;33
 group.Title = ".net group";
        group.Title = ".net group";34

35
 userAndGroup = new UserAndGroup();
        userAndGroup = new UserAndGroup();36
 userAndGroup.SomeUser = user;
        userAndGroup.SomeUser = user;37
 userAndGroup.SomeGroups = new Group[] { group, group, group };
        userAndGroup.SomeGroups = new Group[] { group, group, group };38

39
 userAndGroup2 = new UserAndGroup2();
        userAndGroup2 = new UserAndGroup2();40
 userAndGroup2.SomeUser = user;
        userAndGroup2.SomeUser = user;41
 userAndGroup2.SomeGroups = new Group[] { group, group, group };
        userAndGroup2.SomeGroups = new Group[] { group, group, group };42
 }
    }43

44
 protected void btnBasicSerializeEntity_Click(object sender, EventArgs e)
    protected void btnBasicSerializeEntity_Click(object sender, EventArgs e)45
 {
    {46
 TextBox1.Text = SerializeHelper.Serialize(user);
        TextBox1.Text = SerializeHelper.Serialize(user);47
 User _user = SerializeHelper.Deserialize<User>(EntityFactory<User>.GetDynamicEntityType(), TextBox1.Text);
        User _user = SerializeHelper.Deserialize<User>(EntityFactory<User>.GetDynamicEntityType(), TextBox1.Text);48
 }
    }49
 protected void btnBasicSerializeEntityArray_Click(object sender, EventArgs e)
    protected void btnBasicSerializeEntityArray_Click(object sender, EventArgs e)50
 {
    {51
 TextBox1.Text = SerializeHelper.SerializeArray(new User[] { user, user, user });
        TextBox1.Text = SerializeHelper.SerializeArray(new User[] { user, user, user });52
 User[] _users = SerializeHelper.Deserialize<User[]>(EntityFactory<User>.GetDynamicEntityType().MakeArrayType(), TextBox1.Text);
        User[] _users = SerializeHelper.Deserialize<User[]>(EntityFactory<User>.GetDynamicEntityType().MakeArrayType(), TextBox1.Text);53
 }
    }54
 protected void btnSoapSerializeEntity_Click(object sender, EventArgs e)
    protected void btnSoapSerializeEntity_Click(object sender, EventArgs e)55
 {
    {56
 TextBox1.Text = SerializeHelper.SoapSerialize(user);
        TextBox1.Text = SerializeHelper.SoapSerialize(user);57
 //error when deserialize
        //error when deserialize58
 //User _user = SerializeHelper.SoapDeserialize<User>(TextBox1.Text);
        //User _user = SerializeHelper.SoapDeserialize<User>(TextBox1.Text);59
 }
    }60
 protected void btnSoapSerializeEntityArray_Click(object sender, EventArgs e)
    protected void btnSoapSerializeEntityArray_Click(object sender, EventArgs e)61
 {
    {62
 TextBox1.Text = SerializeHelper.SoapSerialize(new User[] { user, user, user });
        TextBox1.Text = SerializeHelper.SoapSerialize(new User[] { user, user, user });63
 //error when deserialize
        //error when deserialize64
 //User[] _users = SerializeHelper.SoapDeserialize<User[]>(TextBox1.Text);
        //User[] _users = SerializeHelper.SoapDeserialize<User[]>(TextBox1.Text);65
 }
    }66
 protected void btnComplexSoapDefault_Click(object sender, EventArgs e)
    protected void btnComplexSoapDefault_Click(object sender, EventArgs e)67
 {
    {68
 TextBox1.Text = SerializeHelper.SoapSerialize(userAndGroup);
        TextBox1.Text = SerializeHelper.SoapSerialize(userAndGroup);69
 //error when deserialize
        //error when deserialize70
 //UserAndGroup _userAndGroup = SerializeHelper.SoapDeserialize<UserAndGroup>(TextBox1.Text);
        //UserAndGroup _userAndGroup = SerializeHelper.SoapDeserialize<UserAndGroup>(TextBox1.Text);71
 }
    }72
 protected void btnComplexSoapCustom_Click(object sender, EventArgs e)
    protected void btnComplexSoapCustom_Click(object sender, EventArgs e)73
 {
    {74
 TextBox1.Text = SerializeHelper.SoapSerialize(userAndGroup2);
        TextBox1.Text = SerializeHelper.SoapSerialize(userAndGroup2);75
 UserAndGroup2 _userAndGroup2 = SerializeHelper.SoapDeserialize<UserAndGroup2>(TextBox1.Text);
        UserAndGroup2 _userAndGroup2 = SerializeHelper.SoapDeserialize<UserAndGroup2>(TextBox1.Text);76
 }
    }77
 protected void btnCheckSerialNumber_Click(object sender, EventArgs e)
    protected void btnCheckSerialNumber_Click(object sender, EventArgs e)78
 {
    {79
 if (SerialNumberValidator1.CheckSN(TextBox2.Text))
        if (SerialNumberValidator1.CheckSN(TextBox2.Text))80
 {
        {81
 Response.Write(ClientScriptFactory.WrapScriptTag(ClientScriptFactory.PopAlert("Serial Number Correct!")));
            Response.Write(ClientScriptFactory.WrapScriptTag(ClientScriptFactory.PopAlert("Serial Number Correct!")));82
 }
        }83
 else
        else84
 {
        {85
 Response.Write(ClientScriptFactory.WrapScriptTag(ClientScriptFactory.PopAlert("Serial Number Error!")));
            Response.Write(ClientScriptFactory.WrapScriptTag(ClientScriptFactory.PopAlert("Serial Number Error!")));86
 }
        }87
 }
    }88
 }
}好了,代码就是这些,我来分析一下。
更正:经过代码更正,如果您下载的是v1.2.1 build 0408,那么Sample3中所有的序列化和反序列化方式都能正确运行。
让我们一个一个按钮来看:
1、Basic Single Entity和Basic Entity Array是两个最常用的功能,即使用XmlSerializer对单个的Entity实例或Entity[]数组进行序列化。这两个功能是完全正常的,推荐大家使用,自行运行示例程序查看生成的Xml。
2、
更正:经过代码更正,默认的Soap序列化完全能够正确执行了,因为将emit的动态程序集加入了AppDomain,反序列化时就不会有找不到动态程序集的问题了。
3、
更正:Complex Default Soap也不再倒霉了,完全都能运行正常了!
首先,我们看看程序要序列化的对象UserAndGroup,Entities.cs Line32-37。它是一个包含了一个User和一个Group[]数组的复合类。如果使用,XmlSerializer来序列化,很遗憾,会失败,因为,XmlSerializer傻乎乎的只会判断声明的类型,他发现声明的类型如User是一个interface,所以就不允许序列化。如果具体的Entity类型可以直接访问,我们知道,可以通过为Field设置XmlElemenAtttribute属性类指定具体的Entity类型,但是很遗憾,这个类型我们只能通过Entityfactory<IEntityType>.GetDynamicEntityType()获得,但XmlElemenAtttribute只接受常量类型作为参数。
那么,SoapFormatter可不可以序列化呢?可以的!
4、现在剩下最后一个Complex Custom Soap了,同样是Soap,只要我们的组合类型UserAndGroup2实现ISerializable接口,那么SoapFormatter将不会调用其默认的序列化逻辑,转而调用自定义的序列化逻辑。请看Entities.cs Line 49-65. 注意,对于序列化和反序列化,分别由一个函数GetObjectData和一个包含同样参数列表的构造函数对应。也就是说,当序列化发生时,GetObjectData会被调用执行自定义的序列化,而反序列化时,构造函数被执行。SerializeHelper.LoadField等辅助函数用以简化自定义序列化过程,非常简单就不多解释了。
很幸运,通过这种方式,我们序列化和反序列化复合类UserAndGroup2的目的成功的达到了。
小结
讨论了这么久,我们有什么收获呢?
1、首先,确认了一点,Ilungasoft Framework下的Entity、Entity Array和复合类型,都可以进行序列化和反序列化,但是并不是所有.Net Framework提供的序列化方式都能支持。
2、要序列化对象,推荐调用SerializeHelper中定义的helper函数,参照范例。
3、如果类型基于Emit生成,那么注意,必须将emit动态生成的程序集加载到AppDomain,否则,.Net Framework中预定义的那些通过在后台动态编译的函数可能会不能正确运行。
4、功能实现中的任何便利,可能都会有代价,应注意取舍。
5、还有一点前面没提到的,SoapFormatter不支持泛型类型的的序列化,不知为什么微软不支持,还是当前版本没来得及加上。
补充:那么,文中更增了那么多,到底怎样将emit生成的动态程序集加载到AppDomain呢?
只需要这样:
 1 private static ResolveEventHandler _ResolveEventHandler = null;
        private static ResolveEventHandler _ResolveEventHandler = null;
2
3 private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
        private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
4 {
        {
5 return assBuilder;
            return assBuilder;
6 }
        }
7
8 //
//
9
10 //create dynamic IEntityType Assembly & Type through Emit
            //create dynamic IEntityType Assembly & Type through Emit
11 if (assBuilder == null)
            if (assBuilder == null)
12 {
            {
13 AssemblyName assName = new AssemblyName();
                AssemblyName assName = new AssemblyName();
14 assName.Name = DYNAMIC_ENTITY_NAMESPACE;
                assName.Name = DYNAMIC_ENTITY_NAMESPACE;
15 assBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assName, AssemblyBuilderAccess.Run);
                assBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assName, AssemblyBuilderAccess.Run);
16
17 if (_ResolveEventHandler == null)
                if (_ResolveEventHandler == null)
18 {
                {
19 _ResolveEventHandler = new ResolveEventHandler(CurrentDomain_AssemblyResolve);
                    _ResolveEventHandler = new ResolveEventHandler(CurrentDomain_AssemblyResolve);
20 AppDomain.CurrentDomain.AssemblyResolve += _ResolveEventHandler;
                    AppDomain.CurrentDomain.AssemblyResolve += _ResolveEventHandler;
21 }
                }
22 }
            }
23
24 //
//
 private static ResolveEventHandler _ResolveEventHandler = null;
        private static ResolveEventHandler _ResolveEventHandler = null;2

3
 private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
        private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)4
 {
        {5
 return assBuilder;
            return assBuilder;6
 }
        }7

8
 //
//
9

10
 //create dynamic IEntityType Assembly & Type through Emit
            //create dynamic IEntityType Assembly & Type through Emit11
 if (assBuilder == null)
            if (assBuilder == null)12
 {
            {13
 AssemblyName assName = new AssemblyName();
                AssemblyName assName = new AssemblyName();14
 assName.Name = DYNAMIC_ENTITY_NAMESPACE;
                assName.Name = DYNAMIC_ENTITY_NAMESPACE;15
 assBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assName, AssemblyBuilderAccess.Run);
                assBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assName, AssemblyBuilderAccess.Run);16

17
 if (_ResolveEventHandler == null)
                if (_ResolveEventHandler == null)18
 {
                {19
 _ResolveEventHandler = new ResolveEventHandler(CurrentDomain_AssemblyResolve);
                    _ResolveEventHandler = new ResolveEventHandler(CurrentDomain_AssemblyResolve);20
 AppDomain.CurrentDomain.AssemblyResolve += _ResolveEventHandler;
                    AppDomain.CurrentDomain.AssemblyResolve += _ResolveEventHandler;21
 }
                }22
 }
            }23

24
 //
//
好了,讨论就到这儿。欢迎各位,尤其是对序列化经验丰富的朋友多提提意见和建议,看看怎样进一步改进、简化本框架下的序列化支持。
Enjoy!
 
                     
                    
                 
                    
                
 
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号