Vorgehensweise: Deserialisieren von Instanzdateneigenschaften
Dieses Thema gilt für Windows Workflow Foundation 4.
Es gibt möglicherweise Situationen, in denen ein Benutzer oder Workflowadministrator den Zustand einer beibehaltenen Workflowinstanz manuell überprüfen möchte. SqlWorkflowInstanceStore bietet eine Ansicht der Instanzentabelle, die die folgenden vier Spalten verfügbar macht:
ReadWritePrimitiveDataProperties
WriteOnlyPrimitiveDataProperties
ReadWriteComplexDataProperties
WriteOnlyComplexDataProperties
Primitive Dateneigenschaften verweisen auf Eigenschaften, deren .NET Framework-Typen als "häufig verwendet" betracht werden (z. B. Int32 und String), wohingegen komplexe Dateneigenschaften auf alle anderen Typen verweisen. Eine genaue Enumeration von primitiven Typen finden Sie später in diesem Codebeispiel.
ReadWrite-Eigenschaften verweisen auf Eigenschaften, die an die Workflowlaufzeit zurückgegeben werden, wenn eine Instanz geladen wird. WriteOnly-Eigenschaften werden in die Datenbank geschrieben und dann nie wieder gelesen.
Diesem Beispiel stellt Code bereit, mit dem ein Benutzer primitive Dateneigenschaften deserialisieren kann. Bei einem bestimmten Bytearray, das entweder von der ReadWritePrimitiveDataProperties-Spalte oder der WriteOnlyPrimitiveDataProperties-Spalte gelesen wird, wandelt dieser Code das BLOB-Objekt (Binary Large Object) in ein (Dictionary vom Typ <XName, Objekt> um, wobei jedes Schlüssel-Wert-Paar einen Eigenschaftsnamen und den entsprechenden Wert darstellt.
In diesem Beispiel wird nicht veranschaulicht, wie komplexe Dateneigenschaften deserialisiert werden, da dies derzeit kein unterstützter Vorgang ist.
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["ReadWriteComplexDataProperties"] != DBNull.Value)
//{
// encodingOption = (byte)reader["EncodingOption"];
// Console.WriteLine("Printing the ReadWriteComplexDataProperties of the instance with Id:" + reader["InstanceId"]);
// foreach (KeyValuePair<XName, object> pair in (Dictionary<XName, object>)ReadDataProperties((byte[])reader["ReadWriteComplexDataProperties"], 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();
}
//if (reader["WriteOnlyComplexDataProperties"] != DBNull.Value)
//{
// encodingOption = (byte)reader["EncodingOption"];
// Console.WriteLine("Printing the WriteOnlyComplexDataProperties of the instance with Id:" + reader["InstanceId"]);
// foreach (KeyValuePair<XName, object> pair in (Dictionary<XName, object>)ReadDataProperties((byte[])reader["WriteOnlyComplexDataProperties"], 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 will return 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 which 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
}
}
}