1 //----------------------------------------------------------------------------- 2 // Copyright (c) Microsoft Corporation. All rights reserved. 3 //----------------------------------------------------------------------------- 4 5 namespace System.Activities.DurableInstancing 6 { 7 using System.Collections.Generic; 8 using System.Data; 9 using System.Data.SqlClient; 10 using System.Globalization; 11 using System.Linq; 12 using System.Runtime.DurableInstancing; 13 using System.Transactions; 14 using System.Xml.Linq; 15 16 class LoadWorkflowAsyncResult : SqlWorkflowInstanceStoreAsyncResult 17 { 18 static readonly string commandText = string.Format(CultureInfo.InvariantCulture, "{0}.[LoadInstance]", SqlWorkflowInstanceStoreConstants.DefaultSchema); 19 Dictionary<Guid, IDictionary<XName, InstanceValue>> associatedInstanceKeys; 20 Dictionary<Guid, IDictionary<XName, InstanceValue>> completedInstanceKeys; 21 22 Dictionary<XName, InstanceValue> instanceData; 23 Dictionary<XName, InstanceValue> instanceMetadata; 24 IObjectSerializer objectSerializer; 25 LoadWorkflowAsyncResult( InstancePersistenceContext context, InstancePersistenceCommand command, SqlWorkflowInstanceStore store, SqlWorkflowInstanceStoreLock storeLock, Transaction currentTransaction, TimeSpan timeout, AsyncCallback callback, object state )26 public LoadWorkflowAsyncResult 27 ( 28 InstancePersistenceContext context, 29 InstancePersistenceCommand command, 30 SqlWorkflowInstanceStore store, 31 SqlWorkflowInstanceStoreLock storeLock, 32 Transaction currentTransaction, 33 TimeSpan timeout, 34 AsyncCallback callback, 35 object state 36 ) : 37 base(context, command, store, storeLock, currentTransaction, timeout, callback, state) 38 { 39 this.associatedInstanceKeys = new Dictionary<Guid, IDictionary<XName, InstanceValue>>(); 40 this.completedInstanceKeys = new Dictionary<Guid, IDictionary<XName, InstanceValue>>(); 41 this.objectSerializer = ObjectSerializerFactory.GetDefaultObjectSerializer(); 42 } 43 GenerateLoadSqlCommand( SqlCommand command, LoadType loadType, Guid keyToLoadBy, Guid instanceId, List<CorrelationKey> keysToAssociate )44 protected void GenerateLoadSqlCommand 45 ( 46 SqlCommand command, 47 LoadType loadType, 48 Guid keyToLoadBy, 49 Guid instanceId, 50 List<CorrelationKey> keysToAssociate 51 ) 52 { 53 long surrogateLockOwnerId = base.StoreLock.SurrogateLockOwnerId; 54 byte[] concatenatedKeyProperties = null; 55 bool singleKeyToAssociate = (keysToAssociate != null && keysToAssociate.Count == 1); 56 57 if (keysToAssociate != null) 58 { 59 concatenatedKeyProperties = SerializationUtilities.CreateKeyBinaryBlob(keysToAssociate); 60 } 61 62 double operationTimeout = this.TimeoutHelper.RemainingTime().TotalMilliseconds; 63 64 SqlParameterCollection parameters = command.Parameters; 65 parameters.Add(new SqlParameter { ParameterName = "@surrogateLockOwnerId", SqlDbType = SqlDbType.BigInt, Value = surrogateLockOwnerId }); 66 parameters.Add(new SqlParameter { ParameterName = "@operationType", SqlDbType = SqlDbType.TinyInt, Value = loadType }); 67 parameters.Add(new SqlParameter { ParameterName = "@keyToLoadBy", SqlDbType = SqlDbType.UniqueIdentifier, Value = keyToLoadBy }); 68 parameters.Add(new SqlParameter { ParameterName = "@instanceId", SqlDbType = SqlDbType.UniqueIdentifier, Value = instanceId }); 69 parameters.Add(new SqlParameter { ParameterName = "@handleInstanceVersion", SqlDbType = SqlDbType.BigInt, Value = base.InstancePersistenceContext.InstanceVersion }); 70 parameters.Add(new SqlParameter { ParameterName = "@handleIsBoundToLock", SqlDbType = SqlDbType.Bit, Value = base.InstancePersistenceContext.InstanceView.IsBoundToLock }); 71 parameters.Add(new SqlParameter { ParameterName = "@keysToAssociate", SqlDbType = SqlDbType.Xml, Value = singleKeyToAssociate ? DBNull.Value : SerializationUtilities.CreateCorrelationKeyXmlBlob(keysToAssociate) }); 72 parameters.Add(new SqlParameter { ParameterName = "@encodingOption", SqlDbType = SqlDbType.TinyInt, Value = base.Store.InstanceEncodingOption }); 73 parameters.Add(new SqlParameter { ParameterName = "@concatenatedKeyProperties", SqlDbType = SqlDbType.VarBinary, Value = (object) concatenatedKeyProperties ?? DBNull.Value }); 74 parameters.Add(new SqlParameter { ParameterName = "@operationTimeout", SqlDbType = SqlDbType.Int, Value = (operationTimeout < Int32.MaxValue) ? Convert.ToInt32(operationTimeout) : Int32.MaxValue }); 75 parameters.Add(new SqlParameter { ParameterName = "@singleKeyId", SqlDbType = SqlDbType.UniqueIdentifier, Value = singleKeyToAssociate ? keysToAssociate[0].KeyId : (object) DBNull.Value }); 76 } 77 GenerateSqlCommand(SqlCommand command)78 protected override void GenerateSqlCommand(SqlCommand command) 79 { 80 LoadWorkflowCommand loadWorkflowCommand = base.InstancePersistenceCommand as LoadWorkflowCommand; 81 LoadType loadType = loadWorkflowCommand.AcceptUninitializedInstance ? LoadType.LoadOrCreateByInstance : LoadType.LoadByInstance; 82 Guid instanceId = base.InstancePersistenceContext.InstanceView.InstanceId; 83 84 GenerateLoadSqlCommand(command, loadType, Guid.Empty, instanceId, null); 85 } 86 GetSqlCommandText()87 protected override string GetSqlCommandText() 88 { 89 return LoadWorkflowAsyncResult.commandText; 90 } 91 GetSqlCommandType()92 protected override CommandType GetSqlCommandType() 93 { 94 return CommandType.StoredProcedure; 95 } 96 ProcessSqlResult(SqlDataReader reader)97 protected override Exception ProcessSqlResult(SqlDataReader reader) 98 { 99 Exception exception = StoreUtilities.GetNextResultSet(base.InstancePersistenceCommand.Name, reader); 100 101 if (exception == null) 102 { 103 Guid instanceId = reader.GetGuid(1); 104 long surrogateInstanceId = reader.GetInt64(2); 105 byte[] primitiveProperties = reader.IsDBNull(3) ? null : (byte[])(reader.GetValue(3)); 106 byte[] complexProperties = reader.IsDBNull(4) ? null : (byte[])(reader.GetValue(4)); 107 byte[] metadataProperties = reader.IsDBNull(5) ? null : (byte[])(reader.GetValue(5)); 108 InstanceEncodingOption dataEncodingOption = (InstanceEncodingOption)(reader.GetByte(6)); 109 InstanceEncodingOption metadataEncodingOption = (InstanceEncodingOption)(reader.GetByte(7)); 110 long version = reader.GetInt64(8); 111 bool isInitialized = reader.GetBoolean(9); 112 bool createdInstance = reader.GetBoolean(10); 113 114 LoadWorkflowCommand loadWorkflowCommand = base.InstancePersistenceCommand as LoadWorkflowCommand; 115 LoadWorkflowByInstanceKeyCommand loadByKeycommand = base.InstancePersistenceCommand as LoadWorkflowByInstanceKeyCommand; 116 117 if (!base.InstancePersistenceContext.InstanceView.IsBoundToInstance) 118 { 119 base.InstancePersistenceContext.BindInstance(instanceId); 120 } 121 if (!base.InstancePersistenceContext.InstanceView.IsBoundToInstanceOwner) 122 { 123 base.InstancePersistenceContext.BindInstanceOwner(base.StoreLock.LockOwnerId, base.StoreLock.LockOwnerId); 124 } 125 if (!base.InstancePersistenceContext.InstanceView.IsBoundToLock) 126 { 127 InstanceLockTracking instanceLockTracking = (InstanceLockTracking)(base.InstancePersistenceContext.UserContext); 128 instanceLockTracking.TrackStoreLock(instanceId, version, this.DependentTransaction); 129 base.InstancePersistenceContext.BindAcquiredLock(version); 130 } 131 132 this.instanceData = SerializationUtilities.DeserializePropertyBag(primitiveProperties, complexProperties, dataEncodingOption); 133 this.instanceMetadata = SerializationUtilities.DeserializeMetadataPropertyBag(metadataProperties, metadataEncodingOption); 134 135 if (!createdInstance) 136 { 137 ReadInstanceMetadataChanges(reader, this.instanceMetadata); 138 ReadKeyData(reader, this.associatedInstanceKeys, this.completedInstanceKeys); 139 } 140 else if (loadByKeycommand != null) 141 { 142 foreach (KeyValuePair<Guid, IDictionary<XName, InstanceValue>> keyEntry in loadByKeycommand.InstanceKeysToAssociate) 143 { 144 this.associatedInstanceKeys.Add(keyEntry.Key, keyEntry.Value); 145 } 146 147 if (!this.associatedInstanceKeys.ContainsKey(loadByKeycommand.LookupInstanceKey)) 148 { 149 base.InstancePersistenceContext.AssociatedInstanceKey(loadByKeycommand.LookupInstanceKey); 150 this.associatedInstanceKeys.Add(loadByKeycommand.LookupInstanceKey, new Dictionary<XName, InstanceValue>()); 151 } 152 } 153 154 if (loadByKeycommand != null) 155 { 156 foreach (KeyValuePair<Guid, IDictionary<XName, InstanceValue>> keyEntry in loadByKeycommand.InstanceKeysToAssociate) 157 { 158 base.InstancePersistenceContext.AssociatedInstanceKey(keyEntry.Key); 159 160 if (keyEntry.Value != null) 161 { 162 foreach (KeyValuePair<XName, InstanceValue> property in keyEntry.Value) 163 { 164 base.InstancePersistenceContext.WroteInstanceKeyMetadataValue(keyEntry.Key, property.Key, property.Value); 165 } 166 } 167 } 168 } 169 170 base.InstancePersistenceContext.LoadedInstance 171 ( 172 isInitialized ? InstanceState.Initialized : InstanceState.Uninitialized, 173 this.instanceData, 174 this.instanceMetadata, 175 this.associatedInstanceKeys, 176 this.completedInstanceKeys 177 ); 178 } 179 else if (exception is InstanceLockLostException) 180 { 181 base.InstancePersistenceContext.InstanceHandle.Free(); 182 } 183 184 return exception; 185 } 186 ReadInstanceMetadataChanges(SqlDataReader reader, Dictionary<XName, InstanceValue> instanceMetadata)187 void ReadInstanceMetadataChanges(SqlDataReader reader, Dictionary<XName, InstanceValue> instanceMetadata) 188 { 189 Exception exception = StoreUtilities.GetNextResultSet(base.InstancePersistenceCommand.Name, reader); 190 191 if (exception == null) 192 { 193 if (reader.IsDBNull(1)) 194 { 195 return; 196 } 197 } 198 199 do 200 { 201 InstanceEncodingOption encodingOption = (InstanceEncodingOption) reader.GetByte(1); 202 byte[] serializedMetadataChanges = (byte[]) reader.GetValue(2); 203 204 Dictionary<XName, InstanceValue> metadataChangeSet = SerializationUtilities.DeserializeMetadataPropertyBag(serializedMetadataChanges, encodingOption); 205 206 foreach (KeyValuePair<XName, InstanceValue> metadataChange in metadataChangeSet) 207 { 208 XName xname = metadataChange.Key; 209 InstanceValue propertyValue = metadataChange.Value; 210 211 if (propertyValue.Value is DeletedMetadataValue) 212 { 213 instanceMetadata.Remove(xname); 214 } 215 else 216 { 217 instanceMetadata[xname] = propertyValue; 218 } 219 } 220 } 221 while (reader.Read()); 222 } 223 ReadKeyData(SqlDataReader reader, Dictionary<Guid, IDictionary<XName, InstanceValue>> associatedInstanceKeys, Dictionary<Guid, IDictionary<XName, InstanceValue>> completedInstanceKeys)224 void ReadKeyData(SqlDataReader reader, Dictionary<Guid, IDictionary<XName, InstanceValue>> associatedInstanceKeys, 225 Dictionary<Guid, IDictionary<XName, InstanceValue>> completedInstanceKeys) 226 { 227 Exception exception = StoreUtilities.GetNextResultSet(base.InstancePersistenceCommand.Name, reader); 228 229 if (exception == null) 230 { 231 if (reader.IsDBNull(1)) 232 { 233 return; 234 } 235 236 do 237 { 238 Guid key = reader.GetGuid(1); 239 bool isAssociated = reader.GetBoolean(2); 240 InstanceEncodingOption encodingOption = (InstanceEncodingOption) reader.GetByte(3); 241 Dictionary<Guid, IDictionary<XName, InstanceValue>> destination = isAssociated ? associatedInstanceKeys : completedInstanceKeys; 242 243 if (!reader.IsDBNull(4)) 244 { 245 destination[key] = SerializationUtilities.DeserializeKeyMetadata((byte[]) reader.GetValue(4), encodingOption); 246 } 247 else 248 { 249 destination[key] = new Dictionary<XName, InstanceValue>(); 250 } 251 252 } 253 while (reader.Read()); 254 } 255 } 256 } 257 } 258