如何:对实例数据属性进行反序列化
在有些情况下,用户或工作流管理员可能想要手动检查持久化工作流实例的状态。 SqlWorkflowInstanceStore 提供一个有关 Instances 表的视图,公开以下四列:
- ReadWritePrimitiveDataProperties
- WriteOnlyPrimitiveDataProperties
- ReadWriteComplexDataProperties
- WriteOnlyComplexDataProperties
基元数据属性是指其 .NET 类型被视为“通用”的属性(例如,Int32 和 String),而复杂数据属性是指所有其他类型的属性。 在此代码示例的后面提供了基元类型的完整枚举。
Read/write 属性指的是那些在加载实例时返回到工作流运行时的属性。 WriteOnly 属性将写入到数据库,然后再也不会读取。
此示例提供使用户能够将基元数据属性反序列化的代码。 给定从 ReadWritePrimitiveDataProperties 或 WriteOnlyPrimitiveDataProperties 列读取的字节数组,此代码会将二进制大型对象 (BLOB) 转换为类型 <XName, object>
的 Dictionary<TKey,TValue>,其中每个键值对表示一个属性名称及其对应的值。
重要
Microsoft 建议使用最安全的可用身份验证流。 如果要连接到 Azure SQL,建议使用 Azure 资源的托管标识这种身份验证方法。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.IO.Compression;
using System.Xml.Linq;
using System.Xml;
using System.Globalization;
using System.Data.SqlClient;
namespace PropertyReader
{
class Program
{
const string ConnectionString = @"Data Source=localhost;Initial Catalog=Persistence;Integrated Security=True;Asynchronous Processing=True";
static void Main(string[] args)
{
string queryString = "SELECT TOP 10 * FROM [System.Activities.DurableInstancing].[Instances]";
using (SqlConnection connection =
new SqlConnection(ConnectionString))
{
SqlCommand command =
new SqlCommand(queryString, connection);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
byte encodingOption;
while (reader.Read())
{
if (reader["ReadWritePrimitiveDataProperties"] != DBNull.Value)
{
encodingOption = (byte)reader["EncodingOption"];
Console.WriteLine("Printing the ReadWritePrimitiveDataProperties of the instance with Id:" + reader["InstanceId"]);
foreach (KeyValuePair<XName, object> pair in (Dictionary<XName, object>)ReadDataProperties((byte[])reader["ReadWritePrimitiveDataProperties"], encodingOption))
{
Console.WriteLine("{0}, {1}" , pair.Key, pair.Value);
}
Console.WriteLine();
}
if (reader["WriteOnlyPrimitiveDataProperties"] != DBNull.Value)
{
encodingOption = (byte)reader["EncodingOption"];
Console.WriteLine("Printing the WriteOnlyPrimitiveDataProperties of the instance with Id:" + reader["InstanceId"]);
foreach (KeyValuePair<XName, object> pair in (Dictionary<XName, object>)ReadDataProperties((byte[])reader["WriteOnlyPrimitiveDataProperties"], encodingOption))
{
Console.WriteLine("{0}, {1}", pair.Key, pair.Value);
}
Console.WriteLine();
}
}
// Call Close when done reading.
reader.Close();
}
Console.ReadLine();
}
static Dictionary<XName, object> ReadDataProperties(byte[] serializedDataProperties, byte encodingOption)
{
if (serializedDataProperties != null)
{
Dictionary<XName, object> propertyBag = new Dictionary<XName, object>();
bool isCompressed = (encodingOption == 1);
using (MemoryStream memoryStream = new MemoryStream(serializedDataProperties))
{
// if the instance state is compressed using GZip algorithm
if (isCompressed)
{
// decompress the data using the GZip
using (GZipStream stream = new GZipStream(memoryStream, CompressionMode.Decompress))
{
// create an XmlReader object and pass it on to the helper method ReadPrimitiveDataProperties
using (XmlReader reader = XmlDictionaryReader.CreateBinaryReader(stream, XmlDictionaryReaderQuotas.Max))
{
// invoke the helper method
ReadPrimitiveDataProperties(reader, propertyBag);
}
}
}
else
{
// if the instance data is not compressed
// create an XmlReader object and pass it on to the helper method ReadPrimitiveDataProperties
using (XmlReader reader = XmlDictionaryReader.CreateBinaryReader(memoryStream, XmlDictionaryReaderQuotas.Max))
{
// invoke the helper method
ReadPrimitiveDataProperties(reader, propertyBag);
}
}
return propertyBag;
}
}
return null;
}
// Reads the primitive data properties from the XML stream.
// Invoked by the ReadDataProperties method.
static void ReadPrimitiveDataProperties(XmlReader reader, Dictionary<XName, object> propertyBag)
{
const string xmlElementName = "Property";
if (reader.ReadToDescendant(xmlElementName))
{
do
{
// get the name of the property
reader.MoveToFirstAttribute();
string propertyName = reader.Value;
// get the type of the property
reader.MoveToNextAttribute();
PrimitiveType type = (PrimitiveType)Int32.Parse(reader.Value, CultureInfo.InvariantCulture);
// get the value of the property
reader.MoveToNextAttribute();
object propertyValue = ConvertStringToNativeType(reader.Value, type);
// add the name and value of the property to the property bag
propertyBag.Add(propertyName, propertyValue);
}
while (reader.ReadToNextSibling(xmlElementName));
}
}
// Invoked by the ReadPrimitiveDataProperties method.
// Given a property value as parsed from an XML attribute, and the .NET Type of the Property, recreates the actual property value
// (e.g. Given a property value of "1" and a PrimitiveType of Int32, this method returns an object of type Int32 with value 1).
static object ConvertStringToNativeType(string value, PrimitiveType type)
{
switch (type)
{
case PrimitiveType.Bool:
return XmlConvert.ToBoolean(value);
case PrimitiveType.Byte:
return XmlConvert.ToByte(value);
case PrimitiveType.Char:
return XmlConvert.ToChar(value);
case PrimitiveType.DateTime:
return XmlConvert.ToDateTime(value, XmlDateTimeSerializationMode.RoundtripKind);
case PrimitiveType.DateTimeOffset:
return XmlConvert.ToDateTimeOffset(value);
case PrimitiveType.Decimal:
return XmlConvert.ToDecimal(value);
case PrimitiveType.Double:
return XmlConvert.ToDouble(value);
case PrimitiveType.Float:
return float.Parse(value, CultureInfo.InvariantCulture);
case PrimitiveType.Guid:
return XmlConvert.ToGuid(value);
case PrimitiveType.Int:
return XmlConvert.ToInt32(value);
case PrimitiveType.Long:
return XmlConvert.ToInt64(value);
case PrimitiveType.SByte:
return XmlConvert.ToSByte(value);
case PrimitiveType.Short:
return XmlConvert.ToInt16(value);
case PrimitiveType.String:
return value;
case PrimitiveType.TimeSpan:
return XmlConvert.ToTimeSpan(value);
case PrimitiveType.Type:
return Type.GetType(value);
case PrimitiveType.UInt:
return XmlConvert.ToUInt32(value);
case PrimitiveType.ULong:
return XmlConvert.ToUInt64(value);
case PrimitiveType.Uri:
return new Uri(value);
case PrimitiveType.UShort:
return XmlConvert.ToUInt16(value);
case PrimitiveType.XmlQualifiedName:
return new XmlQualifiedName(value);
case PrimitiveType.Null:
case PrimitiveType.Unavailable:
default:
return null;
}
}
// .NET Types that SQL Workflow Instance Store considers to be Primitive. Any other .NET type not listed in this enumeration is a "Complex" property.
enum PrimitiveType
{
Bool = 0,
Byte,
Char,
DateTime,
DateTimeOffset,
Decimal,
Double,
Float,
Guid,
Int,
Null,
Long,
SByte,
Short,
String,
TimeSpan,
Type,
UInt,
ULong,
Uri,
UShort,
XmlQualifiedName,
Unavailable = 99
}
}
}
此示例没有演示如何将复杂数据属性反序列化,因为这是不受支持的操作。