using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Xml;
using System.Xml.Serialization;
using System.Collections.ObjectModel;
namespace MarvellousWorks


{

/**//// <summary>
/// 安全信息上下文
/// </summary>
/// <remarks>
/// 为了同时满足Binary调用和Soap调用的需要,完全定制化了二进制序列化和SOAP序列化的过程
/// </remarks>
[XmlRoot("securityContext")]
[Serializable]
public class SecurityContext : IXmlSerializable, ISerializable

{

Protected Consts#region Protected Consts


/**//// <summary>
/// Xml序列化过程中每个“key / value”项的element名称
/// </summary>
protected const string KeyValuePairItem = "item";


/**//// <summary>
/// Xml序列化过程中key部分的element名称
/// </summary>
protected const string KeyItem = "key";


/**//// <summary>
/// Xml序列化过程中value部分的element名称
/// </summary>
protected const string ValueItem = "value";


/**//// <summary>
/// 普通序列化过程中 keys 项
/// </summary>
protected const string KeysItem = "keys";


/**//// <summary>
/// 普通序列化过程中 values 项
/// </summary>
protected const string ValuesItem = "values";

#endregion


Protected Fields#region Protected Fields


/**//// <summary>
/// 集合
/// </summary>
[NonSerialized]
protected IDictionary<string, string> dictionary;

#endregion


Constructors#region Constructors


/**//// <summary>
/// 服务于序列化的构造
/// </summary>
/// <param name="info"></param>
/// <param name="context"></param>
protected SecurityContext(SerializationInfo info, StreamingContext context)

{
if (dictionary == null)
dictionary = CreateDictionary();

string[] keys = (string[])info.GetValue(KeysItem, typeof(string[]));
string[] values = (string[])info.GetValue(ValuesItem, typeof(string[]));

if ((keys == null) || (keys.Length == 0) || (values == null) || (values.Length == 0) || (keys.Length != values.Length))
return;

for (int i = 0; i < keys.Length; i++)
dictionary.Add(keys[i], values[i]);
}


/**//// <summary>
/// 构造
/// </summary>
public SecurityContext()

{
dictionary = CreateDictionary();
}

#endregion



/**//// <summary>
/// 访问Context内容项
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
/// <remarks>设计上,这个类型不会随便抛出异常,除非提供的key值为空串</remarks>
public virtual string this[string key]

{
get

{
if (string.IsNullOrEmpty(key))
throw new ArgumentNullException("key");

string value;
if (dictionary.TryGetValue(key, out value))
return value;
else
return string.Empty;
}
set

{
if (string.IsNullOrEmpty(key))
throw new ArgumentNullException("key");

if (dictionary.ContainsKey(key))
dictionary[key] = value;
else
dictionary.Add(key, value);
}
}


IXmlSerializable Members#region IXmlSerializable Members


/**//// <summary>
/// 定义Schema
/// </summary>
/// <returns></returns>
public System.Xml.Schema.XmlSchema GetSchema()

{
return null;
}


/**//// <summary>
/// 序列化之后加载内容
/// </summary>
/// <param name="reader"></param>
public void ReadXml(XmlReader reader)

{
XmlSerializer keySerializer = new XmlSerializer(typeof(string));
XmlSerializer valueSerializer = new XmlSerializer(typeof(string));

if ((reader == null) || (reader.IsEmptyElement))
return;

reader.Read();
if (dictionary == null)
dictionary = CreateDictionary();
else
dictionary.Clear();

while (reader.NodeType != XmlNodeType.EndElement)

{
reader.ReadStartElement(KeyValuePairItem);
reader.ReadStartElement(KeyItem);
string key = (string)keySerializer.Deserialize(reader);
reader.ReadEndElement();
reader.ReadStartElement(ValueItem);
string value = (string)valueSerializer.Deserialize(reader);
reader.ReadEndElement();
dictionary.Add(key, value);
reader.ReadEndElement();
reader.MoveToContent();
}
reader.ReadEndElement();
}


/**//// <summary>
/// 序列化内容至XML
/// </summary>
/// <param name="writer"></param>
public void WriteXml(XmlWriter writer)

{
if ((dictionary == null) || (dictionary.Count == 0))
return;

XmlSerializer keySerializer = new XmlSerializer(typeof(string));
XmlSerializer valueSerializer = new XmlSerializer(typeof(string));

foreach (string key in dictionary.Keys)

{
writer.WriteStartElement(KeyValuePairItem);

writer.WriteStartElement(KeyItem);
keySerializer.Serialize(writer, key);
writer.WriteEndElement();
writer.WriteStartElement(ValueItem);
string value = dictionary[key];
valueSerializer.Serialize(writer, value);
writer.WriteEndElement();
writer.WriteEndElement();
}
}

#endregion



ISerializable Members#region ISerializable Members



/**//// <summary>
/// 普通序列化的处理
/// </summary>
/// <param name="info"></param>
/// <param name="context"></param>
public void GetObjectData(SerializationInfo info, StreamingContext context)

{
if ((dictionary == null) || (dictionary.Count == 0))

{
info.AddValue(KeysItem, null, typeof(string[]));
info.AddValue(ValuesItem, null, typeof(string[]));
return;
}

string[] keys = new string[dictionary.Count];
string[] values = new string[dictionary.Count];
dictionary.Keys.CopyTo(keys, 0);
dictionary.Values.CopyTo(values, 0);

info.AddValue(KeysItem, keys, typeof(string[]));
info.AddValue(ValuesItem, values, typeof(string[]));
}

#endregion


Helper Methods#region Helper Methods

private IDictionary<string, string> CreateDictionary()

{
return new Dictionary<string, string>();
}

#endregion
}
}

