e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
874 lines
31 KiB
C#
874 lines
31 KiB
C#
using System;
|
|
using System.Data;
|
|
using System.Data.SqlClient;
|
|
using System.Data.SqlTypes;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using System.Xml;
|
|
using System.Reflection;
|
|
using System.IO;
|
|
using System.Runtime.Serialization.Formatters.Binary;
|
|
using System.ComponentModel.Design.Serialization;
|
|
|
|
using System.Workflow.Runtime;
|
|
using System.Workflow.ComponentModel;
|
|
using System.Workflow.ComponentModel.Serialization;
|
|
using System.Workflow.Runtime.Hosting;
|
|
|
|
namespace System.Workflow.Runtime.Tracking
|
|
{
|
|
[Obsolete("The System.Workflow.* types are deprecated. Instead, please use the new types from System.Activities.*")]
|
|
public class SqlTrackingWorkflowInstance
|
|
{
|
|
#region Private Members
|
|
|
|
private delegate void LoadFromReader(SqlDataReader reader, object parameter);
|
|
|
|
private static int _deadlock = 1205;
|
|
private static short _retries = 5;
|
|
private string _connectionString = null;
|
|
private bool _autoRefresh = false;
|
|
|
|
DateTime _currDT = DateTime.UtcNow,
|
|
_actMinDT = SqlDateTime.MinValue.Value,
|
|
_userMinDT = SqlDateTime.MinValue.Value,
|
|
_instMinDT = SqlDateTime.MinValue.Value,
|
|
_childMinDT = SqlDateTime.MinValue.Value,
|
|
_changesMinDT = SqlDateTime.MinValue.Value,
|
|
_invMinDT = SqlDateTime.MinValue.Value;
|
|
|
|
long _internalId = -1;
|
|
|
|
Guid _id;
|
|
DateTime _initialized;
|
|
Guid _invoker = Guid.Empty;
|
|
WorkflowStatus _status;
|
|
Type _workflowType = null;
|
|
bool _changed = false;
|
|
|
|
List<ActivityTrackingRecord> _activityEvents = new List<ActivityTrackingRecord>();
|
|
List<UserTrackingRecord> _userEvents = new List<UserTrackingRecord>();
|
|
List<WorkflowTrackingRecord> _workflowEvents = new List<WorkflowTrackingRecord>();
|
|
List<SqlTrackingWorkflowInstance> _invoked = new List<SqlTrackingWorkflowInstance>();
|
|
|
|
Activity _def = null;
|
|
|
|
#endregion Private Members
|
|
|
|
#region Constructors
|
|
|
|
private SqlTrackingWorkflowInstance() { }
|
|
|
|
internal SqlTrackingWorkflowInstance(string connectionString)
|
|
{
|
|
if (null == connectionString)
|
|
throw new ArgumentNullException("connectionString");
|
|
_connectionString = connectionString;
|
|
}
|
|
|
|
#endregion Constructors
|
|
|
|
#region Properties
|
|
|
|
public bool AutoRefresh
|
|
{
|
|
get { return _autoRefresh; }
|
|
set { _autoRefresh = value; }
|
|
}
|
|
|
|
public Guid WorkflowInstanceId
|
|
{
|
|
get { return _id; }
|
|
set { _id = value; }
|
|
}
|
|
|
|
public long WorkflowInstanceInternalId
|
|
{
|
|
get { return _internalId; }
|
|
set { _internalId = value; }
|
|
}
|
|
|
|
public DateTime Initialized
|
|
{
|
|
get { return _initialized; }
|
|
set { _initialized = value; }
|
|
}
|
|
|
|
public Guid InvokingWorkflowInstanceId
|
|
{
|
|
get { return _invoker; }
|
|
set { _invoker = value; }
|
|
}
|
|
|
|
public WorkflowStatus Status
|
|
{
|
|
get { return _status; }
|
|
set { _status = value; }
|
|
}
|
|
|
|
public Type WorkflowType
|
|
{
|
|
get { return _workflowType; }
|
|
set { _workflowType = value; }
|
|
}
|
|
|
|
public bool WorkflowDefinitionUpdated
|
|
{
|
|
get
|
|
{
|
|
if (_autoRefresh)
|
|
Refresh();
|
|
|
|
LoadDef();
|
|
return _changed;
|
|
}
|
|
}
|
|
|
|
public IList<ActivityTrackingRecord> ActivityEvents
|
|
{
|
|
get
|
|
{
|
|
if (_autoRefresh)
|
|
Refresh();
|
|
|
|
LoadActivityEvents();
|
|
return _activityEvents;
|
|
}
|
|
}
|
|
|
|
public IList<UserTrackingRecord> UserEvents
|
|
{
|
|
get
|
|
{
|
|
if (_autoRefresh)
|
|
Refresh();
|
|
|
|
LoadUserEvents();
|
|
return _userEvents;
|
|
}
|
|
}
|
|
|
|
public IList<WorkflowTrackingRecord> WorkflowEvents
|
|
{
|
|
get
|
|
{
|
|
if (_autoRefresh)
|
|
Refresh();
|
|
|
|
LoadWorkflowEvents();
|
|
return _workflowEvents;
|
|
}
|
|
}
|
|
|
|
public Activity WorkflowDefinition
|
|
{
|
|
get
|
|
{
|
|
if (_autoRefresh)
|
|
Refresh();
|
|
|
|
LoadDef();
|
|
return _def;
|
|
}
|
|
}
|
|
|
|
public IList<SqlTrackingWorkflowInstance> InvokedWorkflows
|
|
{
|
|
get
|
|
{
|
|
if (_autoRefresh)
|
|
Refresh();
|
|
LoadInvokedWorkflows();
|
|
return _invoked;
|
|
}
|
|
}
|
|
#endregion Properties
|
|
|
|
public void Refresh()
|
|
{
|
|
_currDT = DateTime.UtcNow;
|
|
}
|
|
|
|
private void LoadActivityEvents()
|
|
{
|
|
SqlCommand cmd = CreateInternalIdDateTimeCommand("[dbo].[GetActivityEventsWithDetails]", _actMinDT);
|
|
|
|
ExecuteRetried(cmd, LoadActivityEventsFromReader);
|
|
}
|
|
|
|
private void LoadActivityEventsFromReader(SqlDataReader reader, object parameter)
|
|
{
|
|
if (null == reader)
|
|
throw new ArgumentNullException("reader");
|
|
|
|
//
|
|
// There should always be 4 recordsets in this reader!
|
|
//
|
|
|
|
Dictionary<long, ActivityTrackingRecord> activities = new Dictionary<long, ActivityTrackingRecord>();
|
|
//
|
|
// Build a dictionary of activity records so that we can match
|
|
// annotation and artifact records from subsequent recordsets
|
|
DateTime tmpMin = SqlDateTime.MinValue.Value;
|
|
while (reader.Read())
|
|
{
|
|
string qId = reader.GetString(0);
|
|
ActivityExecutionStatus status = (ActivityExecutionStatus)reader[1];
|
|
DateTime dt = reader.GetDateTime(2);
|
|
Guid context = reader.GetGuid(3), parentContext = reader.GetGuid(4);
|
|
int order = reader.GetInt32(5);
|
|
|
|
if (reader.IsDBNull(6) || reader.IsDBNull(7))
|
|
throw new InvalidOperationException(String.Format(System.Globalization.CultureInfo.CurrentCulture, ExecutionStringManager.SqlTrackingTypeNotFound, qId));
|
|
|
|
Type type = Type.GetType(reader.GetString(6) + ", " + reader.GetString(7), true, false);
|
|
long eventId = reader.GetInt64(8);
|
|
|
|
DateTime dbDt = reader.GetDateTime(9);
|
|
|
|
activities.Add(eventId, new ActivityTrackingRecord(type, qId, context, parentContext, status, dt, order, null));
|
|
if (dbDt > tmpMin)
|
|
tmpMin = dbDt;
|
|
}
|
|
|
|
if (!reader.NextResult())
|
|
throw new ArgumentException(ExecutionStringManager.InvalidActivityEventReader);
|
|
|
|
//
|
|
// If we have annotations on the event itself, add them
|
|
while (reader.Read())
|
|
{
|
|
long eventId = reader.GetInt64(0);
|
|
string annotation = null;
|
|
|
|
if (!reader.IsDBNull(1))
|
|
annotation = reader.GetString(1);
|
|
|
|
ActivityTrackingRecord activity = null;
|
|
if (activities.TryGetValue(eventId, out activity))
|
|
{
|
|
if (null != activity)
|
|
activity.Annotations.Add(annotation);
|
|
}
|
|
}
|
|
|
|
if (!reader.NextResult())
|
|
throw new ArgumentException(ExecutionStringManager.InvalidActivityEventReader);
|
|
|
|
//
|
|
// Build a dictionary of artifact records so that we can match
|
|
// annotation records from subsequent recordsets
|
|
BinaryFormatter formatter = new BinaryFormatter();
|
|
Dictionary<long, TrackingDataItem> artifacts = new Dictionary<long, TrackingDataItem>();
|
|
while (reader.Read())
|
|
{
|
|
long eventId = reader.GetInt64(0);
|
|
long artId = reader.GetInt64(1);
|
|
string name = reader.GetString(2), strData = null;
|
|
object data = null;
|
|
//
|
|
// These may both be null
|
|
if (!reader.IsDBNull(3))
|
|
strData = reader.GetString(3);
|
|
|
|
if (!reader.IsDBNull(4))
|
|
data = formatter.Deserialize(new MemoryStream((Byte[])reader[4]));
|
|
|
|
TrackingDataItem item = new TrackingDataItem();
|
|
item.FieldName = name;
|
|
if (null != data)
|
|
item.Data = data;
|
|
else
|
|
item.Data = strData;
|
|
|
|
artifacts.Add(artId, item);
|
|
//
|
|
// Find the event to which this artifact belongs and add it to the record
|
|
ActivityTrackingRecord activity = null;
|
|
if (activities.TryGetValue(eventId, out activity))
|
|
{
|
|
if (null != activity)
|
|
activity.Body.Add(item);
|
|
}
|
|
}
|
|
|
|
if (!reader.NextResult())
|
|
throw new ArgumentException(ExecutionStringManager.InvalidActivityEventReader);
|
|
|
|
//
|
|
// If we have annotations add them to the appropriate artifact
|
|
while (reader.Read())
|
|
{
|
|
long artId = reader.GetInt64(0);
|
|
string annotation = null;
|
|
|
|
if (!reader.IsDBNull(1))
|
|
annotation = reader.GetString(1);
|
|
//
|
|
// Find the right artifact and give it the annotation
|
|
TrackingDataItem item = null;
|
|
if (artifacts.TryGetValue(artId, out item))
|
|
{
|
|
if (null != item)
|
|
item.Annotations.Add(annotation);
|
|
}
|
|
}
|
|
|
|
_activityEvents.AddRange(activities.Values);
|
|
|
|
//
|
|
// Set the min value to the most recent event that we got with this query
|
|
// Don't overwrite the previous min if nothing came back for this query
|
|
if (tmpMin > SqlDateTime.MinValue.Value)
|
|
_actMinDT = tmpMin;
|
|
return;
|
|
}
|
|
|
|
private void LoadUserEvents()
|
|
{
|
|
SqlCommand cmd = CreateInternalIdDateTimeCommand("[dbo].[GetUserEventsWithDetails]", _userMinDT);
|
|
|
|
ExecuteRetried(cmd, LoadUserEventsFromReader);
|
|
}
|
|
|
|
private void LoadUserEventsFromReader(SqlDataReader reader, object parameter)
|
|
{
|
|
if (null == reader)
|
|
throw new ArgumentNullException("reader");
|
|
|
|
//
|
|
// There should always be 4 recordsets in this reader!
|
|
//
|
|
|
|
BinaryFormatter formatter = new BinaryFormatter();
|
|
Dictionary<long, UserTrackingRecord> userEvents = new Dictionary<long, UserTrackingRecord>();
|
|
//
|
|
// Build a dictionary of activity records so that we can match
|
|
// annotation and artifact records from subsequent recordsets
|
|
DateTime tmpMin = SqlDateTime.MinValue.Value;
|
|
while (reader.Read())
|
|
{
|
|
string qId = reader.GetString(0);
|
|
DateTime dt = reader.GetDateTime(1);
|
|
Guid context = reader.GetGuid(2), parentContext = reader.GetGuid(3);
|
|
int order = reader.GetInt32(4);
|
|
string key = null;
|
|
if (!reader.IsDBNull(5))
|
|
key = reader.GetString(5);
|
|
//
|
|
// Get the user data from the serialized column if we can
|
|
// Try the string column if serialized column is null
|
|
// If both are null the user data was null originally
|
|
object userData = null;
|
|
if (!reader.IsDBNull(7))
|
|
userData = formatter.Deserialize(new MemoryStream((Byte[])reader[7]));
|
|
else if (!reader.IsDBNull(6))
|
|
userData = reader.GetString(6);
|
|
|
|
if (reader.IsDBNull(8) || reader.IsDBNull(9))
|
|
throw new InvalidOperationException(String.Format(System.Globalization.CultureInfo.CurrentCulture, ExecutionStringManager.SqlTrackingTypeNotFound, qId));
|
|
|
|
Type type = Type.GetType(reader.GetString(8) + ", " + reader.GetString(9), true, false);
|
|
long eventId = reader.GetInt64(10);
|
|
|
|
DateTime dbDt = reader.GetDateTime(11);
|
|
|
|
userEvents.Add(eventId, new UserTrackingRecord(type, qId, context, parentContext, dt, order, key, userData));
|
|
|
|
if (dbDt > tmpMin)
|
|
tmpMin = dbDt;
|
|
}
|
|
|
|
if (!reader.NextResult())
|
|
throw new ArgumentException(ExecutionStringManager.InvalidUserEventReader);
|
|
|
|
//
|
|
// If we have annotations on the event itself, add them
|
|
while (reader.Read())
|
|
{
|
|
long eventId = reader.GetInt64(0);
|
|
string annotation = null;
|
|
|
|
if (!reader.IsDBNull(1))
|
|
annotation = reader.GetString(1);
|
|
|
|
UserTrackingRecord user = null;
|
|
if (userEvents.TryGetValue(eventId, out user))
|
|
{
|
|
if (null != user)
|
|
user.Annotations.Add(annotation);
|
|
}
|
|
}
|
|
|
|
if (!reader.NextResult())
|
|
throw new ArgumentException(ExecutionStringManager.InvalidUserEventReader);
|
|
|
|
//
|
|
// Build a dictionary of artifact records so that we can match
|
|
// annotation records from subsequent recordsets
|
|
Dictionary<long, TrackingDataItem> artifacts = new Dictionary<long, TrackingDataItem>();
|
|
while (reader.Read())
|
|
{
|
|
long eventId = reader.GetInt64(0);
|
|
long artId = reader.GetInt64(1);
|
|
string name = reader.GetString(2), strData = null;
|
|
object data = null;
|
|
//
|
|
// These may both be null
|
|
if (!reader.IsDBNull(3))
|
|
strData = reader.GetString(3);
|
|
|
|
if (!reader.IsDBNull(4))
|
|
data = formatter.Deserialize(new MemoryStream((Byte[])reader[4]));
|
|
|
|
TrackingDataItem item = new TrackingDataItem();
|
|
item.FieldName = name;
|
|
if (null != data)
|
|
item.Data = data;
|
|
else
|
|
item.Data = strData;
|
|
|
|
artifacts.Add(artId, item);
|
|
//
|
|
// Find the event to which this artifact belongs and add it to the record
|
|
UserTrackingRecord user = null;
|
|
if (userEvents.TryGetValue(eventId, out user))
|
|
{
|
|
if (null != user)
|
|
user.Body.Add(item);
|
|
}
|
|
}
|
|
|
|
if (!reader.NextResult())
|
|
throw new ArgumentException(ExecutionStringManager.InvalidUserEventReader);
|
|
|
|
//
|
|
// If we have annotations add them to the appropriate artifact
|
|
while (reader.Read())
|
|
{
|
|
long artId = reader.GetInt64(0);
|
|
string annotation = null;
|
|
|
|
if (!reader.IsDBNull(1))
|
|
annotation = reader.GetString(1);
|
|
//
|
|
// Find the right artifact and give it the annotation
|
|
TrackingDataItem item = null;
|
|
if (artifacts.TryGetValue(artId, out item))
|
|
{
|
|
if (null != item)
|
|
item.Annotations.Add(annotation);
|
|
}
|
|
}
|
|
|
|
_userEvents.AddRange(userEvents.Values);
|
|
//
|
|
// Set the min dt to query for next time to the most recent event we got for this query.
|
|
// Don't overwrite the previous min if nothing came back for this query
|
|
if (tmpMin > SqlDateTime.MinValue.Value)
|
|
_userMinDT = tmpMin;
|
|
return;
|
|
}
|
|
|
|
private void LoadWorkflowEvents()
|
|
{
|
|
SqlCommand cmd = CreateInternalIdDateTimeCommand("[dbo].[GetWorkflowInstanceEventsWithDetails]", _instMinDT);
|
|
|
|
ExecuteRetried(cmd, LoadWorkflowEventsFromReader);
|
|
}
|
|
|
|
private void LoadWorkflowEventsFromReader(SqlDataReader reader, object parameter)
|
|
{
|
|
if (null == reader)
|
|
throw new ArgumentNullException("reader");
|
|
|
|
//
|
|
// There should always be 2 recordsets in this reader!
|
|
//
|
|
|
|
DateTime tmpMin = SqlDateTime.MinValue.Value;
|
|
|
|
Dictionary<long, WorkflowTrackingRecord> inst = new Dictionary<long, WorkflowTrackingRecord>();
|
|
while (reader.Read())
|
|
{
|
|
TrackingWorkflowEvent evt = (TrackingWorkflowEvent)reader[0];
|
|
DateTime dt = reader.GetDateTime(1);
|
|
int order = reader.GetInt32(2);
|
|
|
|
object tmp = null;
|
|
EventArgs args = null;
|
|
if (!reader.IsDBNull(3))
|
|
{
|
|
BinaryFormatter formatter = new BinaryFormatter();
|
|
tmp = formatter.Deserialize(new MemoryStream((Byte[])reader[3]));
|
|
if (tmp is EventArgs)
|
|
args = (EventArgs)tmp;
|
|
}
|
|
long eventId = reader.GetInt64(4);
|
|
|
|
DateTime dbDt = reader.GetDateTime(5);
|
|
|
|
inst.Add(eventId, new WorkflowTrackingRecord(evt, dt, order, args));
|
|
|
|
if (dbDt > tmpMin)
|
|
tmpMin = dbDt;
|
|
}
|
|
|
|
if (!reader.NextResult())
|
|
throw new ArgumentException(ExecutionStringManager.InvalidWorkflowInstanceEventReader);
|
|
|
|
//
|
|
// Add any annotations
|
|
while (reader.Read())
|
|
{
|
|
long eventId = reader.GetInt64(0);
|
|
string annotation = null;
|
|
|
|
if (!reader.IsDBNull(1))
|
|
annotation = reader.GetString(1);
|
|
|
|
WorkflowTrackingRecord rec = null;
|
|
if (inst.TryGetValue(eventId, out rec))
|
|
{
|
|
if (null != rec)
|
|
rec.Annotations.Add(annotation);
|
|
}
|
|
}
|
|
|
|
if (!reader.IsClosed)
|
|
reader.Close();
|
|
//
|
|
// Check if we have any WorkflowChange events in this list
|
|
// If so pull back the change actions and reconstruct the args property
|
|
foreach (KeyValuePair<long, WorkflowTrackingRecord> kvp in inst)
|
|
{
|
|
WorkflowTrackingRecord rec = kvp.Value;
|
|
if (TrackingWorkflowEvent.Changed != rec.TrackingWorkflowEvent)
|
|
continue;
|
|
|
|
SqlCommand cmd = new SqlCommand();
|
|
cmd.CommandType = CommandType.StoredProcedure;
|
|
cmd.CommandText = "[dbo].[GetWorkflowChangeEventArgs]";
|
|
cmd.Parameters.Add(new SqlParameter("@WorkflowInstanceInternalId", _internalId));
|
|
cmd.Parameters.Add(new SqlParameter("@BeginDateTime", SqlDateTime.MinValue.Value));
|
|
cmd.Parameters.Add(new SqlParameter("@WorkflowInstanceEventId", kvp.Key));
|
|
|
|
ExecuteRetried(cmd, LoadWorkflowChangeEventArgsFromReader, rec);
|
|
}
|
|
|
|
_workflowEvents.AddRange(inst.Values);
|
|
//
|
|
// set the min for the next query to the most recent event from this query
|
|
// Don't overwrite the previous min if nothing came back for this query
|
|
if (tmpMin > SqlDateTime.MinValue.Value)
|
|
_instMinDT = tmpMin;
|
|
}
|
|
|
|
private void LoadWorkflowChangeEventArgsFromReader(SqlDataReader reader, object parameter)
|
|
{
|
|
if (null == reader)
|
|
throw new ArgumentNullException("reader");
|
|
|
|
if (null == parameter)
|
|
throw new ArgumentNullException("parameter");
|
|
|
|
WorkflowTrackingRecord record = parameter as WorkflowTrackingRecord;
|
|
|
|
if (null == record)
|
|
throw new ArgumentException(ExecutionStringManager.InvalidWorkflowChangeEventArgsParameter, "parameter");
|
|
|
|
if (!reader.Read())
|
|
throw new ArgumentException(ExecutionStringManager.InvalidWorkflowChangeEventArgsReader);
|
|
|
|
StringReader sr = new StringReader(reader.GetString(0));
|
|
|
|
//Deserialize the xoml and set the root activity
|
|
Activity def = null;
|
|
WorkflowMarkupSerializer serializer = new WorkflowMarkupSerializer();
|
|
DesignerSerializationManager serializationManager = new DesignerSerializationManager();
|
|
IList errors = null;
|
|
try
|
|
{
|
|
using (serializationManager.CreateSession())
|
|
{
|
|
using (XmlReader xmlReader = XmlReader.Create(sr))
|
|
{
|
|
def = serializer.Deserialize(serializationManager, xmlReader) as Activity;
|
|
errors = serializationManager.Errors;
|
|
}
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
sr.Close();
|
|
}
|
|
|
|
if ((null == def) || ((null != errors) && (errors.Count > 0)))
|
|
throw new WorkflowMarkupSerializationException(ExecutionStringManager.WorkflowMarkupDeserializationError);
|
|
|
|
if (!reader.NextResult())
|
|
throw new ArgumentException(ExecutionStringManager.InvalidWorkflowChangeEventArgsReader);
|
|
//
|
|
// There is a result set that we don't care about for this scenario, skip it
|
|
if (!reader.NextResult())
|
|
throw new ArgumentException(ExecutionStringManager.InvalidWorkflowChangeEventArgsReader);
|
|
|
|
List<WorkflowChangeAction> actions = new List<WorkflowChangeAction>();
|
|
DateTime currDT = DateTime.MinValue;
|
|
int currEventOrder = -1;
|
|
int currOrder = -1;
|
|
|
|
while (reader.Read())
|
|
{
|
|
DateTime dt = reader.GetDateTime(1);
|
|
int eventOrder = reader.GetInt32(2);
|
|
int order = reader.GetInt32(3);
|
|
//
|
|
// Build temp lists as we read the results but
|
|
// only save the last set of change actions
|
|
if (dt > currDT && eventOrder > currEventOrder)
|
|
{
|
|
currEventOrder = eventOrder;
|
|
currOrder = order;
|
|
currDT = dt;
|
|
actions = new List<WorkflowChangeAction>();
|
|
}
|
|
|
|
using (sr = new StringReader(reader.GetString(0)))
|
|
{
|
|
using (serializationManager.CreateSession())
|
|
{
|
|
using (XmlReader xmlReader = XmlReader.Create(sr))
|
|
{
|
|
ActivityChangeAction aAction = serializer.Deserialize(serializationManager, xmlReader) as ActivityChangeAction;
|
|
|
|
errors = serializationManager.Errors;
|
|
if (null == aAction)
|
|
throw new WorkflowMarkupSerializationException(ExecutionStringManager.WorkflowMarkupDeserializationError);
|
|
|
|
actions.Add(aAction);
|
|
aAction.ApplyTo(def);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
record.EventArgs = new TrackingWorkflowChangedEventArgs(actions, def);
|
|
}
|
|
|
|
private void LoadDef()
|
|
{
|
|
SqlCommand cmd = null;
|
|
//
|
|
// If we don't have the definition load it
|
|
if (null == _def)
|
|
{
|
|
cmd = new SqlCommand();
|
|
cmd.CommandType = CommandType.StoredProcedure;
|
|
cmd.CommandText = "[dbo].[GetWorkflowDefinition]";
|
|
cmd.Parameters.Add(new SqlParameter("@WorkflowInstanceInternalId", _internalId));
|
|
|
|
ExecuteRetried(cmd, LoadDefFromReader);
|
|
}
|
|
//
|
|
// Now check for changes. If we find changes apply them to the definition
|
|
cmd = CreateInternalIdDateTimeCommand("[dbo].[GetWorkflowChanges]", _changesMinDT);
|
|
|
|
ExecuteRetried(cmd, LoadChangesFromReader);
|
|
}
|
|
|
|
private void LoadDefFromReader(SqlDataReader reader, object parameter)
|
|
{
|
|
if (null == reader)
|
|
throw new ArgumentNullException("reader");
|
|
|
|
if (!reader.Read())
|
|
throw new ArgumentException(ExecutionStringManager.InvalidDefinitionReader);
|
|
|
|
StringReader sr = new StringReader(reader.GetString(0));
|
|
|
|
//Deserialize the xoml and set the root activity
|
|
WorkflowMarkupSerializer serializer = new WorkflowMarkupSerializer();
|
|
DesignerSerializationManager serializationManager = new DesignerSerializationManager();
|
|
IList errors = null;
|
|
try
|
|
{
|
|
using (serializationManager.CreateSession())
|
|
{
|
|
using (XmlReader xmlReader = XmlReader.Create(sr))
|
|
{
|
|
_def = serializer.Deserialize(serializationManager, xmlReader) as Activity;
|
|
errors = serializationManager.Errors;
|
|
}
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
sr.Close();
|
|
}
|
|
|
|
if ((null == _def) || ((null != errors) && (errors.Count > 0)))
|
|
throw new WorkflowMarkupSerializationException(ExecutionStringManager.WorkflowMarkupDeserializationError);
|
|
}
|
|
|
|
private void LoadChangesFromReader(SqlDataReader reader, object parameter)
|
|
{
|
|
if (!reader.Read())
|
|
return;
|
|
//
|
|
// Reset the min to the most recent change event
|
|
DateTime tmpDT = _changesMinDT;
|
|
if (!reader.IsDBNull(0))
|
|
tmpDT = reader.GetDateTime(0);
|
|
|
|
if (reader.NextResult())
|
|
{
|
|
WorkflowMarkupSerializer serializer = new WorkflowMarkupSerializer();
|
|
DesignerSerializationManager serializationManager = new DesignerSerializationManager();
|
|
while (reader.Read())
|
|
{
|
|
IList errors = null;
|
|
using (StringReader sr = new StringReader(reader.GetString(0)))
|
|
{
|
|
using (serializationManager.CreateSession())
|
|
{
|
|
using (XmlReader xmlReader = XmlReader.Create(sr))
|
|
{
|
|
ActivityChangeAction aAction = serializer.Deserialize(serializationManager, xmlReader) as ActivityChangeAction;
|
|
|
|
errors = serializationManager.Errors;
|
|
if (null != aAction)
|
|
aAction.ApplyTo(_def);
|
|
else
|
|
throw new WorkflowMarkupSerializationException(ExecutionStringManager.WorkflowMarkupDeserializationError);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (tmpDT > _changesMinDT)
|
|
{
|
|
_changed = true;
|
|
_changesMinDT = tmpDT;
|
|
}
|
|
}
|
|
|
|
private void LoadInvokedWorkflows()
|
|
{
|
|
SqlCommand cmd = new SqlCommand();
|
|
|
|
cmd.CommandText = "[dbo].[GetInvokedWorkflows]";
|
|
cmd.CommandType = CommandType.StoredProcedure;
|
|
|
|
SqlParameter param = new SqlParameter("@WorkflowInstanceId", SqlDbType.UniqueIdentifier);
|
|
param.Value = _id;
|
|
cmd.Parameters.Add(param);
|
|
|
|
param = new SqlParameter("@BeginDateTime", SqlDbType.DateTime);
|
|
param.Value = _invMinDT;
|
|
cmd.Parameters.Add(param);
|
|
|
|
param = new SqlParameter("@EndDateTime", SqlDbType.DateTime);
|
|
param.Value = _currDT;
|
|
cmd.Parameters.Add(param);
|
|
|
|
ExecuteRetried(cmd, LoadInvokedWorkflowsFromReader);
|
|
}
|
|
|
|
private void LoadInvokedWorkflowsFromReader(SqlDataReader reader, object parameter)
|
|
{
|
|
if (null == reader)
|
|
throw new ArgumentNullException("reader");
|
|
|
|
DateTime tmpMin = SqlDateTime.MinValue.Value;
|
|
while (reader.Read())
|
|
{
|
|
SqlTrackingWorkflowInstance inst = SqlTrackingQuery.BuildInstance(reader, _connectionString);
|
|
|
|
if (inst.Initialized > tmpMin)
|
|
tmpMin = inst.Initialized;
|
|
|
|
_invoked.Add(inst);
|
|
}
|
|
//
|
|
// set the min for the next query to the most recently invoked instance from this query
|
|
// Don't overwrite the previous min if nothing came back for this query
|
|
if (tmpMin > SqlDateTime.MinValue.Value)
|
|
_invMinDT = tmpMin;
|
|
}
|
|
|
|
private void ExecuteRetried(SqlCommand cmd, LoadFromReader loader)
|
|
{
|
|
ExecuteRetried(cmd, loader, null);
|
|
}
|
|
|
|
private void ExecuteRetried(SqlCommand cmd, LoadFromReader loader, object loadFromReaderParam)
|
|
{
|
|
SqlDataReader reader = null;
|
|
short count = 0;
|
|
while (true)
|
|
{
|
|
try
|
|
{
|
|
using (SqlConnection conn = new SqlConnection(_connectionString))
|
|
{
|
|
cmd.Connection = conn;
|
|
cmd.Connection.Open();
|
|
reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
|
|
loader(reader, loadFromReaderParam);
|
|
break;
|
|
}
|
|
}
|
|
catch (SqlException se)
|
|
{
|
|
//
|
|
// Retry if we deadlocked.
|
|
// All other exceptions bubble
|
|
if ((_deadlock == se.Number) && (++count < _retries))
|
|
continue;
|
|
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
if ((null != reader) && (!reader.IsClosed))
|
|
reader.Close();
|
|
}
|
|
}
|
|
}
|
|
|
|
private SqlCommand CreateInternalIdDateTimeCommand(string commandText, DateTime minDT)
|
|
{
|
|
return CreateInternalIdDateTimeCommand(commandText, minDT, _currDT);
|
|
}
|
|
|
|
private SqlCommand CreateInternalIdDateTimeCommand(string commandText, DateTime minDT, DateTime maxDT)
|
|
{
|
|
if (null == commandText)
|
|
throw new ArgumentNullException("commandText");
|
|
|
|
SqlCommand cmd = new SqlCommand();
|
|
cmd.CommandType = CommandType.StoredProcedure;
|
|
cmd.CommandText = commandText;
|
|
//
|
|
// Add parameter values for GetActivityEvents
|
|
SqlParameter param = new SqlParameter("@WorkflowInstanceInternalId", SqlDbType.BigInt);
|
|
param.Value = _internalId;
|
|
cmd.Parameters.Add(param);
|
|
|
|
param = new SqlParameter("@BeginDateTime", SqlDbType.DateTime);
|
|
param.Value = minDT;
|
|
cmd.Parameters.Add(param);
|
|
|
|
param = new SqlParameter("@EndDateTime", SqlDbType.DateTime);
|
|
param.Value = maxDT;
|
|
cmd.Parameters.Add(param);
|
|
|
|
return cmd;
|
|
}
|
|
|
|
}
|
|
}
|