1 //------------------------------------------------------------ 2 // Copyright (c) Microsoft Corporation. All rights reserved. 3 //------------------------------------------------------------ 4 namespace System.ServiceModel.Persistence 5 { 6 using System; 7 using System.Collections.Generic; 8 using System.Collections.Specialized; 9 using System.Configuration; 10 using System.Data; 11 using System.Data.SqlClient; 12 using System.Diagnostics; 13 using System.Diagnostics.CodeAnalysis; 14 using System.Globalization; 15 using System.IO; 16 using System.Runtime; 17 using System.Runtime.Diagnostics; 18 using System.Runtime.Serialization; 19 using System.ServiceModel.Diagnostics; 20 using System.Text; 21 using System.Xml; 22 23 [Obsolete("The WF3 types are deprecated. Instead, please use the new WF4 types from System.Activities.*")] 24 public class SqlPersistenceProviderFactory : PersistenceProviderFactory 25 { 26 static readonly TimeSpan maxSecondsTimeSpan = TimeSpan.FromSeconds(int.MaxValue); 27 const string connectionStringNameParameter = "connectionStringName"; 28 const string lockTimeoutParameter = "lockTimeout"; 29 const string serializeAsTextParameter = "serializeAsText"; 30 List<SqlCommand> activeCommands; 31 string canonicalConnectionString; 32 33 string connectionString; 34 CreateHandler createHandler; 35 DeleteHandler deleteHandler; 36 Guid hostId; 37 LoadHandler loadHandler; 38 TimeSpan lockTimeout; 39 bool serializeAsText; 40 UnlockHandler unlockHandler; 41 UpdateHandler updateHandler; 42 SqlPersistenceProviderFactory(string connectionString)43 public SqlPersistenceProviderFactory(string connectionString) 44 : this(connectionString, false, TimeSpan.Zero) 45 { 46 } 47 SqlPersistenceProviderFactory(string connectionString, bool serializeAsText)48 public SqlPersistenceProviderFactory(string connectionString, bool serializeAsText) 49 : this(connectionString, serializeAsText, TimeSpan.Zero) 50 { 51 } 52 SqlPersistenceProviderFactory(string connectionString, bool serializeAsText, TimeSpan lockTimeout)53 public SqlPersistenceProviderFactory(string connectionString, bool serializeAsText, TimeSpan lockTimeout) 54 { 55 this.ConnectionString = connectionString; 56 this.LockTimeout = lockTimeout; 57 this.SerializeAsText = serializeAsText; 58 this.loadHandler = new LoadHandler(this); 59 this.createHandler = new CreateHandler(this); 60 this.updateHandler = new UpdateHandler(this); 61 this.unlockHandler = new UnlockHandler(this); 62 this.deleteHandler = new DeleteHandler(this); 63 } 64 SqlPersistenceProviderFactory(NameValueCollection parameters)65 public SqlPersistenceProviderFactory(NameValueCollection parameters) 66 { 67 if (parameters == null) 68 { 69 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("parameters"); 70 } 71 72 this.connectionString = null; 73 this.LockTimeout = TimeSpan.Zero; 74 this.SerializeAsText = false; 75 76 foreach (string key in parameters.Keys) 77 { 78 switch (key) 79 { 80 case connectionStringNameParameter: 81 ConnectionStringSettings settings = ConfigurationManager.ConnectionStrings[parameters[key]]; 82 83 if (settings == null) 84 { 85 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument( 86 SR2.GetString(SR2.ConnectionStringNameIncorrect, parameters[key])); 87 } 88 89 this.connectionString = settings.ConnectionString; 90 break; 91 case serializeAsTextParameter: 92 this.SerializeAsText = bool.Parse(parameters[key]); 93 break; 94 case lockTimeoutParameter: 95 this.LockTimeout = TimeSpan.Parse(parameters[key], CultureInfo.InvariantCulture); 96 break; 97 default: 98 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument( 99 key, 100 SR2.GetString(SR2.UnknownSqlPersistenceConfigurationParameter, key, connectionStringNameParameter, serializeAsTextParameter, lockTimeoutParameter)); 101 } 102 } 103 104 if (this.connectionString == null) 105 { 106 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument( 107 SR2.GetString(SR2.ConnectionStringNameParameterRequired, connectionStringNameParameter)); 108 } 109 110 this.loadHandler = new LoadHandler(this); 111 this.createHandler = new CreateHandler(this); 112 this.updateHandler = new UpdateHandler(this); 113 this.unlockHandler = new UnlockHandler(this); 114 this.deleteHandler = new DeleteHandler(this); 115 } 116 117 public string ConnectionString 118 { 119 get 120 { 121 return this.connectionString; 122 } 123 set 124 { 125 if (string.IsNullOrEmpty(value)) 126 { 127 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value"); 128 } 129 this.connectionString = value; 130 } 131 } 132 133 public TimeSpan LockTimeout 134 { 135 get 136 { 137 return this.lockTimeout; 138 } 139 set 140 { 141 // Allowed values are TimeSpan.Zero (no locking), TimeSpan.MaxValue (infinite locking), 142 // and any values between 1 and int.MaxValue seconds 143 if (value < TimeSpan.Zero || 144 (value > TimeSpan.FromSeconds(int.MaxValue) && value != TimeSpan.MaxValue)) 145 { 146 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 147 new ArgumentOutOfRangeException( 148 "value", 149 SR2.GetString(SR2.LockTimeoutOutOfRange))); 150 } 151 this.lockTimeout = value; 152 } 153 } 154 155 public bool SerializeAsText 156 { 157 get 158 { 159 return this.serializeAsText; 160 } 161 set 162 { 163 this.serializeAsText = value; 164 } 165 } 166 167 protected override TimeSpan DefaultCloseTimeout 168 { 169 get { return PersistenceProvider.DefaultOpenClosePersistenceTimout; } 170 } 171 172 protected override TimeSpan DefaultOpenTimeout 173 { 174 get { return PersistenceProvider.DefaultOpenClosePersistenceTimout; } 175 } 176 177 bool IsLockingTurnedOn 178 { 179 get { return this.lockTimeout != TimeSpan.Zero; } 180 } 181 182 int LockTimeoutAsInt 183 { 184 get 185 { 186 // Consider storing lockTimeout as int32 TotalSeconds instead 187 if (this.lockTimeout == TimeSpan.Zero) 188 { 189 return -1; 190 } 191 else if (this.lockTimeout == TimeSpan.MaxValue) 192 { 193 return 0; 194 } 195 else 196 { 197 Fx.Assert(this.lockTimeout <= TimeSpan.FromSeconds(int.MaxValue), 198 "The lockTimeout should have been checked in the constructor."); 199 200 return Convert.ToInt32(this.lockTimeout.TotalSeconds); 201 } 202 } 203 } 204 CreateProvider(Guid id)205 public override PersistenceProvider CreateProvider(Guid id) 206 { 207 base.ThrowIfDisposedOrNotOpen(); 208 209 if (Guid.Empty == id) 210 { 211 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("id", SR2.GetString(SR2.SqlPersistenceProviderRequiresNonEmptyGuid)); 212 } 213 214 return new SqlPersistenceProvider(id, this); 215 } 216 OnAbort()217 protected override void OnAbort() 218 { 219 if (this.activeCommands != null) 220 { 221 lock (this.activeCommands) 222 { 223 foreach (SqlCommand command in this.activeCommands) 224 { 225 command.Cancel(); 226 } 227 } 228 } 229 } 230 OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)231 protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state) 232 { 233 ValidateCommandTimeout(timeout); 234 235 return new CloseAsyncResult(this, timeout, callback, state); 236 } 237 OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)238 protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state) 239 { 240 ValidateCommandTimeout(timeout); 241 242 return new OpenAsyncResult(this, timeout, callback, state); 243 } 244 OnClose(TimeSpan timeout)245 protected override void OnClose(TimeSpan timeout) 246 { 247 } 248 OnEndClose(IAsyncResult result)249 protected override void OnEndClose(IAsyncResult result) 250 { 251 if (result == null) 252 { 253 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("result"); 254 } 255 256 CloseAsyncResult.End(result); 257 } 258 OnEndOpen(IAsyncResult result)259 protected override void OnEndOpen(IAsyncResult result) 260 { 261 if (result == null) 262 { 263 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("result"); 264 } 265 266 OpenAsyncResult.End(result); 267 } 268 OnOpen(TimeSpan timeout)269 protected override void OnOpen(TimeSpan timeout) 270 { 271 ValidateCommandTimeout(timeout); 272 273 try 274 { 275 PerformOpen(timeout); 276 } 277 catch (Exception e) 278 { 279 if (Fx.IsFatal(e)) 280 { 281 throw; 282 } 283 284 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 285 new PersistenceException( 286 SR2.GetString(SR2.ErrorOpeningSqlPersistenceProvider), 287 e)); 288 } 289 } 290 ConvertTimeSpanToSqlTimeout(TimeSpan timeout)291 static int ConvertTimeSpanToSqlTimeout(TimeSpan timeout) 292 { 293 if (timeout == TimeSpan.MaxValue) 294 { 295 return 0; 296 } 297 else 298 { 299 Fx.Assert(timeout <= TimeSpan.FromSeconds(int.MaxValue), 300 "Timeout should have been validated before entering this method."); 301 302 return Convert.ToInt32(timeout.TotalSeconds); 303 } 304 } 305 BeginCreate(Guid id, object instance, TimeSpan timeout, bool unlockInstance, AsyncCallback callback, object state)306 IAsyncResult BeginCreate(Guid id, object instance, TimeSpan timeout, bool unlockInstance, AsyncCallback callback, object state) 307 { 308 base.ThrowIfDisposedOrNotOpen(); 309 310 if (instance == null) 311 { 312 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("instance"); 313 } 314 315 ValidateCommandTimeout(timeout); 316 317 return new OperationAsyncResult(this.createHandler, this, id, timeout, callback, state, instance, unlockInstance); 318 } 319 320 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801")] BeginDelete(Guid id, object instance, TimeSpan timeout, AsyncCallback callback, object state)321 IAsyncResult BeginDelete(Guid id, object instance, TimeSpan timeout, AsyncCallback callback, object state) 322 { 323 base.ThrowIfDisposedOrNotOpen(); 324 325 ValidateCommandTimeout(timeout); 326 327 return new OperationAsyncResult(this.deleteHandler, this, id, timeout, callback, state); 328 } 329 BeginLoad(Guid id, TimeSpan timeout, bool lockInstance, AsyncCallback callback, object state)330 IAsyncResult BeginLoad(Guid id, TimeSpan timeout, bool lockInstance, AsyncCallback callback, object state) 331 { 332 base.ThrowIfDisposedOrNotOpen(); 333 334 ValidateCommandTimeout(timeout); 335 336 return new OperationAsyncResult(this.loadHandler, this, id, timeout, callback, state, lockInstance); 337 } 338 BeginUnlock(Guid id, TimeSpan timeout, AsyncCallback callback, object state)339 IAsyncResult BeginUnlock(Guid id, TimeSpan timeout, AsyncCallback callback, object state) 340 { 341 base.ThrowIfDisposedOrNotOpen(); 342 343 ValidateCommandTimeout(timeout); 344 345 return new OperationAsyncResult(this.unlockHandler, this, id, timeout, callback, state); 346 } 347 BeginUpdate(Guid id, object instance, TimeSpan timeout, bool unlockInstance, AsyncCallback callback, object state)348 IAsyncResult BeginUpdate(Guid id, object instance, TimeSpan timeout, bool unlockInstance, AsyncCallback callback, object state) 349 { 350 base.ThrowIfDisposedOrNotOpen(); 351 352 if (instance == null) 353 { 354 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("instance"); 355 } 356 357 ValidateCommandTimeout(timeout); 358 359 return new OperationAsyncResult(this.updateHandler, this, id, timeout, callback, state, instance, unlockInstance); 360 } 361 CleanupCommand(SqlCommand command)362 void CleanupCommand(SqlCommand command) 363 { 364 lock (this.activeCommands) 365 { 366 this.activeCommands.Remove(command); 367 } 368 369 command.Dispose(); 370 } 371 Create(Guid id, object instance, TimeSpan timeout, bool unlockInstance)372 object Create(Guid id, object instance, TimeSpan timeout, bool unlockInstance) 373 { 374 base.ThrowIfDisposedOrNotOpen(); 375 376 if (instance == null) 377 { 378 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("instance"); 379 } 380 381 ValidateCommandTimeout(timeout); 382 383 PerformOperation(this.createHandler, id, timeout, instance, unlockInstance); 384 385 return null; 386 } 387 CreateCommand(SqlConnection connection, TimeSpan timeout)388 SqlCommand CreateCommand(SqlConnection connection, TimeSpan timeout) 389 { 390 SqlCommand command = connection.CreateCommand(); 391 command.CommandTimeout = ConvertTimeSpanToSqlTimeout(timeout); 392 393 lock (this.activeCommands) 394 { 395 this.activeCommands.Add(command); 396 } 397 398 return command; 399 } 400 401 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801")] Delete(Guid id, object instance, TimeSpan timeout)402 void Delete(Guid id, object instance, TimeSpan timeout) 403 { 404 base.ThrowIfDisposedOrNotOpen(); 405 406 ValidateCommandTimeout(timeout); 407 408 PerformOperation(this.deleteHandler, id, timeout); 409 } 410 DeserializeInstance(object serializedInstance, bool isText)411 object DeserializeInstance(object serializedInstance, bool isText) 412 { 413 object instance; 414 415 NetDataContractSerializer serializer = new NetDataContractSerializer(); 416 if (isText) 417 { 418 StringReader stringReader = new StringReader((string)serializedInstance); 419 XmlReader xmlReader = XmlReader.Create(stringReader); 420 421 instance = serializer.ReadObject(xmlReader); 422 423 xmlReader.Close(); 424 stringReader.Close(); 425 } 426 else 427 { 428 XmlDictionaryReader dictionaryReader = XmlDictionaryReader.CreateBinaryReader((byte[])serializedInstance, XmlDictionaryReaderQuotas.Max); 429 430 instance = serializer.ReadObject(dictionaryReader); 431 432 dictionaryReader.Close(); 433 } 434 435 return instance; 436 } 437 EndCreate(IAsyncResult result)438 object EndCreate(IAsyncResult result) 439 { 440 if (result == null) 441 { 442 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("result"); 443 } 444 445 OperationAsyncResult.End(result); 446 447 return null; 448 } 449 EndDelete(IAsyncResult result)450 void EndDelete(IAsyncResult result) 451 { 452 if (result == null) 453 { 454 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("result"); 455 } 456 457 OperationAsyncResult.End(result); 458 } 459 EndLoad(IAsyncResult result)460 object EndLoad(IAsyncResult result) 461 { 462 if (result == null) 463 { 464 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("result"); 465 } 466 467 return OperationAsyncResult.End(result); 468 } 469 EndUnlock(IAsyncResult result)470 void EndUnlock(IAsyncResult result) 471 { 472 OperationAsyncResult.End(result); 473 } 474 EndUpdate(IAsyncResult result)475 object EndUpdate(IAsyncResult result) 476 { 477 if (result == null) 478 { 479 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("result"); 480 } 481 482 OperationAsyncResult.End(result); 483 484 return null; 485 } 486 GetBinarySerializedForm(object instance)487 byte[] GetBinarySerializedForm(object instance) 488 { 489 NetDataContractSerializer serializer = new NetDataContractSerializer(); 490 MemoryStream memStr = new MemoryStream(); 491 XmlDictionaryWriter dictionaryWriter = XmlDictionaryWriter.CreateBinaryWriter(memStr); 492 493 serializer.WriteObject(dictionaryWriter, instance); 494 dictionaryWriter.Flush(); 495 496 byte[] bytes = memStr.ToArray(); 497 498 dictionaryWriter.Close(); 499 memStr.Close(); 500 501 return bytes; 502 } 503 GetConnectionString(TimeSpan timeout)504 string GetConnectionString(TimeSpan timeout) 505 { 506 if (this.canonicalConnectionString != null) 507 { 508 StringBuilder sb = new StringBuilder(this.canonicalConnectionString); 509 sb.Append(ConvertTimeSpanToSqlTimeout(timeout)); 510 return sb.ToString(); 511 } 512 513 return this.connectionString; 514 } 515 GetXmlSerializedForm(object instance)516 string GetXmlSerializedForm(object instance) 517 { 518 NetDataContractSerializer serializer = new NetDataContractSerializer(); 519 MemoryStream memStr = new MemoryStream(); 520 521 serializer.WriteObject(memStr, instance); 522 523 string xml = UnicodeEncoding.UTF8.GetString(memStr.ToArray()); 524 525 memStr.Close(); 526 527 return xml; 528 } 529 Load(Guid id, TimeSpan timeout, bool lockInstance)530 object Load(Guid id, TimeSpan timeout, bool lockInstance) 531 { 532 base.ThrowIfDisposedOrNotOpen(); 533 534 ValidateCommandTimeout(timeout); 535 536 return PerformOperation(this.loadHandler, id, timeout, lockInstance); 537 } 538 OpenConnection(TimeSpan timeout)539 SqlConnection OpenConnection(TimeSpan timeout) 540 { 541 // Do I need to do timeout decrementing? 542 SqlConnection connection = new SqlConnection(GetConnectionString(timeout)); 543 connection.Open(); 544 545 return connection; 546 } 547 PerformOpen(TimeSpan timeout)548 void PerformOpen(TimeSpan timeout) 549 { 550 string lowerCaseConnectionString = this.connectionString.ToUpper(CultureInfo.InvariantCulture); 551 552 if (!lowerCaseConnectionString.Contains("CONNECTION TIMEOUT") && 553 !lowerCaseConnectionString.Contains("CONNECTIONTIMEOUT")) 554 { 555 this.canonicalConnectionString = this.connectionString.Trim(); 556 557 if (this.canonicalConnectionString.EndsWith(";", StringComparison.Ordinal)) 558 { 559 this.canonicalConnectionString += "Connection Timeout="; 560 } 561 else 562 { 563 this.canonicalConnectionString += ";Connection Timeout="; 564 } 565 } 566 567 // Check that the connection string is valid 568 using (SqlConnection connection = new SqlConnection(GetConnectionString(timeout))) 569 { 570 if (DiagnosticUtility.ShouldTraceInformation) 571 { 572 Dictionary<string, string> openParameters = new Dictionary<string, string>(2) 573 { 574 { "IsLocking", this.IsLockingTurnedOn ? "True" : "False" }, 575 { "LockTimeout", this.lockTimeout.ToString() } 576 }; 577 578 TraceRecord record = new DictionaryTraceRecord(openParameters); 579 580 TraceUtility.TraceEvent(TraceEventType.Information, 581 TraceCode.SqlPersistenceProviderOpenParameters, SR.GetString(SR.TraceCodeSqlPersistenceProviderOpenParameters), 582 record, this, null); 583 } 584 585 connection.Open(); 586 } 587 588 this.activeCommands = new List<SqlCommand>(); 589 this.hostId = Guid.NewGuid(); 590 } 591 PerformOperation(OperationHandler handler, Guid id, TimeSpan timeout, params object[] additionalParameters)592 object PerformOperation(OperationHandler handler, Guid id, TimeSpan timeout, params object[] additionalParameters) 593 { 594 int resultCode; 595 object returnValue = null; 596 597 if (DiagnosticUtility.ShouldTraceInformation) 598 { 599 string traceText = SR2.GetString(SR2.SqlPrsistenceProviderOperationAndInstanceId, handler.OperationName, id.ToString()); 600 TraceUtility.TraceEvent(TraceEventType.Information, 601 TraceCode.SqlPersistenceProviderSQLCallStart, SR.GetString(SR.TraceCodeSqlPersistenceProviderSQLCallStart), 602 new StringTraceRecord("OperationDetail", traceText), 603 this, null); 604 } 605 606 try 607 { 608 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); 609 610 using (SqlConnection connection = OpenConnection(timeoutHelper.RemainingTime())) 611 { 612 SqlCommand command = CreateCommand(connection, timeoutHelper.RemainingTime()); 613 614 try 615 { 616 handler.SetupCommand(command, id, additionalParameters); 617 618 if (handler.ExecuteReader) 619 { 620 using (SqlDataReader reader = command.ExecuteReader()) 621 { 622 returnValue = handler.ProcessReader(reader); 623 } 624 } 625 else 626 { 627 command.ExecuteNonQuery(); 628 } 629 630 resultCode = (int)command.Parameters["@result"].Value; 631 } 632 finally 633 { 634 CleanupCommand(command); 635 } 636 } 637 } 638 catch (Exception e) 639 { 640 if (Fx.IsFatal(e)) 641 { 642 throw; 643 } 644 645 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 646 new PersistenceException( 647 SR2.GetString(SR2.PersistenceOperationError, handler.OperationName), 648 e)); 649 } 650 651 Exception toThrow = handler.ProcessResult(resultCode, id, returnValue); 652 653 if (DiagnosticUtility.ShouldTraceInformation) 654 { 655 string traceText = SR2.GetString(SR2.SqlPrsistenceProviderOperationAndInstanceId, handler.OperationName, id.ToString()); 656 TraceUtility.TraceEvent(TraceEventType.Information, 657 TraceCode.SqlPersistenceProviderSQLCallEnd, SR.GetString(SR.TraceCodeSqlPersistenceProviderSQLCallEnd), 658 new StringTraceRecord("OperationDetail", traceText), 659 this, null); 660 } 661 662 if (toThrow != null) 663 { 664 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(toThrow); 665 } 666 667 return returnValue; 668 } 669 Unlock(Guid id, TimeSpan timeout)670 void Unlock(Guid id, TimeSpan timeout) 671 { 672 base.ThrowIfDisposedOrNotOpen(); 673 674 if (this.unlockHandler.ShortcutExecution) 675 { 676 return; 677 } 678 679 ValidateCommandTimeout(timeout); 680 681 PerformOperation(this.unlockHandler, id, timeout); 682 } 683 Update(Guid id, object instance, TimeSpan timeout, bool unlockInstance)684 object Update(Guid id, object instance, TimeSpan timeout, bool unlockInstance) 685 { 686 base.ThrowIfDisposedOrNotOpen(); 687 688 if (instance == null) 689 { 690 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("instance"); 691 } 692 693 ValidateCommandTimeout(timeout); 694 695 PerformOperation(this.updateHandler, id, timeout, instance, unlockInstance); 696 697 return null; 698 } 699 ValidateCommandTimeout(TimeSpan timeout)700 void ValidateCommandTimeout(TimeSpan timeout) 701 { 702 if (timeout <= TimeSpan.Zero || 703 (timeout > SqlPersistenceProviderFactory.maxSecondsTimeSpan && timeout != TimeSpan.MaxValue)) 704 { 705 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument( 706 "timeout", 707 SR2.GetString(SR2.CommandTimeoutOutOfRange)); 708 } 709 } 710 711 class CloseAsyncResult : AsyncResult 712 { CloseAsyncResult(SqlPersistenceProviderFactory provider, TimeSpan timeout, AsyncCallback callback, object state)713 public CloseAsyncResult(SqlPersistenceProviderFactory provider, TimeSpan timeout, AsyncCallback callback, object state) 714 : base(callback, state) 715 { 716 // There is no point in even pretending SqlConnection.Close needs async 717 provider.OnClose(timeout); 718 719 Complete(true); 720 } 721 End(IAsyncResult result)722 public static void End(IAsyncResult result) 723 { 724 AsyncResult.End<CloseAsyncResult>(result); 725 } 726 } 727 728 class CreateHandler : OperationHandler 729 { CreateHandler(SqlPersistenceProviderFactory provider)730 public CreateHandler(SqlPersistenceProviderFactory provider) 731 : base(provider) 732 { 733 } 734 735 public override string OperationName 736 { 737 get { return "Create"; } 738 } 739 ProcessResult(int resultCode, Guid id, object loadedInstance)740 public override Exception ProcessResult(int resultCode, Guid id, object loadedInstance) 741 { 742 switch (resultCode) 743 { 744 case 0: // Success 745 return null; 746 case 1: // Already exists 747 return new PersistenceException(SR2.GetString(SR2.InstanceAlreadyExists, id)); 748 case 2: // Some other error 749 return new PersistenceException(SR2.GetString(SR2.InsertFailed, id)); 750 default: 751 return 752 new PersistenceException(SR2.GetString(SR2.UnknownStoredProcResult)); 753 } 754 } 755 SetupCommand(SqlCommand command, Guid id, params object[] additionalParameters)756 public override void SetupCommand(SqlCommand command, Guid id, params object[] additionalParameters) 757 { 758 Fx.Assert(additionalParameters != null && additionalParameters.Length == 2, 759 "Should have had 2 additional parameters."); 760 761 Fx.Assert(additionalParameters[1].GetType() == typeof(bool), 762 "Parameter at index 1 should have been a boolean."); 763 764 object instance = additionalParameters[0]; 765 766 command.CommandType = CommandType.StoredProcedure; 767 command.CommandText = "InsertInstance"; 768 769 SqlParameter idParameter = new SqlParameter("@id", SqlDbType.UniqueIdentifier); 770 idParameter.Value = id; 771 command.Parameters.Add(idParameter); 772 773 SqlParameter instanceParameter = new SqlParameter("@instance", SqlDbType.Image); 774 SqlParameter instanceXmlParameter = new SqlParameter("@instanceXml", SqlDbType.Xml); 775 776 if (this.provider.serializeAsText) 777 { 778 instanceXmlParameter.Value = this.provider.GetXmlSerializedForm(instance); 779 instanceParameter.Value = null; 780 } 781 else 782 { 783 instanceParameter.Value = this.provider.GetBinarySerializedForm(instance); 784 instanceXmlParameter.Value = null; 785 } 786 787 command.Parameters.Add(instanceParameter); 788 command.Parameters.Add(instanceXmlParameter); 789 790 SqlParameter unlockInstanceParameter = new SqlParameter("@unlockInstance", SqlDbType.Bit); 791 unlockInstanceParameter.Value = (bool)additionalParameters[1]; 792 command.Parameters.Add(unlockInstanceParameter); 793 794 SqlParameter lockOwnerParameter = new SqlParameter("@hostId", SqlDbType.UniqueIdentifier); 795 lockOwnerParameter.Value = this.provider.hostId; 796 command.Parameters.Add(lockOwnerParameter); 797 798 SqlParameter lockTimeoutParameter = new SqlParameter("@lockTimeout", SqlDbType.Int); 799 lockTimeoutParameter.Value = this.provider.LockTimeoutAsInt; 800 command.Parameters.Add(lockTimeoutParameter); 801 802 SqlParameter resultParameter = new SqlParameter("@result", SqlDbType.Int); 803 resultParameter.Direction = ParameterDirection.Output; 804 command.Parameters.Add(resultParameter); 805 } 806 } 807 808 class DeleteHandler : OperationHandler 809 { DeleteHandler(SqlPersistenceProviderFactory provider)810 public DeleteHandler(SqlPersistenceProviderFactory provider) 811 : base(provider) 812 { 813 } 814 815 public override string OperationName 816 { 817 get { return "Delete"; } 818 } 819 ProcessResult(int resultCode, Guid id, object loadedInstance)820 public override Exception ProcessResult(int resultCode, Guid id, object loadedInstance) 821 { 822 switch (resultCode) 823 { 824 case 0: // Success 825 return null; 826 case 1: // Instance not found 827 return 828 new InstanceNotFoundException(id); 829 case 2: // Could not acquire lock 830 return new InstanceLockException(id, SR2.GetString(SR2.DidNotOwnLock, id, OperationName)); 831 default: 832 return 833 new PersistenceException( 834 SR2.GetString(SR2.UnknownStoredProcResult)); 835 } 836 } 837 SetupCommand(SqlCommand command, Guid id, params object[] additionalParameters)838 public override void SetupCommand(SqlCommand command, Guid id, params object[] additionalParameters) 839 { 840 Fx.Assert(additionalParameters == null || additionalParameters.Length == 0, 841 "Should not have gotten any additional parameters."); 842 843 command.CommandType = CommandType.StoredProcedure; 844 command.CommandText = "DeleteInstance"; 845 846 SqlParameter idParameter = new SqlParameter("@id", SqlDbType.UniqueIdentifier); 847 idParameter.Value = id; 848 command.Parameters.Add(idParameter); 849 850 SqlParameter hostIdParameter = new SqlParameter("@hostId", SqlDbType.UniqueIdentifier); 851 hostIdParameter.Value = this.provider.hostId; 852 command.Parameters.Add(hostIdParameter); 853 854 SqlParameter lockTimeoutParameter = new SqlParameter("@lockTimeout", SqlDbType.Int); 855 lockTimeoutParameter.Value = this.provider.LockTimeoutAsInt; 856 command.Parameters.Add(lockTimeoutParameter); 857 858 SqlParameter resultParameter = new SqlParameter("@result", SqlDbType.Int); 859 resultParameter.Direction = ParameterDirection.Output; 860 command.Parameters.Add(resultParameter); 861 } 862 } 863 864 class LoadHandler : OperationHandler 865 { LoadHandler(SqlPersistenceProviderFactory provider)866 public LoadHandler(SqlPersistenceProviderFactory provider) 867 : base(provider) 868 { 869 } 870 871 public override bool ExecuteReader 872 { 873 get { return true; } 874 } 875 876 public override string OperationName 877 { 878 get { return "Load"; } 879 } 880 ProcessReader(SqlDataReader reader)881 public override object ProcessReader(SqlDataReader reader) 882 { 883 if (reader.Read()) 884 { 885 bool isXml = ((int)reader["isXml"] == 0 ? false : true); 886 object serializedInstance; 887 888 if (isXml) 889 { 890 serializedInstance = reader["instanceXml"]; 891 } 892 else 893 { 894 serializedInstance = reader["instance"]; 895 } 896 897 if (serializedInstance != null) 898 { 899 return this.provider.DeserializeInstance(serializedInstance, isXml); 900 } 901 } 902 903 return null; 904 } 905 ProcessResult(int resultCode, Guid id, object loadedInstance)906 public override Exception ProcessResult(int resultCode, Guid id, object loadedInstance) 907 { 908 Exception toReturn = null; 909 910 switch (resultCode) 911 { 912 case 0: // Success 913 break; 914 case 1: // Instance not found 915 toReturn = new InstanceNotFoundException(id); 916 break; 917 case 2: // Could not acquire lock 918 toReturn = new InstanceLockException(id); 919 break; 920 default: 921 toReturn = 922 new PersistenceException(SR2.GetString(SR2.UnknownStoredProcResult)); 923 break; 924 } 925 926 if (toReturn == null) 927 { 928 if (loadedInstance == null) 929 { 930 toReturn = new PersistenceException(SR2.GetString(SR2.SerializationFormatMismatch)); 931 } 932 } 933 934 return toReturn; 935 } 936 SetupCommand(SqlCommand command, Guid id, params object[] additionalParameters)937 public override void SetupCommand(SqlCommand command, Guid id, params object[] additionalParameters) 938 { 939 Fx.Assert(additionalParameters != null && additionalParameters.Length == 1, 940 "Should have had 1 additional parameter."); 941 942 Fx.Assert(additionalParameters[0].GetType() == typeof(bool), 943 "Parameter 0 should have been a boolean."); 944 945 command.CommandType = CommandType.StoredProcedure; 946 command.CommandText = "LoadInstance"; 947 948 SqlParameter idParameter = new SqlParameter("@id", SqlDbType.UniqueIdentifier); 949 idParameter.Value = id; 950 command.Parameters.Add(idParameter); 951 952 SqlParameter lockInstanceParameter = new SqlParameter("@lockInstance", SqlDbType.Bit); 953 lockInstanceParameter.Value = (bool)additionalParameters[0]; 954 command.Parameters.Add(lockInstanceParameter); 955 956 SqlParameter hostIdParameter = new SqlParameter("@hostId", SqlDbType.UniqueIdentifier); 957 hostIdParameter.Value = this.provider.hostId; 958 command.Parameters.Add(hostIdParameter); 959 960 SqlParameter lockTimeoutParameter = new SqlParameter("@lockTimeout", SqlDbType.Int); 961 lockTimeoutParameter.Value = this.provider.LockTimeoutAsInt; 962 command.Parameters.Add(lockTimeoutParameter); 963 964 SqlParameter resultParameter = new SqlParameter("@result", SqlDbType.Int); 965 resultParameter.Direction = ParameterDirection.Output; 966 command.Parameters.Add(resultParameter); 967 } 968 } 969 970 class OpenAsyncResult : AsyncResult 971 { 972 SqlPersistenceProviderFactory provider; 973 TimeSpan timeout; 974 OpenAsyncResult(SqlPersistenceProviderFactory provider, TimeSpan timeout, AsyncCallback callback, object state)975 public OpenAsyncResult(SqlPersistenceProviderFactory provider, TimeSpan timeout, AsyncCallback callback, object state) 976 : base(callback, state) 977 { 978 Fx.Assert(provider != null, 979 "Provider should never be null."); 980 981 this.provider = provider; 982 this.timeout = timeout; 983 984 ActionItem.Schedule(ScheduledCallback, null); 985 } 986 End(IAsyncResult result)987 public static void End(IAsyncResult result) 988 { 989 AsyncResult.End<OpenAsyncResult>(result); 990 } 991 ScheduledCallback(object state)992 void ScheduledCallback(object state) 993 { 994 Exception completionException = null; 995 996 try 997 { 998 this.provider.PerformOpen(this.timeout); 999 } 1000 catch (Exception e) 1001 { 1002 if (Fx.IsFatal(e)) 1003 { 1004 throw; 1005 } 1006 1007 completionException = 1008 new PersistenceException( 1009 SR2.GetString(SR2.ErrorOpeningSqlPersistenceProvider), 1010 e); 1011 } 1012 1013 Complete(false, completionException); 1014 } 1015 } 1016 1017 class OperationAsyncResult : AsyncResult 1018 { 1019 protected SqlPersistenceProviderFactory provider; 1020 static AsyncCallback commandCallback = Fx.ThunkCallback(new AsyncCallback(CommandExecutionComplete)); 1021 1022 SqlCommand command; 1023 OperationHandler handler; 1024 Guid id; 1025 1026 object instance; 1027 1028 // We are using virtual methods from the constructor on purpose 1029 [SuppressMessage("Microsoft.Usage", "CA2214")] OperationAsyncResult(OperationHandler handler, SqlPersistenceProviderFactory provider, Guid id, TimeSpan timeout, AsyncCallback callback, object state, params object[] additionalParameters)1030 public OperationAsyncResult(OperationHandler handler, SqlPersistenceProviderFactory provider, Guid id, TimeSpan timeout, AsyncCallback callback, object state, params object[] additionalParameters) 1031 : base(callback, state) 1032 { 1033 Fx.Assert(provider != null, 1034 "Provider should never be null."); 1035 1036 this.handler = handler; 1037 this.provider = provider; 1038 this.id = id; 1039 1040 if (this.handler.ShortcutExecution) 1041 { 1042 Complete(true); 1043 return; 1044 } 1045 1046 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); 1047 SqlConnection connection = this.provider.OpenConnection(timeoutHelper.RemainingTime()); 1048 1049 bool completeSelf = false; 1050 Exception delayedException = null; 1051 try 1052 { 1053 this.command = this.provider.CreateCommand(connection, timeoutHelper.RemainingTime()); 1054 1055 this.handler.SetupCommand(this.command, this.id, additionalParameters); 1056 1057 IAsyncResult result = null; 1058 1059 if (this.handler.ExecuteReader) 1060 { 1061 result = this.command.BeginExecuteReader(commandCallback, this); 1062 } 1063 else 1064 { 1065 result = this.command.BeginExecuteNonQuery(commandCallback, this); 1066 } 1067 1068 if (result.CompletedSynchronously) 1069 { 1070 delayedException = CompleteOperation(result); 1071 1072 completeSelf = true; 1073 } 1074 } 1075 catch (Exception e) 1076 { 1077 if (Fx.IsFatal(e)) 1078 { 1079 throw; 1080 } 1081 1082 try 1083 { 1084 connection.Close(); 1085 this.provider.CleanupCommand(this.command); 1086 } 1087 catch (Exception e1) 1088 { 1089 if (Fx.IsFatal(e1)) 1090 { 1091 throw; 1092 } 1093 // do not rethrow non-fatal exceptions thrown from cleanup code 1094 } 1095 finally 1096 { 1097 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 1098 new PersistenceException( 1099 SR2.GetString(SR2.PersistenceOperationError, this.handler.OperationName), e)); 1100 } 1101 } 1102 1103 if (completeSelf) 1104 { 1105 connection.Close(); 1106 this.provider.CleanupCommand(this.command); 1107 1108 if (delayedException != null) 1109 { 1110 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(delayedException); 1111 } 1112 1113 Complete(true); 1114 } 1115 } 1116 1117 public object Instance 1118 { 1119 get { return this.instance; } 1120 } 1121 End(IAsyncResult result)1122 public static object End(IAsyncResult result) 1123 { 1124 OperationAsyncResult operationResult = AsyncResult.End<OperationAsyncResult>(result); 1125 1126 return operationResult.Instance; 1127 } 1128 CommandExecutionComplete(IAsyncResult result)1129 static void CommandExecutionComplete(IAsyncResult result) 1130 { 1131 if (result.CompletedSynchronously) 1132 { 1133 return; 1134 } 1135 1136 OperationAsyncResult operationResult = (OperationAsyncResult)result.AsyncState; 1137 1138 Exception completionException = null; 1139 try 1140 { 1141 completionException = operationResult.CompleteOperation(result); 1142 } 1143 catch (Exception e) 1144 { 1145 if (Fx.IsFatal(e)) 1146 { 1147 throw; 1148 } 1149 1150 completionException = 1151 new PersistenceException( 1152 SR2.GetString(SR2.PersistenceOperationError, operationResult.handler.OperationName), e); 1153 } 1154 finally 1155 { 1156 try 1157 { 1158 operationResult.command.Connection.Close(); 1159 operationResult.provider.CleanupCommand(operationResult.command); 1160 } 1161 catch (Exception e1) 1162 { 1163 if (Fx.IsFatal(e1)) 1164 { 1165 throw; 1166 } 1167 // do not rethrow non-fatal exceptions thrown from cleanup code 1168 } 1169 } 1170 1171 operationResult.Complete(false, completionException); 1172 } 1173 CompleteOperation(IAsyncResult result)1174 Exception CompleteOperation(IAsyncResult result) 1175 { 1176 Exception delayedException = null; 1177 1178 if (this.handler.ExecuteReader) 1179 { 1180 using (SqlDataReader reader = this.command.EndExecuteReader(result)) 1181 { 1182 this.instance = this.handler.ProcessReader(reader); 1183 } 1184 } 1185 else 1186 { 1187 this.command.EndExecuteNonQuery(result); 1188 } 1189 1190 int resultCode = (int)this.command.Parameters["@result"].Value; 1191 1192 delayedException = this.handler.ProcessResult(resultCode, this.id, this.instance); 1193 1194 return delayedException; 1195 } 1196 } 1197 1198 abstract class OperationHandler 1199 { 1200 protected SqlPersistenceProviderFactory provider; 1201 OperationHandler(SqlPersistenceProviderFactory provider)1202 public OperationHandler(SqlPersistenceProviderFactory provider) 1203 { 1204 this.provider = provider; 1205 } 1206 1207 public virtual bool ExecuteReader 1208 { 1209 get { return false; } 1210 } 1211 1212 public abstract string OperationName 1213 { get; } 1214 1215 public virtual bool ShortcutExecution 1216 { 1217 get { return false; } 1218 } 1219 1220 ProcessReader(SqlDataReader reader)1221 public virtual object ProcessReader(SqlDataReader reader) 1222 { 1223 return null; 1224 } 1225 ProcessResult(int resultCode, Guid id, object loadedInstance)1226 public abstract Exception ProcessResult(int resultCode, Guid id, object loadedInstance); 1227 SetupCommand(SqlCommand command, Guid id, params object[] additionalParameters)1228 public abstract void SetupCommand(SqlCommand command, Guid id, params object[] additionalParameters); 1229 } 1230 1231 class SqlPersistenceProvider : LockingPersistenceProvider 1232 { 1233 SqlPersistenceProviderFactory factory; 1234 SqlPersistenceProvider(Guid id, SqlPersistenceProviderFactory factory)1235 public SqlPersistenceProvider(Guid id, SqlPersistenceProviderFactory factory) 1236 : base(id) 1237 { 1238 this.factory = factory; 1239 } 1240 1241 protected override TimeSpan DefaultCloseTimeout 1242 { 1243 get { return TimeSpan.FromSeconds(15); } 1244 } 1245 1246 protected override TimeSpan DefaultOpenTimeout 1247 { 1248 get { return TimeSpan.FromSeconds(15); } 1249 } 1250 BeginCreate(object instance, TimeSpan timeout, bool unlockInstance, AsyncCallback callback, object state)1251 public override IAsyncResult BeginCreate(object instance, TimeSpan timeout, bool unlockInstance, AsyncCallback callback, object state) 1252 { 1253 base.ThrowIfDisposedOrNotOpen(); 1254 return this.factory.BeginCreate(this.Id, instance, timeout, unlockInstance, callback, state); 1255 } 1256 BeginDelete(object instance, TimeSpan timeout, AsyncCallback callback, object state)1257 public override IAsyncResult BeginDelete(object instance, TimeSpan timeout, AsyncCallback callback, object state) 1258 { 1259 base.ThrowIfDisposedOrNotOpen(); 1260 return this.factory.BeginDelete(this.Id, instance, timeout, callback, state); 1261 } 1262 BeginLoad(TimeSpan timeout, bool lockInstance, AsyncCallback callback, object state)1263 public override IAsyncResult BeginLoad(TimeSpan timeout, bool lockInstance, AsyncCallback callback, object state) 1264 { 1265 base.ThrowIfDisposedOrNotOpen(); 1266 return this.factory.BeginLoad(this.Id, timeout, lockInstance, callback, state); 1267 } 1268 BeginUnlock(TimeSpan timeout, AsyncCallback callback, object state)1269 public override IAsyncResult BeginUnlock(TimeSpan timeout, AsyncCallback callback, object state) 1270 { 1271 base.ThrowIfDisposedOrNotOpen(); 1272 return this.factory.BeginUnlock(this.Id, timeout, callback, state); 1273 } 1274 BeginUpdate(object instance, TimeSpan timeout, bool unlockInstance, AsyncCallback callback, object state)1275 public override IAsyncResult BeginUpdate(object instance, TimeSpan timeout, bool unlockInstance, AsyncCallback callback, object state) 1276 { 1277 base.ThrowIfDisposedOrNotOpen(); 1278 return this.factory.BeginUpdate(this.Id, instance, timeout, unlockInstance, callback, state); 1279 } 1280 Create(object instance, TimeSpan timeout, bool unlockInstance)1281 public override object Create(object instance, TimeSpan timeout, bool unlockInstance) 1282 { 1283 base.ThrowIfDisposedOrNotOpen(); 1284 return this.factory.Create(this.Id, instance, timeout, unlockInstance); 1285 } 1286 Delete(object instance, TimeSpan timeout)1287 public override void Delete(object instance, TimeSpan timeout) 1288 { 1289 base.ThrowIfDisposedOrNotOpen(); 1290 this.factory.Delete(this.Id, instance, timeout); 1291 } 1292 EndCreate(IAsyncResult result)1293 public override object EndCreate(IAsyncResult result) 1294 { 1295 return this.factory.EndCreate(result); 1296 } 1297 EndDelete(IAsyncResult result)1298 public override void EndDelete(IAsyncResult result) 1299 { 1300 this.factory.EndDelete(result); 1301 } 1302 EndLoad(IAsyncResult result)1303 public override object EndLoad(IAsyncResult result) 1304 { 1305 return this.factory.EndLoad(result); 1306 } 1307 EndUnlock(IAsyncResult result)1308 public override void EndUnlock(IAsyncResult result) 1309 { 1310 this.factory.EndUnlock(result); 1311 } 1312 EndUpdate(IAsyncResult result)1313 public override object EndUpdate(IAsyncResult result) 1314 { 1315 return this.factory.EndUpdate(result); 1316 } 1317 Load(TimeSpan timeout, bool lockInstance)1318 public override object Load(TimeSpan timeout, bool lockInstance) 1319 { 1320 base.ThrowIfDisposedOrNotOpen(); 1321 return this.factory.Load(this.Id, timeout, lockInstance); 1322 } 1323 Unlock(TimeSpan timeout)1324 public override void Unlock(TimeSpan timeout) 1325 { 1326 base.ThrowIfDisposedOrNotOpen(); 1327 this.factory.Unlock(this.Id, timeout); 1328 } 1329 Update(object instance, TimeSpan timeout, bool unlockInstance)1330 public override object Update(object instance, TimeSpan timeout, bool unlockInstance) 1331 { 1332 base.ThrowIfDisposedOrNotOpen(); 1333 return this.factory.Update(this.Id, instance, timeout, unlockInstance); 1334 } 1335 OnAbort()1336 protected override void OnAbort() 1337 { 1338 } 1339 OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)1340 protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state) 1341 { 1342 return new CompletedAsyncResult(callback, state); 1343 } 1344 OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)1345 protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state) 1346 { 1347 return new CompletedAsyncResult(callback, state); 1348 } 1349 OnClose(TimeSpan timeout)1350 protected override void OnClose(TimeSpan timeout) 1351 { 1352 } 1353 OnEndClose(IAsyncResult result)1354 protected override void OnEndClose(IAsyncResult result) 1355 { 1356 CompletedAsyncResult.End(result); 1357 } 1358 OnEndOpen(IAsyncResult result)1359 protected override void OnEndOpen(IAsyncResult result) 1360 { 1361 CompletedAsyncResult.End(result); 1362 } 1363 OnOpen(TimeSpan timeout)1364 protected override void OnOpen(TimeSpan timeout) 1365 { 1366 } 1367 } 1368 1369 class UnlockHandler : OperationHandler 1370 { UnlockHandler(SqlPersistenceProviderFactory provider)1371 public UnlockHandler(SqlPersistenceProviderFactory provider) 1372 : base(provider) 1373 { 1374 } 1375 1376 public override string OperationName 1377 { 1378 get { return "Unlock"; } 1379 } 1380 1381 public override bool ShortcutExecution 1382 { 1383 get { return !this.provider.IsLockingTurnedOn; } 1384 } 1385 ProcessResult(int resultCode, Guid id, object loadedInstance)1386 public override Exception ProcessResult(int resultCode, Guid id, object loadedInstance) 1387 { 1388 switch (resultCode) 1389 { 1390 case 0: // Success 1391 return null; 1392 case 1: // Instance not found 1393 return 1394 new InstanceNotFoundException(id); 1395 case 2: // Could not acquire lock 1396 return new InstanceLockException(id, SR2.GetString(SR2.DidNotOwnLock, id, OperationName)); 1397 default: 1398 return 1399 new PersistenceException(SR2.GetString(SR2.UnknownStoredProcResult)); 1400 } 1401 } 1402 SetupCommand(SqlCommand command, Guid id, params object[] additionalParameters)1403 public override void SetupCommand(SqlCommand command, Guid id, params object[] additionalParameters) 1404 { 1405 Fx.Assert(additionalParameters == null || additionalParameters.Length == 0, 1406 "There should not be any additional parameters."); 1407 1408 command.CommandType = CommandType.StoredProcedure; 1409 command.CommandText = "UnlockInstance"; 1410 1411 SqlParameter idParameter = new SqlParameter("@id", SqlDbType.UniqueIdentifier); 1412 idParameter.Value = id; 1413 command.Parameters.Add(idParameter); 1414 1415 SqlParameter hostIdParameter = new SqlParameter("@hostId", SqlDbType.UniqueIdentifier); 1416 hostIdParameter.Value = this.provider.hostId; 1417 command.Parameters.Add(hostIdParameter); 1418 1419 SqlParameter lockTimeoutParameter = new SqlParameter("@lockTimeout", SqlDbType.Int); 1420 lockTimeoutParameter.Value = this.provider.LockTimeoutAsInt; 1421 command.Parameters.Add(lockTimeoutParameter); 1422 1423 SqlParameter resultParameter = new SqlParameter("@result", SqlDbType.Int); 1424 resultParameter.Direction = ParameterDirection.Output; 1425 command.Parameters.Add(resultParameter); 1426 } 1427 } 1428 1429 class UpdateHandler : OperationHandler 1430 { UpdateHandler(SqlPersistenceProviderFactory provider)1431 public UpdateHandler(SqlPersistenceProviderFactory provider) 1432 : base(provider) 1433 { 1434 } 1435 1436 public override string OperationName 1437 { 1438 get { return "Update"; } 1439 } 1440 ProcessResult(int resultCode, Guid id, object loadedInstance)1441 public override Exception ProcessResult(int resultCode, Guid id, object loadedInstance) 1442 { 1443 switch (resultCode) 1444 { 1445 case 0: // Success 1446 return null; 1447 case 1: // Instance did not exist 1448 return new InstanceNotFoundException(id, SR2.GetString(SR2.InstanceNotFoundForUpdate, id)); 1449 case 2: // Did not have lock 1450 return new InstanceLockException(id, SR2.GetString(SR2.DidNotOwnLock, id, OperationName)); 1451 default: 1452 return 1453 new PersistenceException(SR2.GetString(SR2.UnknownStoredProcResult)); 1454 } 1455 } 1456 SetupCommand(SqlCommand command, Guid id, params object[] additionalParameters)1457 public override void SetupCommand(SqlCommand command, Guid id, params object[] additionalParameters) 1458 { 1459 Fx.Assert(additionalParameters != null && additionalParameters.Length == 2, 1460 "Should have had 2 additional parameters."); 1461 1462 Fx.Assert(additionalParameters[1].GetType() == typeof(bool), 1463 "Parameter at index 1 should have been a boolean."); 1464 1465 object instance = additionalParameters[0]; 1466 1467 command.CommandType = CommandType.StoredProcedure; 1468 command.CommandText = "UpdateInstance"; 1469 1470 SqlParameter idParameter = new SqlParameter("@id", SqlDbType.UniqueIdentifier); 1471 idParameter.Value = id; 1472 command.Parameters.Add(idParameter); 1473 1474 SqlParameter instanceParameter = new SqlParameter("@instance", SqlDbType.Image); 1475 SqlParameter instanceXmlParameter = new SqlParameter("@instanceXml", SqlDbType.Xml); 1476 1477 if (this.provider.serializeAsText) 1478 { 1479 instanceXmlParameter.Value = this.provider.GetXmlSerializedForm(instance); 1480 instanceParameter.Value = null; 1481 } 1482 else 1483 { 1484 instanceParameter.Value = this.provider.GetBinarySerializedForm(instance); 1485 instanceXmlParameter.Value = null; 1486 } 1487 1488 command.Parameters.Add(instanceParameter); 1489 command.Parameters.Add(instanceXmlParameter); 1490 1491 SqlParameter unlockInstanceParameter = new SqlParameter("@unlockInstance", SqlDbType.Bit); 1492 unlockInstanceParameter.Value = (bool)additionalParameters[1]; 1493 command.Parameters.Add(unlockInstanceParameter); 1494 1495 SqlParameter lockOwnerParameter = new SqlParameter("@hostId", SqlDbType.UniqueIdentifier); 1496 lockOwnerParameter.Value = this.provider.hostId; 1497 command.Parameters.Add(lockOwnerParameter); 1498 1499 SqlParameter lockTimeoutParameter = new SqlParameter("@lockTimeout", SqlDbType.Int); 1500 lockTimeoutParameter.Value = this.provider.LockTimeoutAsInt; 1501 command.Parameters.Add(lockTimeoutParameter); 1502 1503 SqlParameter resultParameter = new SqlParameter("@result", SqlDbType.Int); 1504 resultParameter.Direction = ParameterDirection.Output; 1505 command.Parameters.Add(resultParameter); 1506 } 1507 } 1508 } 1509 } 1510