相应的UnitTest
1
/**//// <summary>
2
/// 测试安全上下文
3
/// </summary>
4
[TestClass]
5
public class SecurityContextFixture
6
{
7
/**//// <summary>
8
/// Prepare
9
/// </summary>
10
/// <returns></returns>
11
private SecurityContext CreateContext()
12
{
13
SecurityContext context = new SecurityContext();
14
context["hello"] = "world";
15
context["1"] = "first";
16
return context;
17
}
18
19
/**//// <summary>
20
/// 访问SecurityContext
21
/// </summary>
22
[TestMethod]
23
public void TestContextAccess()
24
{
25
SecurityContext context = CreateContext();
26
27
Assert.AreEqual<string>("world", context["hello"]);
28
Assert.AreEqual<string>("first", context["1"]);
29
Assert.IsTrue(string.IsNullOrEmpty(context["2"]));
30
31
context["1"] = "First";
32
Assert.AreEqual<string>("First", context["1"]);
33
}
34
35
/**//// <summary>
36
/// 主要确认是否可以被Binary序列化,尤其是用于远程调用
37
/// </summary>
38
[TestMethod]
39
public void TestBinarySerializeContext()
40
{
41
// 测试序列化
42
SecurityContext temp = CreateContext();
43
string tempGraph = SerializationHelper.SerializeObjectToString(temp, SerializationFormatterType.Binary);
44
Trace.WriteLine(tempGraph);
45
SecurityContext context = SerializationHelper.DeserializeStringToObject<SecurityContext>(tempGraph, SerializationFormatterType.Binary);
46
47
Assert.AreEqual<string>("world", context["hello"]);
48
Assert.AreEqual<string>("first", context["1"]);
49
Assert.IsTrue(string.IsNullOrEmpty(context["2"]));
50
51
string graph = SerializationHelper.SerializeObjectToString(context, SerializationFormatterType.Binary);
52
Trace.WriteLine(graph);
53
Assert.AreEqual<string>(tempGraph, graph);
54
55
// 测试序列化的结构是两个完全不同的实例
56
temp["2"] = "Second";
57
Assert.IsTrue(string.IsNullOrEmpty(context["2"]));
58
context["2"] = "二";
59
Assert.AreNotEqual<string>(context["2"], temp["2"]);
60
Trace.WriteLine(context["2"]);
61
Trace.WriteLine(temp["2"]);
62
}
63
64
/**//// <summary>
65
/// 主要确认是否可以被Soap序列化,尤其是用于远程调用
66
/// </summary>
67
[TestMethod]
68
public void TestSoapSerializeContext()
69
{
70
// 测试序列化
71
SecurityContext temp = CreateContext();
72
string tempGraph = SerializationHelper.SerializeObjectToString(temp, SerializationFormatterType.Soap);
73
Trace.WriteLine(tempGraph);
74
SecurityContext context = SerializationHelper.DeserializeStringToObject<SecurityContext>(tempGraph, SerializationFormatterType.Soap);
75
76
Assert.AreEqual<string>("world", context["hello"]);
77
Assert.AreEqual<string>("first", context["1"]);
78
Assert.IsTrue(string.IsNullOrEmpty(context["2"]));
79
80
string graph = SerializationHelper.SerializeObjectToString(context, SerializationFormatterType.Soap);
81
Trace.WriteLine(graph);
82
Assert.AreEqual<string>(tempGraph, graph);
83
byte[] buffer = Convert.FromBase64String(graph);
84
string soap = Encoding.Default.GetString(buffer);
85
Trace.WriteLine(soap);
86
87
88
// 测试序列化的结构是两个完全不同的实例
89
temp["2"] = "Second";
90
Assert.IsTrue(string.IsNullOrEmpty(context["2"]));
91
context["2"] = "二";
92
Assert.AreNotEqual<string>(context["2"], temp["2"]);
93
Trace.WriteLine(context["2"]);
94
Trace.WriteLine(temp["2"]);
95
}
96
}
97
这里SerializationHelper是对一个简单的序列化工具类型
public enum SerializationFormatterType

{
Soap,
Binary
}


public static class SerializationHelper

{

Helper method#region Helper method

/**//// <summary>
/// 按照串行化的编码要求,生成对应的编码器。
/// </summary>
/// <param name="formatterType"></param>
/// <returns></returns>
private static IRemotingFormatter GetFormatter(SerializationFormatterType formatterType)

{
switch (formatterType)

{
case SerializationFormatterType.Binary:
return new BinaryFormatter();
case SerializationFormatterType.Soap:
return new SoapFormatter();
default:
throw new NotSupportedException();
}
}
#endregion

public static string SerializeObjectToString(object graph, SerializationFormatterType formatterType)

{
using (MemoryStream memoryStream = new MemoryStream())

{
IRemotingFormatter formatter = GetFormatter(formatterType);
formatter.Serialize(memoryStream, graph);
Byte[] arrGraph = memoryStream.ToArray();
return Convert.ToBase64String(arrGraph);
}
}

public static T DeserializeStringToObject<T>(string serializedGraph, SerializationFormatterType formatterType)

{
Byte[] arrGraph = Convert.FromBase64String(serializedGraph);
using (MemoryStream memoryStream = new MemoryStream(arrGraph))

{
IRemotingFormatter formatter = GetFormatter(formatterType);
return (T)formatter.Deserialize(memoryStream);
}
}
}