WF4提供了强大的持久化的功能,ms提供了SqlWorkflowInstanceStore 来进行SqlServer的持久化,我研究了一下,DB里面有10个数据表,24个存储过程。功能非常强大,但是也逻辑也比较复杂。这里我介绍自定义的持久化。持久化的存储器也SqlServer。
1、设计数据表,表结构非常简单,如下图所示:
2、自定义的SqlServerWorkflowInstanceStore继承了InstanceStore:
代码
public class SqlServerWorkflowInstanceStore : InstanceStore
{
public Guid ownerInstanceID;
public SqlServerWorkflowInstanceStore() : this(Guid.NewGuid())
{
}
public SqlServerWorkflowInstanceStore(Guid id)
{
ownerInstanceID = id;
}
//Synchronous version of the Begin/EndTryCommand functions
protected override bool TryCommand(InstancePersistenceContext context, InstancePersistenceCommand command, TimeSpan timeout)
{
return EndTryCommand(BeginTryCommand(context, command, timeout, null, null));
}
//The persistence engine will send a variety of commands to the configured InstanceStore,
//such as CreateWorkflowOwnerCommand, SaveWorkflowCommand, and LoadWorkflowCommand.
//This method is where we will handle those commands
protected override IAsyncResult BeginTryCommand(InstancePersistenceContext context, InstancePersistenceCommand command, TimeSpan timeout, AsyncCallback callback, object state)
{
IDictionary<System.Xml.Linq.XName, InstanceValue> data = null;
//The CreateWorkflowOwner command instructs the instance store to create a new instance owner bound to the instanace handle
if (command is CreateWorkflowOwnerCommand)
{
context.BindInstanceOwner(ownerInstanceID, Guid.NewGuid());
}
//The SaveWorkflow command instructs the instance store to modify the instance bound to the instance handle or an instance key
else if (command is SaveWorkflowCommand)
{
SaveWorkflowCommand saveCommand = (SaveWorkflowCommand)command;
data = saveCommand.InstanceData;
Save(data);
}
else if (command is LoadWorkflowCommand)
{
try
{
InstancesTable obj = InstancesTableBiz.GetInstancesTable(this.ownerInstanceID);
System.Text.UTF8Encoding utf8 = new System.Text.UTF8Encoding();
byte[] bs = utf8.GetBytes(obj.InstanceXML);
System.IO.MemoryStream memoryStream = new System.IO.MemoryStream(bs);
data = LoadInstanceDataFromFile(memoryStream);
context.LoadedInstance(InstanceState.Initialized, data, null, null, null);
}
catch (Exception exception)
{
throw new PersistenceException(exception.Message);
}
}
return new CompletedAsyncResult<bool>(true, callback, state);
}
protected override bool EndTryCommand(IAsyncResult result)
{
return CompletedAsyncResult<bool>.End(result);
}
IDictionary<System.Xml.Linq.XName, InstanceValue> LoadInstanceDataFromFile(Stream inputStream)
{
IDictionary<System.Xml.Linq.XName, InstanceValue> data = new Dictionary<System.Xml.Linq.XName, InstanceValue>();
NetDataContractSerializer s = new NetDataContractSerializer();
XmlReader rdr = XmlReader.Create(inputStream);
XmlDocument doc = new XmlDocument();
doc.Load(rdr);
XmlNodeList instances = doc.GetElementsByTagName("InstanceValue");
foreach (XmlElement instanceElement in instances)
{
XmlElement keyElement = (XmlElement)instanceElement.SelectSingleNode("descendant::key");
System.Xml.Linq.XName key = (System.Xml.Linq.XName)DeserializeObject(s, keyElement);
XmlElement valueElement = (XmlElement)instanceElement.SelectSingleNode("descendant::value");
object value = DeserializeObject(s, valueElement);
InstanceValue instVal = new InstanceValue(value);
data.Add(key, instVal);
}
return data;
}
object DeserializeObject(NetDataContractSerializer serializer, XmlElement element)
{
object deserializedObject = null;
MemoryStream stm = new MemoryStream();
XmlDictionaryWriter wtr = XmlDictionaryWriter.CreateTextWriter(stm);
element.WriteContentTo(wtr);
wtr.Flush();
stm.Position = 0;
deserializedObject = serializer.Deserialize(stm);
return deserializedObject;
}
void Save(IDictionary<System.Xml.Linq.XName, InstanceValue> instanceData)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml("<InstanceValues/>");
foreach (KeyValuePair<System.Xml.Linq.XName,InstanceValue> valPair in instanceData)
{
XmlElement newInstance = doc.CreateElement("InstanceValue");
XmlElement newKey = SerializeObject("key", valPair.Key, doc);
newInstance.AppendChild(newKey);
XmlElement newValue = SerializeObject("value", valPair.Value.Value, doc);
newInstance.AppendChild(newValue);
doc.DocumentElement.AppendChild(newInstance);
}
if (!string.IsNullOrEmpty(InstancesTableBiz.GetInstancesTable(this.ownerInstanceID).InstanceXML))
{
InstancesTable obj = InstancesTableBiz.GetInstancesTable(this.ownerInstanceID);
obj.InstanceXML = doc.InnerXml;
InstancesTableBiz.UpdateInstancesTable(obj);
}
else
{
InstancesTable obj = new InstancesTable();
obj.id = this.ownerInstanceID;
obj.InstanceXML = doc.InnerXml;
InstancesTableBiz.AddInstancesTable(obj);
}
}
XmlElement SerializeObject(string elementName, object o, XmlDocument doc)
{
NetDataContractSerializer s = new NetDataContractSerializer();
XmlElement newElement = doc.CreateElement(elementName);
MemoryStream stm = new MemoryStream();
s.Serialize(stm, o);
stm.Position = 0;
StreamReader rdr = new StreamReader(stm);
newElement.InnerXml = rdr.ReadToEnd();
return newElement;
}
}
{
public Guid ownerInstanceID;
public SqlServerWorkflowInstanceStore() : this(Guid.NewGuid())
{
}
public SqlServerWorkflowInstanceStore(Guid id)
{
ownerInstanceID = id;
}
//Synchronous version of the Begin/EndTryCommand functions
protected override bool TryCommand(InstancePersistenceContext context, InstancePersistenceCommand command, TimeSpan timeout)
{
return EndTryCommand(BeginTryCommand(context, command, timeout, null, null));
}
//The persistence engine will send a variety of commands to the configured InstanceStore,
//such as CreateWorkflowOwnerCommand, SaveWorkflowCommand, and LoadWorkflowCommand.
//This method is where we will handle those commands
protected override IAsyncResult BeginTryCommand(InstancePersistenceContext context, InstancePersistenceCommand command, TimeSpan timeout, AsyncCallback callback, object state)
{
IDictionary<System.Xml.Linq.XName, InstanceValue> data = null;
//The CreateWorkflowOwner command instructs the instance store to create a new instance owner bound to the instanace handle
if (command is CreateWorkflowOwnerCommand)
{
context.BindInstanceOwner(ownerInstanceID, Guid.NewGuid());
}
//The SaveWorkflow command instructs the instance store to modify the instance bound to the instance handle or an instance key
else if (command is SaveWorkflowCommand)
{
SaveWorkflowCommand saveCommand = (SaveWorkflowCommand)command;
data = saveCommand.InstanceData;
Save(data);
}
else if (command is LoadWorkflowCommand)
{
try
{
InstancesTable obj = InstancesTableBiz.GetInstancesTable(this.ownerInstanceID);
System.Text.UTF8Encoding utf8 = new System.Text.UTF8Encoding();
byte[] bs = utf8.GetBytes(obj.InstanceXML);
System.IO.MemoryStream memoryStream = new System.IO.MemoryStream(bs);
data = LoadInstanceDataFromFile(memoryStream);
context.LoadedInstance(InstanceState.Initialized, data, null, null, null);
}
catch (Exception exception)
{
throw new PersistenceException(exception.Message);
}
}
return new CompletedAsyncResult<bool>(true, callback, state);
}
protected override bool EndTryCommand(IAsyncResult result)
{
return CompletedAsyncResult<bool>.End(result);
}
IDictionary<System.Xml.Linq.XName, InstanceValue> LoadInstanceDataFromFile(Stream inputStream)
{
IDictionary<System.Xml.Linq.XName, InstanceValue> data = new Dictionary<System.Xml.Linq.XName, InstanceValue>();
NetDataContractSerializer s = new NetDataContractSerializer();
XmlReader rdr = XmlReader.Create(inputStream);
XmlDocument doc = new XmlDocument();
doc.Load(rdr);
XmlNodeList instances = doc.GetElementsByTagName("InstanceValue");
foreach (XmlElement instanceElement in instances)
{
XmlElement keyElement = (XmlElement)instanceElement.SelectSingleNode("descendant::key");
System.Xml.Linq.XName key = (System.Xml.Linq.XName)DeserializeObject(s, keyElement);
XmlElement valueElement = (XmlElement)instanceElement.SelectSingleNode("descendant::value");
object value = DeserializeObject(s, valueElement);
InstanceValue instVal = new InstanceValue(value);
data.Add(key, instVal);
}
return data;
}
object DeserializeObject(NetDataContractSerializer serializer, XmlElement element)
{
object deserializedObject = null;
MemoryStream stm = new MemoryStream();
XmlDictionaryWriter wtr = XmlDictionaryWriter.CreateTextWriter(stm);
element.WriteContentTo(wtr);
wtr.Flush();
stm.Position = 0;
deserializedObject = serializer.Deserialize(stm);
return deserializedObject;
}
void Save(IDictionary<System.Xml.Linq.XName, InstanceValue> instanceData)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml("<InstanceValues/>");
foreach (KeyValuePair<System.Xml.Linq.XName,InstanceValue> valPair in instanceData)
{
XmlElement newInstance = doc.CreateElement("InstanceValue");
XmlElement newKey = SerializeObject("key", valPair.Key, doc);
newInstance.AppendChild(newKey);
XmlElement newValue = SerializeObject("value", valPair.Value.Value, doc);
newInstance.AppendChild(newValue);
doc.DocumentElement.AppendChild(newInstance);
}
if (!string.IsNullOrEmpty(InstancesTableBiz.GetInstancesTable(this.ownerInstanceID).InstanceXML))
{
InstancesTable obj = InstancesTableBiz.GetInstancesTable(this.ownerInstanceID);
obj.InstanceXML = doc.InnerXml;
InstancesTableBiz.UpdateInstancesTable(obj);
}
else
{
InstancesTable obj = new InstancesTable();
obj.id = this.ownerInstanceID;
obj.InstanceXML = doc.InnerXml;
InstancesTableBiz.AddInstancesTable(obj);
}
}
XmlElement SerializeObject(string elementName, object o, XmlDocument doc)
{
NetDataContractSerializer s = new NetDataContractSerializer();
XmlElement newElement = doc.CreateElement(elementName);
MemoryStream stm = new MemoryStream();
s.Serialize(stm, o);
stm.Position = 0;
StreamReader rdr = new StreamReader(stm);
newElement.InnerXml = rdr.ReadToEnd();
return newElement;
}
}
3、设计书签类:
代码
public sealed class Read<TResult> : NativeActivity<TResult>
{
public Read()
: base()
{
}
public string BookmarkName { get; set; }
// Must return true for a NativeActivity that creates a bookmark
protected override bool CanInduceIdle
{
get { return true; }
}
protected override void Execute(NativeActivityContext context)
{
context.CreateBookmark(this.BookmarkName, new BookmarkCallback(this.Continue));
}
void Continue(NativeActivityContext context, Bookmark bookmark, object obj)
{
this.Result.Set(context, (TResult)obj);
}
}
{
public Read()
: base()
{
}
public string BookmarkName { get; set; }
// Must return true for a NativeActivity that creates a bookmark
protected override bool CanInduceIdle
{
get { return true; }
}
protected override void Execute(NativeActivityContext context)
{
context.CreateBookmark(this.BookmarkName, new BookmarkCallback(this.Continue));
}
void Continue(NativeActivityContext context, Bookmark bookmark, object obj)
{
this.Result.Set(context, (TResult)obj);
}
}
4、设计三个书签的流程:
5、自定义持久化的使用
代码
SqlServerWorkflowInstanceStore instanceStore = new SqlServerWorkflowInstanceStore ();
WorkflowApplication application = new WorkflowApplication(new Activity1());
application.InstanceStore = instanceStore;
application.PersistableIdle = (e) =>
{
return PersistableIdleAction.Unload;
};
application.Completed = (workflowApplicationCompletedEventArgs) =>
{
Console.WriteLine("\nWorkflowApplication has Completed in the {0} state.", workflowApplicationCompletedEventArgs.CompletionState);
};
application.Unloaded = (workflowApplicationEventArgs) =>
{
Console.WriteLine("WorkflowApplication has Unloaded\n");
instanceUnloaded.Set();
};
instanceStore.ownerInstanceID = application.Id;
// continue executing this instance
application.Run();
//string a= application.GetBookmarks()[0].BookmarkName;
instanceUnloaded.WaitOne();
return application.Id; ;
WorkflowApplication application = new WorkflowApplication(new Activity1());
application.InstanceStore = instanceStore;
application.PersistableIdle = (e) =>
{
return PersistableIdleAction.Unload;
};
application.Completed = (workflowApplicationCompletedEventArgs) =>
{
Console.WriteLine("\nWorkflowApplication has Completed in the {0} state.", workflowApplicationCompletedEventArgs.CompletionState);
};
application.Unloaded = (workflowApplicationEventArgs) =>
{
Console.WriteLine("WorkflowApplication has Unloaded\n");
instanceUnloaded.Set();
};
instanceStore.ownerInstanceID = application.Id;
// continue executing this instance
application.Run();
//string a= application.GetBookmarks()[0].BookmarkName;
instanceUnloaded.WaitOne();
return application.Id; ;
6、Demo说明:
在Start.aspx,启动一个流程
在Default.aspx,进行A,B,C三个站的审核。
备注:运行环境是VS2010 BETA2。
代码:/Files/zhuqil/WorkflowConsoleApplication3.rar
(全文完)
以下为广告部分
您部署的HTTPS网站安全吗?
如果您想看下您的网站HTTPS部署的是否安全,花1分钟时间来 myssl.com 检测以下吧。让您的HTTPS网站变得更安全!
快速了解HTTPS网站安全情况。
安全评级(A+、A、A-...)、行业合规检测、证书信息查看、证书链信息以及补完、服务器套件信息、证书兼容性检测等。
安装部署SSL证书变得更方便。
SSL证书内容查看、SSL证书格式转换、CSR在线生成、SSL私钥加解密、CAA检测等。
让服务器远离SSL证书漏洞侵扰
TLS ROBOT漏洞检测、心血漏洞检测、FREAK Attack漏洞检测、SSL Poodle漏洞检测、CCS注入漏洞检测。