e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
607 lines
35 KiB
C#
607 lines
35 KiB
C#
//-----------------------------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
namespace System.Activities.DurableInstancing
|
|
{
|
|
using System.Activities.Hosting;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Data;
|
|
using System.Data.SqlClient;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
using System.Runtime;
|
|
using System.Runtime.DurableInstancing;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Transactions;
|
|
using System.Xml;
|
|
using System.Xml.Linq;
|
|
|
|
sealed class SaveWorkflowAsyncResult : SqlWorkflowInstanceStoreAsyncResult
|
|
{
|
|
const string createServiceDeploymentStoredProcedureParameters = @"@serviceDeploymentHash, @siteName, @relativeServicePath, @relativeApplicationPath,
|
|
@serviceName, @serviceNamespace, @serviceDeploymentId output";
|
|
|
|
const string storedProcedureParameters40 = @"@instanceId, @surrogateLockOwnerId, @handleInstanceVersion, @handleIsBoundToLock,
|
|
@primitiveDataProperties, @complexDataProperties, @writeOnlyPrimitiveDataProperties, @writeOnlyComplexDataProperties, @metadataProperties,
|
|
@metadataIsConsistent, @encodingOption, @timerDurationMilliseconds, @suspensionStateChange, @suspensionReason, @suspensionExceptionName, @keysToAssociate,
|
|
@keysToComplete, @keysToFree, @concatenatedKeyProperties, @unlockInstance, @isReadyToRun, @isCompleted, @singleKeyId,
|
|
@lastMachineRunOn, @executionStatus, @blockingBookmarks, @workflowHostType, @serviceDeploymentId, @operationTimeout";
|
|
|
|
const string storedProcedureParameters = @"@instanceId, @surrogateLockOwnerId, @handleInstanceVersion, @handleIsBoundToLock,
|
|
@primitiveDataProperties, @complexDataProperties, @writeOnlyPrimitiveDataProperties, @writeOnlyComplexDataProperties, @metadataProperties,
|
|
@metadataIsConsistent, @encodingOption, @timerDurationMilliseconds, @suspensionStateChange, @suspensionReason, @suspensionExceptionName, @keysToAssociate,
|
|
@keysToComplete, @keysToFree, @concatenatedKeyProperties, @unlockInstance, @isReadyToRun, @isCompleted, @singleKeyId,
|
|
@lastMachineRunOn, @executionStatus, @blockingBookmarks, @workflowHostType, @serviceDeploymentId, @operationTimeout, @identityMetadata";
|
|
|
|
static Dictionary<Guid, long> serviceDeploymentIdsCache = new Dictionary<Guid, long>();
|
|
static ReaderWriterLockSlim serviceDeploymentIdsCacheLock = new ReaderWriterLockSlim();
|
|
string commandText;
|
|
|
|
Guid serviceDeploymentHash;
|
|
long serviceDeploymentId;
|
|
|
|
public SaveWorkflowAsyncResult
|
|
(
|
|
InstancePersistenceContext context,
|
|
InstancePersistenceCommand command,
|
|
SqlWorkflowInstanceStore store,
|
|
SqlWorkflowInstanceStoreLock storeLock,
|
|
Transaction currentTransaction,
|
|
TimeSpan timeout,
|
|
AsyncCallback callback,
|
|
object state
|
|
) :
|
|
base(context, command, store, storeLock, currentTransaction, timeout, callback, state)
|
|
{
|
|
if (((SaveWorkflowCommand)command).InstanceKeyMetadataChanges.Count > 0)
|
|
{
|
|
throw FxTrace.Exception.AsError(new InstancePersistenceCommandException(SR.InstanceKeyMetadataChangesNotSupported));
|
|
}
|
|
}
|
|
|
|
protected override void GenerateSqlCommand(SqlCommand command)
|
|
{
|
|
SaveWorkflowCommand saveWorkflowCommand = base.InstancePersistenceCommand as SaveWorkflowCommand;
|
|
StringBuilder commandTextBuilder = new StringBuilder(SqlWorkflowInstanceStoreConstants.DefaultStringBuilderCapacity);
|
|
double operationTimeout = this.TimeoutHelper.RemainingTime().TotalMilliseconds;
|
|
SqlParameterCollection parameters = command.Parameters;
|
|
string suspensionReason;
|
|
string suspensionExceptionName;
|
|
|
|
parameters.Add(new SqlParameter { ParameterName = "@instanceId", SqlDbType = SqlDbType.UniqueIdentifier, Value = base.InstancePersistenceContext.InstanceView.InstanceId });
|
|
parameters.Add(new SqlParameter { ParameterName = "@surrogateLockOwnerId", SqlDbType = SqlDbType.BigInt, Value = base.StoreLock.SurrogateLockOwnerId });
|
|
parameters.Add(new SqlParameter { ParameterName = "@handleInstanceVersion", SqlDbType = SqlDbType.BigInt, Value = base.InstancePersistenceContext.InstanceVersion });
|
|
parameters.Add(new SqlParameter { ParameterName = "@handleIsBoundToLock", SqlDbType = SqlDbType.Bit, Value = base.InstancePersistenceContext.InstanceView.IsBoundToLock });
|
|
parameters.Add(new SqlParameter { ParameterName = "@timerDurationMilliseconds", SqlDbType = SqlDbType.BigInt, Value = (object)GetPendingTimerExpiration(saveWorkflowCommand) ?? DBNull.Value });
|
|
parameters.Add(new SqlParameter { ParameterName = "@unlockInstance", SqlDbType = SqlDbType.Bit, Value = saveWorkflowCommand.UnlockInstance });
|
|
parameters.Add(new SqlParameter { ParameterName = "@suspensionStateChange", SqlDbType = SqlDbType.TinyInt, Value = GetSuspensionReason(saveWorkflowCommand, out suspensionReason, out suspensionExceptionName) });
|
|
parameters.Add(new SqlParameter { ParameterName = "@suspensionReason", SqlDbType = SqlDbType.NVarChar, Value = (object)suspensionReason ?? DBNull.Value });
|
|
parameters.Add(new SqlParameter { ParameterName = "@suspensionExceptionName", SqlDbType = SqlDbType.NVarChar, Size = 450, Value = (object)suspensionExceptionName ?? DBNull.Value });
|
|
parameters.Add(new SqlParameter { ParameterName = "@isCompleted", SqlDbType = SqlDbType.Bit, Value = saveWorkflowCommand.CompleteInstance });
|
|
parameters.Add(new SqlParameter { ParameterName = "@isReadyToRun", SqlDbType = SqlDbType.Bit, Value = IsReadyToRun(saveWorkflowCommand) });
|
|
parameters.Add(new SqlParameter { ParameterName = "@workflowHostType", SqlDbType = SqlDbType.UniqueIdentifier, Value = (object)GetWorkflowHostType(saveWorkflowCommand) ?? DBNull.Value });
|
|
parameters.Add(new SqlParameter { ParameterName = "@operationTimeout", SqlDbType = SqlDbType.Int, Value = (operationTimeout < Int32.MaxValue) ? Convert.ToInt32(operationTimeout) : Int32.MaxValue });
|
|
|
|
string parameterNames = null;
|
|
if (base.Store.DatabaseVersion >= StoreUtilities.Version45)
|
|
{
|
|
string identityMetadataXml = SerializationUtilities.GetIdentityMetadataXml(saveWorkflowCommand);
|
|
parameters.Add(new SqlParameter { ParameterName = "@identityMetadata", SqlDbType = SqlDbType.Xml, Value = (object)identityMetadataXml ?? DBNull.Value });
|
|
|
|
parameterNames = SaveWorkflowAsyncResult.storedProcedureParameters;
|
|
}
|
|
else
|
|
{
|
|
parameterNames = SaveWorkflowAsyncResult.storedProcedureParameters40;
|
|
}
|
|
|
|
commandTextBuilder.AppendLine(@"set nocount on
|
|
set transaction isolation level read committed
|
|
set xact_abort on
|
|
begin transaction");
|
|
|
|
ExtractServiceDeploymentInformation(saveWorkflowCommand, commandTextBuilder, parameters);
|
|
|
|
commandTextBuilder.AppendLine("declare @result int");
|
|
commandTextBuilder.AppendLine(string.Format(CultureInfo.InvariantCulture, "exec @result = {0}.[SaveInstance] {1} ;",
|
|
SqlWorkflowInstanceStoreConstants.DefaultSchema, parameterNames));
|
|
commandTextBuilder.AppendLine("if (@result = 0)");
|
|
commandTextBuilder.AppendLine("begin");
|
|
|
|
SerializeAssociatedData(parameters, saveWorkflowCommand, commandTextBuilder);
|
|
|
|
commandTextBuilder.AppendLine("commit transaction");
|
|
commandTextBuilder.AppendLine("end");
|
|
commandTextBuilder.AppendLine("else");
|
|
commandTextBuilder.AppendLine("rollback transaction");
|
|
|
|
this.commandText = commandTextBuilder.ToString();
|
|
}
|
|
|
|
protected override string GetSqlCommandText()
|
|
{
|
|
return this.commandText;
|
|
}
|
|
|
|
protected override CommandType GetSqlCommandType()
|
|
{
|
|
return CommandType.Text;
|
|
}
|
|
|
|
protected override Exception ProcessSqlResult(SqlDataReader reader)
|
|
{
|
|
Exception exception = StoreUtilities.GetNextResultSet(base.InstancePersistenceCommand.Name, reader);
|
|
|
|
if (exception == null)
|
|
{
|
|
SaveWorkflowCommand saveWorkflowCommand = base.InstancePersistenceCommand as SaveWorkflowCommand;
|
|
InstanceLockTracking instanceLockTracking = (InstanceLockTracking)(base.InstancePersistenceContext.UserContext);
|
|
if ((this.serviceDeploymentHash != Guid.Empty) && (this.serviceDeploymentId == 0))
|
|
{
|
|
this.serviceDeploymentId = reader.GetInt64(1);
|
|
PutServiceDeploymentId();
|
|
exception = StoreUtilities.GetNextResultSet(base.InstancePersistenceCommand.Name, reader);
|
|
}
|
|
|
|
if (exception == null)
|
|
{
|
|
if (!base.InstancePersistenceContext.InstanceView.IsBoundToLock)
|
|
{
|
|
long instanceVersion = reader.GetInt64(1);
|
|
instanceLockTracking.TrackStoreLock(base.InstancePersistenceContext.InstanceView.InstanceId, instanceVersion, this.DependentTransaction);
|
|
base.InstancePersistenceContext.BindAcquiredLock(instanceVersion);
|
|
}
|
|
|
|
if (saveWorkflowCommand.InstanceData.Count > 0)
|
|
{
|
|
base.InstancePersistenceContext.PersistedInstance(saveWorkflowCommand.InstanceData);
|
|
}
|
|
|
|
SaveWorkflowAsyncResult.UpdateKeyData(base.InstancePersistenceContext, saveWorkflowCommand);
|
|
|
|
foreach (KeyValuePair<XName, InstanceValue> property in saveWorkflowCommand.InstanceMetadataChanges)
|
|
{
|
|
base.InstancePersistenceContext.WroteInstanceMetadataValue(property.Key, property.Value);
|
|
}
|
|
|
|
if (saveWorkflowCommand.CompleteInstance)
|
|
{
|
|
base.InstancePersistenceContext.CompletedInstance();
|
|
}
|
|
|
|
if (saveWorkflowCommand.UnlockInstance || saveWorkflowCommand.CompleteInstance)
|
|
{
|
|
instanceLockTracking.TrackStoreUnlock(this.DependentTransaction);
|
|
base.InstancePersistenceContext.InstanceHandle.Free();
|
|
}
|
|
}
|
|
else if (exception is InstanceLockLostException)
|
|
{
|
|
base.InstancePersistenceContext.InstanceHandle.Free();
|
|
}
|
|
}
|
|
|
|
return exception;
|
|
}
|
|
|
|
static void AddSerializedProperty(ArraySegment<byte> source, SqlParameterCollection parameters, string parameterName)
|
|
{
|
|
int parameterSize = source.Count > 8000 ? source.Count : -1;
|
|
object parameterValue = (parameterSize == -1 ? SaveWorkflowAsyncResult.GenerateByteArray(source) : source.Array) ?? (object)DBNull.Value;
|
|
parameters.Add(new SqlParameter { ParameterName = parameterName, SqlDbType = SqlDbType.VarBinary, Size = parameterSize, Value = parameterValue });
|
|
}
|
|
|
|
static byte[] GenerateByteArray(ArraySegment<byte> source)
|
|
{
|
|
if (source.Array != null)
|
|
{
|
|
byte[] destination = new byte[source.Count];
|
|
Buffer.BlockCopy(source.Array, 0, destination, 0, source.Count);
|
|
return destination;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
static string GetBlockingBookmarks(SaveWorkflowCommand saveWorkflowCommand)
|
|
{
|
|
string blockingBookmarks = null;
|
|
InstanceValue binaryBlockingBookmarks;
|
|
|
|
if (saveWorkflowCommand.InstanceData.TryGetValue(SqlWorkflowInstanceStoreConstants.BinaryBlockingBookmarksPropertyName, out binaryBlockingBookmarks))
|
|
{
|
|
StringBuilder bookmarkListBuilder = new StringBuilder(SqlWorkflowInstanceStoreConstants.DefaultStringBuilderCapacity);
|
|
IEnumerable<BookmarkInfo> activeBookmarks = binaryBlockingBookmarks.Value as IEnumerable<BookmarkInfo>;
|
|
|
|
foreach (BookmarkInfo bookmarkInfo in activeBookmarks)
|
|
{
|
|
bookmarkListBuilder.AppendFormat(CultureInfo.InvariantCulture, "[{0}: {1}]{2}", bookmarkInfo.BookmarkName, bookmarkInfo.OwnerDisplayName, Environment.NewLine);
|
|
}
|
|
|
|
blockingBookmarks = bookmarkListBuilder.ToString();
|
|
}
|
|
|
|
return blockingBookmarks;
|
|
}
|
|
|
|
static string GetExecutionStatus(SaveWorkflowCommand saveWorkflowCommand)
|
|
{
|
|
string executionStatus = null;
|
|
InstanceValue executionStatusProperty;
|
|
|
|
if (saveWorkflowCommand.InstanceData.TryGetValue(SqlWorkflowInstanceStoreConstants.StatusPropertyName, out executionStatusProperty))
|
|
{
|
|
executionStatus = (string)executionStatusProperty.Value;
|
|
}
|
|
|
|
return executionStatus;
|
|
}
|
|
|
|
static Int64? GetPendingTimerExpiration(SaveWorkflowCommand saveWorkflowCommand)
|
|
{
|
|
InstanceValue pendingTimerExpirationPropertyValue;
|
|
|
|
if (saveWorkflowCommand.InstanceData.TryGetValue(SqlWorkflowInstanceStoreConstants.PendingTimerExpirationPropertyName, out pendingTimerExpirationPropertyValue))
|
|
{
|
|
DateTime pendingTimerExpiration = ((DateTime)pendingTimerExpirationPropertyValue.Value).ToUniversalTime();
|
|
TimeSpan datetimeOffset = pendingTimerExpiration - DateTime.UtcNow;
|
|
|
|
return (Int64)datetimeOffset.TotalMilliseconds;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
static SuspensionStateChange GetSuspensionReason(SaveWorkflowCommand saveWorkflowCommand, out string suspensionReason, out string suspensionExceptionName)
|
|
{
|
|
IDictionary<XName, InstanceValue> instanceMetadataChanges = saveWorkflowCommand.InstanceMetadataChanges;
|
|
SuspensionStateChange suspensionStateChange = SuspensionStateChange.NoChange;
|
|
InstanceValue propertyValue;
|
|
suspensionReason = null;
|
|
suspensionExceptionName = null;
|
|
|
|
if (instanceMetadataChanges.TryGetValue(WorkflowServiceNamespace.SuspendReason, out propertyValue))
|
|
{
|
|
if (!propertyValue.IsDeletedValue)
|
|
{
|
|
suspensionStateChange = SuspensionStateChange.SuspendInstance;
|
|
suspensionReason = (string)propertyValue.Value;
|
|
|
|
if (instanceMetadataChanges.TryGetValue(WorkflowServiceNamespace.SuspendException, out propertyValue) && !propertyValue.IsDeletedValue)
|
|
{
|
|
suspensionExceptionName = ((Exception)propertyValue.Value).GetType().ToString();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
suspensionStateChange = SuspensionStateChange.UnsuspendInstance;
|
|
}
|
|
}
|
|
|
|
return suspensionStateChange;
|
|
}
|
|
|
|
static Guid? GetWorkflowHostType(SaveWorkflowCommand saveWorkflowCommand)
|
|
{
|
|
InstanceValue instanceValue;
|
|
if (saveWorkflowCommand.InstanceMetadataChanges.TryGetValue(WorkflowNamespace.WorkflowHostType, out instanceValue))
|
|
{
|
|
XName workflowHostType = instanceValue.Value as XName;
|
|
|
|
if (workflowHostType == null)
|
|
{
|
|
throw FxTrace.Exception.AsError(new InstancePersistenceCommandException(SR.InvalidMetadataValue(WorkflowNamespace.WorkflowHostType, typeof(XName).Name)));
|
|
}
|
|
byte[] workflowHostTypeBuffer = Encoding.Unicode.GetBytes(((XName)instanceValue.Value).ToString());
|
|
return new Guid(HashHelper.ComputeHash(workflowHostTypeBuffer));
|
|
}
|
|
return null;
|
|
}
|
|
|
|
static bool IsReadyToRun(SaveWorkflowCommand saveWorkflowCommand)
|
|
{
|
|
InstanceValue statusPropertyValue;
|
|
|
|
if (saveWorkflowCommand.InstanceData.TryGetValue(SqlWorkflowInstanceStoreConstants.StatusPropertyName, out statusPropertyValue) &&
|
|
((string)statusPropertyValue.Value) == SqlWorkflowInstanceStoreConstants.ExecutingStatusPropertyValue)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static void UpdateKeyData(InstancePersistenceContext context, SaveWorkflowCommand saveWorkflowCommand)
|
|
{
|
|
InstanceView instanceView = context.InstanceView;
|
|
|
|
foreach (KeyValuePair<Guid, IDictionary<XName, InstanceValue>> keyEntry in saveWorkflowCommand.InstanceKeysToAssociate)
|
|
{
|
|
if (!instanceView.InstanceKeys.ContainsKey(keyEntry.Key))
|
|
{
|
|
context.AssociatedInstanceKey(keyEntry.Key);
|
|
|
|
if (keyEntry.Value != null)
|
|
{
|
|
foreach (KeyValuePair<XName, InstanceValue> property in keyEntry.Value)
|
|
{
|
|
context.WroteInstanceKeyMetadataValue(keyEntry.Key, property.Key, property.Value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (Guid key in saveWorkflowCommand.InstanceKeysToComplete)
|
|
{
|
|
InstanceKeyView existingKeyView;
|
|
if (instanceView.InstanceKeys.TryGetValue(key, out existingKeyView))
|
|
{
|
|
if (existingKeyView.InstanceKeyState != InstanceKeyState.Completed)
|
|
{
|
|
context.CompletedInstanceKey(key);
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (Guid key in saveWorkflowCommand.InstanceKeysToFree)
|
|
{
|
|
InstanceKeyView existingKeyView;
|
|
if (instanceView.InstanceKeys.TryGetValue(key, out existingKeyView))
|
|
{
|
|
context.UnassociatedInstanceKey(key);
|
|
}
|
|
}
|
|
|
|
foreach (KeyValuePair<Guid, IDictionary<XName, InstanceValue>> keyEntry in saveWorkflowCommand.InstanceKeyMetadataChanges)
|
|
{
|
|
if (keyEntry.Value != null)
|
|
{
|
|
foreach (KeyValuePair<XName, InstanceValue> property in keyEntry.Value)
|
|
{
|
|
context.WroteInstanceKeyMetadataValue(keyEntry.Key, property.Key, property.Value);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (saveWorkflowCommand.CompleteInstance)
|
|
{
|
|
foreach (KeyValuePair<Guid, InstanceKeyView> instanceKeys in instanceView.InstanceKeys)
|
|
{
|
|
if (instanceKeys.Value != null)
|
|
{
|
|
if (instanceKeys.Value.InstanceKeyState == InstanceKeyState.Associated)
|
|
{
|
|
context.CompletedInstanceKey(instanceKeys.Key);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ExtractServiceDeploymentInformation(SaveWorkflowCommand saveWorkflowCommand, StringBuilder commandTextBuilder, SqlParameterCollection parameters)
|
|
{
|
|
InstanceValue instanceValue;
|
|
//Extract the activation parameters
|
|
string serviceName = null;
|
|
string serviceNamespace = null;
|
|
string site = null;
|
|
string relativeApplicationPath = null;
|
|
string relativeServicePath = null;
|
|
|
|
if (saveWorkflowCommand.InstanceMetadataChanges.TryGetValue(PersistenceMetadataNamespace.ActivationType, out instanceValue))
|
|
{
|
|
if (PersistenceMetadataNamespace.ActivationTypes.WAS.Equals(instanceValue.Value))
|
|
{
|
|
if (saveWorkflowCommand.InstanceMetadataChanges.TryGetValue(WorkflowServiceNamespace.Service, out instanceValue))
|
|
{
|
|
serviceName = ((XName)instanceValue.Value).LocalName;
|
|
serviceNamespace = ((XName)instanceValue.Value).Namespace.NamespaceName;
|
|
}
|
|
if (saveWorkflowCommand.InstanceMetadataChanges.TryGetValue(WorkflowServiceNamespace.SiteName, out instanceValue))
|
|
{
|
|
site = (string)instanceValue.Value;
|
|
}
|
|
if (saveWorkflowCommand.InstanceMetadataChanges.TryGetValue(WorkflowServiceNamespace.RelativeApplicationPath, out instanceValue))
|
|
{
|
|
relativeApplicationPath = (string)instanceValue.Value;
|
|
}
|
|
if (saveWorkflowCommand.InstanceMetadataChanges.TryGetValue(WorkflowServiceNamespace.RelativeServicePath, out instanceValue))
|
|
{
|
|
relativeServicePath = (string)instanceValue.Value;
|
|
}
|
|
|
|
byte[] serviceDeploymentHashBuffer = Encoding.Unicode.GetBytes(string.Format(CultureInfo.InvariantCulture, "{0}#{1}#{2}#{3}#{4}",
|
|
serviceName ?? string.Empty, serviceNamespace ?? string.Empty, site ?? string.Empty, relativeApplicationPath ?? string.Empty, relativeServicePath ?? string.Empty));
|
|
this.serviceDeploymentHash = new Guid(HashHelper.ComputeHash(serviceDeploymentHashBuffer));
|
|
|
|
//Get the service id has been seen before, get it from the cache
|
|
GetServiceDeploymentId();
|
|
}
|
|
else
|
|
{
|
|
throw FxTrace.Exception.AsError(new InstancePersistenceCommandException(SR.NonWASActivationNotSupported));
|
|
}
|
|
}
|
|
|
|
if ((this.serviceDeploymentHash != Guid.Empty) && (this.serviceDeploymentId == 0))
|
|
{
|
|
//This is the first time we see this service deployment so we need to create a new entry for it before creating the instance
|
|
commandTextBuilder.AppendLine("declare @serviceDeploymentId bigint");
|
|
commandTextBuilder.AppendLine(string.Format(CultureInfo.InvariantCulture, "exec {0}.[CreateServiceDeployment] {1} ;",
|
|
SqlWorkflowInstanceStoreConstants.DefaultSchema, SaveWorkflowAsyncResult.createServiceDeploymentStoredProcedureParameters));
|
|
|
|
parameters.Add(new SqlParameter { ParameterName = "@serviceDeploymentHash", SqlDbType = SqlDbType.UniqueIdentifier, Value = this.serviceDeploymentHash });
|
|
parameters.Add(new SqlParameter { ParameterName = "@serviceName", Size = -1, SqlDbType = SqlDbType.NVarChar, Value = serviceName ?? (object)DBNull.Value });
|
|
parameters.Add(new SqlParameter { ParameterName = "@serviceNamespace", Size = -1, SqlDbType = SqlDbType.NVarChar, Value = serviceNamespace ?? (object)DBNull.Value });
|
|
parameters.Add(new SqlParameter { ParameterName = "@siteName", Size = -1, SqlDbType = SqlDbType.NVarChar, Value = site ?? (object)DBNull.Value });
|
|
parameters.Add(new SqlParameter { ParameterName = "@relativeServicePath", Size = -1, SqlDbType = SqlDbType.NVarChar, Value = relativeServicePath ?? (object)DBNull.Value });
|
|
parameters.Add(new SqlParameter { ParameterName = "@relativeApplicationPath", Size = -1, SqlDbType = SqlDbType.NVarChar, Value = relativeApplicationPath ?? (object)DBNull.Value });
|
|
}
|
|
else
|
|
{
|
|
parameters.Add(new SqlParameter { ParameterName = "@serviceDeploymentId", SqlDbType = SqlDbType.BigInt, Value = (this.serviceDeploymentId != 0) ? (object)this.serviceDeploymentId : (object)DBNull.Value });
|
|
}
|
|
}
|
|
|
|
void GetServiceDeploymentId()
|
|
{
|
|
try
|
|
{
|
|
SaveWorkflowAsyncResult.serviceDeploymentIdsCacheLock.EnterReadLock();
|
|
SaveWorkflowAsyncResult.serviceDeploymentIdsCache.TryGetValue(this.serviceDeploymentHash, out this.serviceDeploymentId);
|
|
}
|
|
finally
|
|
{
|
|
SaveWorkflowAsyncResult.serviceDeploymentIdsCacheLock.ExitReadLock();
|
|
}
|
|
}
|
|
|
|
void PutServiceDeploymentId()
|
|
{
|
|
try
|
|
{
|
|
serviceDeploymentIdsCacheLock.EnterWriteLock();
|
|
serviceDeploymentIdsCache[this.serviceDeploymentHash] = this.serviceDeploymentId;
|
|
}
|
|
finally
|
|
{
|
|
serviceDeploymentIdsCacheLock.ExitWriteLock();
|
|
}
|
|
}
|
|
|
|
void SerializeAssociatedData(SqlParameterCollection parameters, SaveWorkflowCommand saveWorkflowCommand, StringBuilder commandTextBuilder)
|
|
{
|
|
if (saveWorkflowCommand.CompleteInstance && base.Store.InstanceCompletionAction == InstanceCompletionAction.DeleteAll)
|
|
{
|
|
parameters.Add(new SqlParameter { ParameterName = "@keysToAssociate", SqlDbType = SqlDbType.Xml, Value = DBNull.Value });
|
|
parameters.Add(new SqlParameter { ParameterName = "@singleKeyId", SqlDbType = SqlDbType.UniqueIdentifier, Value = DBNull.Value });
|
|
parameters.Add(new SqlParameter { ParameterName = "@keysToComplete", SqlDbType = SqlDbType.Xml, Value = DBNull.Value });
|
|
parameters.Add(new SqlParameter { ParameterName = "@keysToFree", SqlDbType = SqlDbType.Xml, Value = DBNull.Value });
|
|
parameters.Add(new SqlParameter { ParameterName = "@concatenatedKeyProperties", SqlDbType = SqlDbType.VarBinary, Value = DBNull.Value });
|
|
parameters.Add(new SqlParameter { ParameterName = "@primitiveDataProperties", SqlDbType = SqlDbType.VarBinary, Value = DBNull.Value });
|
|
parameters.Add(new SqlParameter { ParameterName = "@complexDataProperties", SqlDbType = SqlDbType.VarBinary, Value = DBNull.Value });
|
|
parameters.Add(new SqlParameter { ParameterName = "@writeOnlyPrimitiveDataProperties", SqlDbType = SqlDbType.VarBinary, Value = DBNull.Value });
|
|
parameters.Add(new SqlParameter { ParameterName = "@writeOnlyComplexDataProperties", SqlDbType = SqlDbType.VarBinary, Value = DBNull.Value });
|
|
parameters.Add(new SqlParameter { ParameterName = "@metadataProperties", SqlDbType = SqlDbType.VarBinary, Value = DBNull.Value });
|
|
parameters.Add(new SqlParameter { ParameterName = "@metadataIsConsistent", SqlDbType = SqlDbType.Bit, Value = DBNull.Value });
|
|
parameters.Add(new SqlParameter { ParameterName = "@encodingOption", SqlDbType = SqlDbType.TinyInt, Value = DBNull.Value });
|
|
parameters.Add(new SqlParameter { ParameterName = "@lastMachineRunOn", SqlDbType = SqlDbType.NVarChar, Value = DBNull.Value });
|
|
parameters.Add(new SqlParameter { ParameterName = "@executionStatus", SqlDbType = SqlDbType.NVarChar, Value = DBNull.Value });
|
|
parameters.Add(new SqlParameter { ParameterName = "@blockingBookmarks", SqlDbType = SqlDbType.NVarChar, Value = DBNull.Value });
|
|
|
|
return;
|
|
}
|
|
|
|
List<CorrelationKey> keysToAssociate = CorrelationKey.BuildKeyList(saveWorkflowCommand.InstanceKeysToAssociate, base.Store.InstanceEncodingOption);
|
|
List<CorrelationKey> keysToComplete = CorrelationKey.BuildKeyList(saveWorkflowCommand.InstanceKeysToComplete);
|
|
List<CorrelationKey> keysToFree = CorrelationKey.BuildKeyList(saveWorkflowCommand.InstanceKeysToFree);
|
|
ArraySegment<byte>[] dataProperties = SerializationUtilities.SerializePropertyBag(saveWorkflowCommand.InstanceData, base.Store.InstanceEncodingOption);
|
|
ArraySegment<byte> metadataProperties = SerializationUtilities.SerializeMetadataPropertyBag(saveWorkflowCommand, base.InstancePersistenceContext, base.Store.InstanceEncodingOption);
|
|
byte[] concatenatedKeyProperties = SerializationUtilities.CreateKeyBinaryBlob(keysToAssociate);
|
|
bool metadataConsistency = (base.InstancePersistenceContext.InstanceView.InstanceMetadataConsistency == InstanceValueConsistency.None);
|
|
bool singleKeyToAssociate = (keysToAssociate != null && keysToAssociate.Count == 1);
|
|
|
|
parameters.Add(new SqlParameter { ParameterName = "@keysToAssociate", SqlDbType = SqlDbType.Xml, Value = singleKeyToAssociate ? DBNull.Value : SerializationUtilities.CreateCorrelationKeyXmlBlob(keysToAssociate) });
|
|
parameters.Add(new SqlParameter { ParameterName = "@singleKeyId", SqlDbType = SqlDbType.UniqueIdentifier, Value = singleKeyToAssociate ? keysToAssociate[0].KeyId : (object)DBNull.Value });
|
|
parameters.Add(new SqlParameter { ParameterName = "@keysToComplete", SqlDbType = SqlDbType.Xml, Value = SerializationUtilities.CreateCorrelationKeyXmlBlob(keysToComplete) });
|
|
parameters.Add(new SqlParameter { ParameterName = "@keysToFree", SqlDbType = SqlDbType.Xml, Value = SerializationUtilities.CreateCorrelationKeyXmlBlob(keysToFree) });
|
|
parameters.Add(new SqlParameter { ParameterName = "@concatenatedKeyProperties", SqlDbType = SqlDbType.VarBinary, Size = -1, Value = (object)concatenatedKeyProperties ?? DBNull.Value });
|
|
parameters.Add(new SqlParameter { ParameterName = "@metadataIsConsistent", SqlDbType = SqlDbType.Bit, Value = metadataConsistency });
|
|
parameters.Add(new SqlParameter { ParameterName = "@encodingOption", SqlDbType = SqlDbType.TinyInt, Value = base.Store.InstanceEncodingOption });
|
|
parameters.Add(new SqlParameter { ParameterName = "@lastMachineRunOn", SqlDbType = SqlDbType.NVarChar, Size = 450, Value = SqlWorkflowInstanceStoreConstants.MachineName });
|
|
parameters.Add(new SqlParameter { ParameterName = "@executionStatus", SqlDbType = SqlDbType.NVarChar, Size = 450, Value = GetExecutionStatus(saveWorkflowCommand) ?? (object)DBNull.Value });
|
|
parameters.Add(new SqlParameter { ParameterName = "@blockingBookmarks", SqlDbType = SqlDbType.NVarChar, Size = -1, Value = GetBlockingBookmarks(saveWorkflowCommand) ?? (object)DBNull.Value });
|
|
|
|
ArraySegment<byte>[] properties = { dataProperties[0], dataProperties[1], dataProperties[2], dataProperties[3], metadataProperties };
|
|
string[] dataPropertyParameters = { "@primitiveDataProperties", "@complexDataProperties", "@writeOnlyPrimitiveDataProperties", @"writeOnlyComplexDataProperties", "@metadataProperties" };
|
|
|
|
for (int i = 0; i < 5; i++)
|
|
{
|
|
SaveWorkflowAsyncResult.AddSerializedProperty(properties[i], parameters, dataPropertyParameters[i]);
|
|
}
|
|
|
|
this.SerializePromotedProperties(parameters, commandTextBuilder, saveWorkflowCommand);
|
|
}
|
|
|
|
void SerializePromotedProperties(SqlParameterCollection parameters, StringBuilder commandTextBuilder, SaveWorkflowCommand saveWorkflowCommand)
|
|
{
|
|
const int SqlVariantStartColumn = 1;
|
|
const string promotionNameParameter = "@promotionName=";
|
|
const string instanceIdParameter = "@instanceId=";
|
|
int promotionNumber = 0;
|
|
|
|
foreach (KeyValuePair<string, Tuple<List<XName>, List<XName>>> promotion in base.Store.Promotions)
|
|
{
|
|
StringBuilder storedProcInvocationBuilder = new StringBuilder(SqlWorkflowInstanceStoreConstants.DefaultStringBuilderCapacity);
|
|
int column = SqlVariantStartColumn;
|
|
bool addPromotion = false;
|
|
string promotionNameArgument = string.Format(CultureInfo.InvariantCulture, "@promotionName{0}", promotionNumber);
|
|
string instanceIdArgument = string.Format(CultureInfo.InvariantCulture, "@instanceId{0}", promotionNumber);
|
|
|
|
storedProcInvocationBuilder.Append(string.Format(CultureInfo.InvariantCulture, "exec {0}.[InsertPromotedProperties] ", SqlWorkflowInstanceStoreConstants.DefaultSchema));
|
|
storedProcInvocationBuilder.Append(promotionNameParameter);
|
|
storedProcInvocationBuilder.Append(promotionNameArgument);
|
|
storedProcInvocationBuilder.Append(",");
|
|
storedProcInvocationBuilder.Append(instanceIdParameter);
|
|
storedProcInvocationBuilder.Append(instanceIdArgument);
|
|
|
|
foreach (XName name in promotion.Value.Item1)
|
|
{
|
|
InstanceValue propertyValue;
|
|
|
|
if (saveWorkflowCommand.InstanceData.TryGetValue(name, out propertyValue))
|
|
{
|
|
if (!SerializationUtilities.IsPropertyTypeSqlVariantCompatible(propertyValue))
|
|
{
|
|
throw FxTrace.Exception.AsError(new InstancePersistenceException(SR.CannotPromoteAsSqlVariant(propertyValue.Value.GetType().ToString(), name.ToString())));
|
|
}
|
|
|
|
string parameterName = string.Format(CultureInfo.InvariantCulture, "@value{0}=", column);
|
|
string argumentName = string.Format(CultureInfo.InvariantCulture, "@value{0}_promotion{1}", column, promotionNumber);
|
|
parameters.Add(new SqlParameter() { SqlDbType = SqlDbType.Variant, ParameterName = argumentName, Value = propertyValue.Value ?? DBNull.Value });
|
|
|
|
storedProcInvocationBuilder.Append(", ");
|
|
storedProcInvocationBuilder.Append(parameterName);
|
|
storedProcInvocationBuilder.Append(argumentName);
|
|
addPromotion = true;
|
|
}
|
|
column++;
|
|
}
|
|
|
|
column = SqlVariantStartColumn + SqlWorkflowInstanceStoreConstants.MaximumPropertiesPerPromotion;
|
|
|
|
foreach (XName name in promotion.Value.Item2)
|
|
{
|
|
InstanceValue propertyValue;
|
|
IObjectSerializer serializer = ObjectSerializerFactory.GetObjectSerializer(base.Store.InstanceEncodingOption);
|
|
|
|
if (saveWorkflowCommand.InstanceData.TryGetValue(name, out propertyValue))
|
|
{
|
|
string parameterName = string.Format(CultureInfo.InvariantCulture, "@value{0}=", column);
|
|
string argumentName = string.Format(CultureInfo.InvariantCulture, "@value{0}_promotion{1}", column, promotionNumber);
|
|
|
|
SaveWorkflowAsyncResult.AddSerializedProperty(serializer.SerializeValue(propertyValue.Value), parameters, argumentName);
|
|
storedProcInvocationBuilder.Append(", ");
|
|
storedProcInvocationBuilder.Append(parameterName);
|
|
storedProcInvocationBuilder.Append(argumentName);
|
|
addPromotion = true;
|
|
}
|
|
column++;
|
|
}
|
|
|
|
if (addPromotion)
|
|
{
|
|
parameters.Add(new SqlParameter() { SqlDbType = SqlDbType.NVarChar, Size = 400, ParameterName = promotionNameArgument, Value = promotion.Key });
|
|
parameters.Add(new SqlParameter() { SqlDbType = SqlDbType.UniqueIdentifier, ParameterName = instanceIdArgument, Value = base.InstancePersistenceContext.InstanceView.InstanceId });
|
|
storedProcInvocationBuilder.Append(";");
|
|
commandTextBuilder.AppendLine(storedProcInvocationBuilder.ToString());
|
|
promotionNumber++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|