前面在《Asp.Net Forums中对.Net中序列化和反序列化的应用》一文中讲了,对于一些扩展属性,可以将字符串集合序列化为二进制,也可以从二进制反序列化为字符串集合。其实我一直有个疑问,对于asp.net中可以很容易实现,但是在asp中该如何?
在CS和DNN3中都采用了asp.net2.0的新特性MemberShip,今天研究了一下CSBeta2,特地研究了一下MemberShip中对于用户资料的序列化保存。发现在aspnet_Profile表中有三个特殊字段PropertyNames、 PropertyValuesString和PropertyValuesBinary,其中的PropertyValuesBinary十之八九就是保存序列化为二进制后的内容。对于PropertyNames、PropertyValuesString这两个字段倒是不知道,打开查看,发现其中一条记录这两个字段的内容分别为下面两行的内容:
publicEmail:S:0:0:yahooIM:S:0:0:timezone:S:0:1:birthdate:B:0:-1:gender:S:1:6:location:S:7:0:fontsize:S:7:1:signature:S:8:0:dateFormat:S:8:10:webLog:S:18:7:enablePostPreviewPopup:B:0:-1:language:S:25:5:interests:S:30:0:occupation:S:30:0:webAddress:S:30:7:icqIM:S:37:0:aolIM:S:37:0:signatureFormatted:S:37:0:msnIM:S:37:0:
8NotSet0MM-dd-yyyyhttp://zh-CNhttp://
借助Reflector分析了一下源码,终于明白了,原来在PropertyNames字段中,由“:”分割为若干个数组,其中每个属性占数组的4项(如publicEmail:S:0:0:为一个属性的整体):
第1项为属性名称
第2项有两种可能值,B表示该属性值为null,S表示不为null
第3项表示在PropertyValuesString字段中字符串的起始位置
第4项表示长度
那么publicEmail:S:0:0:就表示为空值,timezone:S:0:1:表示“8NotSet0MM-dd-yyyyhttp://zh- CNhttp://“中从0开始取1个字符长度为“8”,birthdate:B:0:-1:就表示为null,dateFormat:S:8:10:就表示取“8NotSet0MM-dd-yyyyhttp://zh-CNhttp://”中第8位开始取10个字符为“MM-dd-yyyy”……
通过这种序列化为字符串的方式,即使是一些弱语言,如vbscript,jscript都可以实现序列化和反序列化了,那么在asp中也就可以共享asp.net的MemberShip了。
贴两段核心代码参考一下:
{
StringBuilder builder1 = new StringBuilder();
StringBuilder builder2 = new StringBuilder();
MemoryStream stream1 = binarySupported ? new MemoryStream() : null;
try
{
bool flag1 = false;
foreach (SettingsPropertyValue value1 in properties)
{
if (!value1.IsDirty)
{
continue;
}
if (userIsAuthenticated || ((bool) value1.Property.Attributes["AllowAnonymous"]))
{
flag1 = true;
break;
}
}
if (!flag1)
{
return;
}
foreach (SettingsPropertyValue value2 in properties)
{
if (!userIsAuthenticated && !((bool) value2.Property.Attributes["AllowAnonymous"]))
{
continue;
}
if (value2.IsDirty || !value2.UsingDefaultValue)
{
int num1 = 0;
int num2 = 0;
string text1 = null;
if (value2.Deserialized && (value2.PropertyValue == null))
{
num1 = -1;
}
else
{
object obj1 = value2.SerializedValue;
if (obj1 == null)
{
num1 = -1;
}
else
{
if (!(obj1 is string) && !binarySupported)
{
obj1 = Convert.ToBase64String((byte[]) obj1);
}
if (obj1 is string)
{
text1 = (string) obj1;
num1 = text1.Length;
num2 = builder2.Length;
}
else
{
byte[] buffer1 = (byte[]) obj1;
num2 = (int) stream1.Position;
stream1.Write(buffer1, 0, buffer1.Length);
stream1.Position = num2 + buffer1.Length;
num1 = buffer1.Length;
}
}
}
string[] textArray1 = new string[8] { value2.Name, ":", (text1 != null) ? "S" : "B", ":", num2.ToString(CultureInfo.InvariantCulture), ":", num1.ToString(CultureInfo.InvariantCulture), ":" } ;
builder1.Append(string.Concat(textArray1));
if (text1 != null)
{
builder2.Append(text1);
}
}
}
if (binarySupported)
{
buf = stream1.ToArray();
}
}
catch
{
throw;
}
finally
{
if (stream1 != null)
{
stream1.Close();
}
}
allNames = builder1.ToString();
allValues = builder2.ToString();
}
internal static void ParseDataFromDB(string[] names, string values, byte[] buf, SettingsPropertyValueCollection properties)
{
for (int num1 = 0; num1 < (names.Length / 4); num1++)
{
string text1 = names[num1 * 4];
SettingsPropertyValue value1 = properties[text1];
if (value1 != null)
{
int num2 = int.Parse(names[(num1 * 4) + 2], CultureInfo.InvariantCulture);
int num3 = int.Parse(names[(num1 * 4) + 3], CultureInfo.InvariantCulture);
if (num3 == -1)