1 //----------------------------------------------------------------------------- 2 // Copyright (c) Microsoft Corporation. All rights reserved. 3 //----------------------------------------------------------------------------- 4 namespace System.ServiceModel.Channels 5 { 6 using System.Collections.Generic; 7 using System.ComponentModel; 8 using System.Diagnostics; 9 using System.Runtime; 10 using System.ServiceModel; 11 using System.ServiceModel.Diagnostics; 12 using System.ServiceModel.Diagnostics.Application; 13 14 public abstract class CommunicationObject : ICommunicationObject 15 { 16 bool aborted; 17 bool closeCalled; 18 #if DEBUG 19 StackTrace closeStack; 20 StackTrace faultedStack; 21 #endif 22 ExceptionQueue exceptionQueue; 23 object mutex; 24 bool onClosingCalled; 25 bool onClosedCalled; 26 bool onOpeningCalled; 27 bool onOpenedCalled; 28 bool raisedClosed; 29 bool raisedClosing; 30 bool raisedFaulted; 31 bool traceOpenAndClose; 32 object eventSender; 33 CommunicationState state; 34 CommunicationObject()35 protected CommunicationObject() 36 : this(new object()) 37 { 38 } 39 CommunicationObject(object mutex)40 protected CommunicationObject(object mutex) 41 { 42 this.mutex = mutex; 43 this.eventSender = this; 44 this.state = CommunicationState.Created; 45 } 46 CommunicationObject(object mutex, object eventSender)47 internal CommunicationObject(object mutex, object eventSender) 48 { 49 this.mutex = mutex; 50 this.eventSender = eventSender; 51 this.state = CommunicationState.Created; 52 } 53 54 internal bool Aborted 55 { 56 get { return this.aborted; } 57 } 58 59 internal object EventSender 60 { 61 get { return this.eventSender; } 62 set { eventSender = value; } 63 } 64 65 protected bool IsDisposed 66 { 67 get { return this.state == CommunicationState.Closed; } 68 } 69 70 public CommunicationState State 71 { 72 get { return this.state; } 73 } 74 75 protected object ThisLock 76 { 77 get { return this.mutex; } 78 } 79 80 protected abstract TimeSpan DefaultCloseTimeout { get; } 81 protected abstract TimeSpan DefaultOpenTimeout { get; } 82 83 internal TimeSpan InternalCloseTimeout 84 { 85 get { return this.DefaultCloseTimeout; } 86 } 87 88 internal TimeSpan InternalOpenTimeout 89 { 90 get { return this.DefaultOpenTimeout; } 91 } 92 93 public event EventHandler Closed; 94 public event EventHandler Closing; 95 public event EventHandler Faulted; 96 public event EventHandler Opened; 97 public event EventHandler Opening; 98 Abort()99 public void Abort() 100 { 101 lock (ThisLock) 102 { 103 if (this.aborted || this.state == CommunicationState.Closed) 104 return; 105 this.aborted = true; 106 #if DEBUG 107 if (closeStack == null) 108 closeStack = new StackTrace(); 109 #endif 110 111 this.state = CommunicationState.Closing; 112 } 113 114 if (DiagnosticUtility.ShouldTraceInformation) 115 { 116 TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.CommunicationObjectAborted, SR.GetString(SR.TraceCodeCommunicationObjectAborted, TraceUtility.CreateSourceString(this)), this); 117 } 118 119 bool throwing = true; 120 121 try 122 { 123 OnClosing(); 124 if (!this.onClosingCalled) 125 throw TraceUtility.ThrowHelperError(this.CreateBaseClassMethodNotCalledException("OnClosing"), Guid.Empty, this); 126 127 OnAbort(); 128 129 OnClosed(); 130 if (!this.onClosedCalled) 131 throw TraceUtility.ThrowHelperError(this.CreateBaseClassMethodNotCalledException("OnClosed"), Guid.Empty, this); 132 133 throwing = false; 134 } 135 finally 136 { 137 if (throwing) 138 { 139 if (DiagnosticUtility.ShouldTraceWarning) 140 TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.CommunicationObjectAbortFailed, SR.GetString(SR.TraceCodeCommunicationObjectAbortFailed, this.GetCommunicationObjectType().ToString()), this); 141 } 142 } 143 } 144 BeginClose(AsyncCallback callback, object state)145 public IAsyncResult BeginClose(AsyncCallback callback, object state) 146 { 147 return this.BeginClose(this.DefaultCloseTimeout, callback, state); 148 } 149 BeginClose(TimeSpan timeout, AsyncCallback callback, object state)150 public IAsyncResult BeginClose(TimeSpan timeout, AsyncCallback callback, object state) 151 { 152 if (timeout < TimeSpan.Zero) 153 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 154 new ArgumentOutOfRangeException("timeout", SR.GetString(SR.SFxTimeoutOutOfRange0))); 155 156 using (DiagnosticUtility.ShouldUseActivity && this.TraceOpenAndClose ? this.CreateCloseActivity() : null) 157 { 158 CommunicationState originalState; 159 lock (ThisLock) 160 { 161 originalState = this.state; 162 #if DEBUG 163 if (closeStack == null) 164 closeStack = new StackTrace(); 165 #endif 166 if (originalState != CommunicationState.Closed) 167 this.state = CommunicationState.Closing; 168 169 this.closeCalled = true; 170 } 171 172 switch (originalState) 173 { 174 case CommunicationState.Created: 175 case CommunicationState.Opening: 176 case CommunicationState.Faulted: 177 this.Abort(); 178 if (originalState == CommunicationState.Faulted) 179 { 180 throw TraceUtility.ThrowHelperError(this.CreateFaultedException(), Guid.Empty, this); 181 } 182 return new AlreadyClosedAsyncResult(callback, state); 183 184 case CommunicationState.Opened: 185 { 186 bool throwing = true; 187 try 188 { 189 OnClosing(); 190 if (!this.onClosingCalled) 191 throw TraceUtility.ThrowHelperError(this.CreateBaseClassMethodNotCalledException("OnClosing"), Guid.Empty, this); 192 193 IAsyncResult result = new CloseAsyncResult(this, timeout, callback, state); 194 throwing = false; 195 return result; 196 } 197 finally 198 { 199 if (throwing) 200 { 201 if (DiagnosticUtility.ShouldTraceWarning) 202 { 203 TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.CommunicationObjectCloseFailed, SR.GetString(SR.TraceCodeCommunicationObjectCloseFailed, this.GetCommunicationObjectType().ToString()), this); 204 } 205 206 Abort(); 207 } 208 } 209 } 210 211 case CommunicationState.Closing: 212 case CommunicationState.Closed: 213 return new AlreadyClosedAsyncResult(callback, state); 214 215 default: 216 throw Fx.AssertAndThrow("CommunicationObject.BeginClose: Unknown CommunicationState"); 217 } 218 } 219 } 220 BeginOpen(AsyncCallback callback, object state)221 public IAsyncResult BeginOpen(AsyncCallback callback, object state) 222 { 223 return this.BeginOpen(this.DefaultOpenTimeout, callback, state); 224 } 225 BeginOpen(TimeSpan timeout, AsyncCallback callback, object state)226 public IAsyncResult BeginOpen(TimeSpan timeout, AsyncCallback callback, object state) 227 { 228 if (timeout < TimeSpan.Zero) 229 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 230 new ArgumentOutOfRangeException("timeout", SR.GetString(SR.SFxTimeoutOutOfRange0))); 231 232 lock (ThisLock) 233 { 234 ThrowIfDisposedOrImmutable(); 235 this.state = CommunicationState.Opening; 236 } 237 238 bool throwing = true; 239 try 240 { 241 OnOpening(); 242 if (!this.onOpeningCalled) 243 throw TraceUtility.ThrowHelperError(this.CreateBaseClassMethodNotCalledException("OnOpening"), Guid.Empty, this); 244 245 IAsyncResult result = new OpenAsyncResult(this, timeout, callback, state); 246 throwing = false; 247 return result; 248 } 249 finally 250 { 251 if (throwing) 252 { 253 if (DiagnosticUtility.ShouldTraceWarning) 254 { 255 TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.CommunicationObjectOpenFailed, SR.GetString(SR.TraceCodeCommunicationObjectOpenFailed, this.GetCommunicationObjectType().ToString()), this); 256 } 257 258 Fault(); 259 } 260 } 261 } 262 Close()263 public void Close() 264 { 265 this.Close(this.DefaultCloseTimeout); 266 } 267 Close(TimeSpan timeout)268 public void Close(TimeSpan timeout) 269 { 270 if (timeout < TimeSpan.Zero) 271 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 272 new ArgumentOutOfRangeException("timeout", SR.GetString(SR.SFxTimeoutOutOfRange0))); 273 274 using (DiagnosticUtility.ShouldUseActivity && this.TraceOpenAndClose ? this.CreateCloseActivity() : null) 275 { 276 277 CommunicationState originalState; 278 lock (ThisLock) 279 { 280 originalState = this.state; 281 #if DEBUG 282 if (closeStack == null) 283 closeStack = new StackTrace(); 284 #endif 285 if (originalState != CommunicationState.Closed) 286 this.state = CommunicationState.Closing; 287 288 this.closeCalled = true; 289 } 290 291 switch (originalState) 292 { 293 case CommunicationState.Created: 294 case CommunicationState.Opening: 295 case CommunicationState.Faulted: 296 this.Abort(); 297 if (originalState == CommunicationState.Faulted) 298 { 299 throw TraceUtility.ThrowHelperError(this.CreateFaultedException(), Guid.Empty, this); 300 } 301 break; 302 303 case CommunicationState.Opened: 304 { 305 bool throwing = true; 306 try 307 { 308 TimeoutHelper actualTimeout = new TimeoutHelper(timeout); 309 310 OnClosing(); 311 if (!this.onClosingCalled) 312 throw TraceUtility.ThrowHelperError(this.CreateBaseClassMethodNotCalledException("OnClosing"), Guid.Empty, this); 313 314 OnClose(actualTimeout.RemainingTime()); 315 316 OnClosed(); 317 if (!this.onClosedCalled) 318 throw TraceUtility.ThrowHelperError(this.CreateBaseClassMethodNotCalledException("OnClosed"), Guid.Empty, this); 319 320 throwing = false; 321 } 322 finally 323 { 324 if (throwing) 325 { 326 if (DiagnosticUtility.ShouldTraceWarning) 327 { 328 TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.CommunicationObjectCloseFailed, SR.GetString(SR.TraceCodeCommunicationObjectCloseFailed, this.GetCommunicationObjectType().ToString()), this); 329 } 330 331 Abort(); 332 } 333 } 334 break; 335 } 336 337 case CommunicationState.Closing: 338 case CommunicationState.Closed: 339 break; 340 341 default: 342 throw Fx.AssertAndThrow("CommunicationObject.BeginClose: Unknown CommunicationState"); 343 } 344 } 345 } 346 CreateNotOpenException()347 Exception CreateNotOpenException() 348 { 349 return new InvalidOperationException(SR.GetString(SR.CommunicationObjectCannotBeUsed, this.GetCommunicationObjectType().ToString(), this.state.ToString())); 350 } 351 CreateImmutableException()352 Exception CreateImmutableException() 353 { 354 return new InvalidOperationException(SR.GetString(SR.CommunicationObjectCannotBeModifiedInState, this.GetCommunicationObjectType().ToString(), this.state.ToString())); 355 } 356 CreateBaseClassMethodNotCalledException(string method)357 Exception CreateBaseClassMethodNotCalledException(string method) 358 { 359 return new InvalidOperationException(SR.GetString(SR.CommunicationObjectBaseClassMethodNotCalled, this.GetCommunicationObjectType().ToString(), method)); 360 } 361 CreateClosedException()362 internal Exception CreateClosedException() 363 { 364 if (!this.closeCalled) 365 { 366 return CreateAbortedException(); 367 } 368 else 369 { 370 #if DEBUG 371 string originalStack = closeStack.ToString().Replace("\r\n", "\r\n "); 372 return new ObjectDisposedException(this.GetCommunicationObjectType().ToString() + ", Object already closed:\r\n " + originalStack); 373 #else 374 return new ObjectDisposedException(this.GetCommunicationObjectType().ToString()); 375 #endif 376 } 377 } 378 CreateFaultedException()379 internal Exception CreateFaultedException() 380 { 381 #if DEBUG 382 string originalStack = faultedStack.ToString().Replace("\r\n", "\r\n "); 383 string message = SR.GetString(SR.CommunicationObjectFaultedStack2, this.GetCommunicationObjectType().ToString(), originalStack); 384 #else 385 string message = SR.GetString(SR.CommunicationObjectFaulted1, this.GetCommunicationObjectType().ToString()); 386 #endif 387 return new CommunicationObjectFaultedException(message); 388 } 389 CreateAbortedException()390 internal Exception CreateAbortedException() 391 { 392 #if DEBUG 393 string originalStack = closeStack.ToString().Replace("\r\n", "\r\n "); 394 return new CommunicationObjectAbortedException(SR.GetString(SR.CommunicationObjectAbortedStack2, this.GetCommunicationObjectType().ToString(), originalStack)); 395 #else 396 return new CommunicationObjectAbortedException(SR.GetString(SR.CommunicationObjectAborted1, this.GetCommunicationObjectType().ToString())); 397 #endif 398 } 399 400 internal virtual string CloseActivityName 401 { 402 get { return SR.GetString(SR.ActivityClose, this.GetType().FullName); } 403 } 404 405 internal virtual string OpenActivityName 406 { 407 get { return SR.GetString(SR.ActivityOpen, this.GetType().FullName); } 408 } 409 410 internal virtual ActivityType OpenActivityType 411 { 412 get { return ActivityType.Open; } 413 } 414 CreateCloseActivity()415 ServiceModelActivity CreateCloseActivity() 416 { 417 ServiceModelActivity retval = null; 418 retval = ServiceModelActivity.CreateBoundedActivity(); 419 if (DiagnosticUtility.ShouldUseActivity) 420 { 421 ServiceModelActivity.Start(retval, this.CloseActivityName, ActivityType.Close); 422 } 423 424 return retval; 425 } 426 DoneReceivingInCurrentState()427 internal bool DoneReceivingInCurrentState() 428 { 429 this.ThrowPending(); 430 431 switch (this.state) 432 { 433 case CommunicationState.Created: 434 throw TraceUtility.ThrowHelperError(this.CreateNotOpenException(), Guid.Empty, this); 435 436 case CommunicationState.Opening: 437 throw TraceUtility.ThrowHelperError(this.CreateNotOpenException(), Guid.Empty, this); 438 439 case CommunicationState.Opened: 440 return false; 441 442 case CommunicationState.Closing: 443 return true; 444 445 case CommunicationState.Closed: 446 return true; 447 448 case CommunicationState.Faulted: 449 return true; 450 451 default: 452 throw Fx.AssertAndThrow("DoneReceivingInCurrentState: Unknown CommunicationObject.state"); 453 } 454 } 455 EndClose(IAsyncResult result)456 public void EndClose(IAsyncResult result) 457 { 458 if (result is AlreadyClosedAsyncResult) 459 AlreadyClosedAsyncResult.End(result); 460 else 461 CloseAsyncResult.End(result); 462 } 463 EndOpen(IAsyncResult result)464 public void EndOpen(IAsyncResult result) 465 { 466 OpenAsyncResult.End(result); 467 } 468 Fault()469 protected void Fault() 470 { 471 lock (ThisLock) 472 { 473 if (this.state == CommunicationState.Closed || this.state == CommunicationState.Closing) 474 return; 475 476 if (this.state == CommunicationState.Faulted) 477 return; 478 #if DEBUG 479 if (faultedStack == null) 480 faultedStack = new StackTrace(); 481 #endif 482 this.state = CommunicationState.Faulted; 483 } 484 485 OnFaulted(); 486 } 487 Fault(Exception exception)488 internal void Fault(Exception exception) 489 { 490 lock (this.ThisLock) 491 { 492 if (this.exceptionQueue == null) 493 this.exceptionQueue = new ExceptionQueue(this.ThisLock); 494 } 495 496 if (exception != null && DiagnosticUtility.ShouldTraceInformation) 497 { 498 TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.CommunicationObjectFaultReason, 499 SR.GetString(SR.TraceCodeCommunicationObjectFaultReason), exception, null); 500 } 501 502 this.exceptionQueue.AddException(exception); 503 this.Fault(); 504 } 505 AddPendingException(Exception exception)506 internal void AddPendingException(Exception exception) 507 { 508 lock (this.ThisLock) 509 { 510 if (this.exceptionQueue == null) 511 this.exceptionQueue = new ExceptionQueue(this.ThisLock); 512 } 513 514 this.exceptionQueue.AddException(exception); 515 } 516 GetPendingException()517 internal Exception GetPendingException() 518 { 519 CommunicationState currentState = this.state; 520 521 Fx.Assert(currentState == CommunicationState.Closing || currentState == CommunicationState.Closed || currentState == CommunicationState.Faulted, 522 "CommunicationObject.GetPendingException(currentState == CommunicationState.Closing || currentState == CommunicationState.Closed || currentState == CommunicationState.Faulted)"); 523 524 ExceptionQueue queue = this.exceptionQueue; 525 if (queue != null) 526 { 527 return queue.GetException(); 528 } 529 else 530 { 531 return null; 532 } 533 } 534 535 // Terminal is loosely defined as an interruption to close or a fault. GetTerminalException()536 internal Exception GetTerminalException() 537 { 538 Exception exception = this.GetPendingException(); 539 540 if (exception != null) 541 { 542 return exception; 543 } 544 545 switch (this.state) 546 { 547 case CommunicationState.Closing: 548 case CommunicationState.Closed: 549 return new CommunicationException(SR.GetString(SR.CommunicationObjectCloseInterrupted1, this.GetCommunicationObjectType().ToString())); 550 551 case CommunicationState.Faulted: 552 return this.CreateFaultedException(); 553 554 default: 555 throw Fx.AssertAndThrow("GetTerminalException: Invalid CommunicationObject.state"); 556 } 557 } 558 Open()559 public void Open() 560 { 561 this.Open(this.DefaultOpenTimeout); 562 } 563 Open(TimeSpan timeout)564 public void Open(TimeSpan timeout) 565 { 566 if (timeout < TimeSpan.Zero) 567 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 568 new ArgumentOutOfRangeException("timeout", SR.GetString(SR.SFxTimeoutOutOfRange0))); 569 570 using (ServiceModelActivity activity = DiagnosticUtility.ShouldUseActivity && this.TraceOpenAndClose ? ServiceModelActivity.CreateBoundedActivity() : null) 571 { 572 if (DiagnosticUtility.ShouldUseActivity) 573 { 574 ServiceModelActivity.Start(activity, this.OpenActivityName, this.OpenActivityType); 575 } 576 lock (ThisLock) 577 { 578 ThrowIfDisposedOrImmutable(); 579 this.state = CommunicationState.Opening; 580 } 581 582 bool throwing = true; 583 try 584 { 585 TimeoutHelper actualTimeout = new TimeoutHelper(timeout); 586 587 OnOpening(); 588 if (!this.onOpeningCalled) 589 throw TraceUtility.ThrowHelperError(this.CreateBaseClassMethodNotCalledException("OnOpening"), Guid.Empty, this); 590 591 OnOpen(actualTimeout.RemainingTime()); 592 593 OnOpened(); 594 if (!this.onOpenedCalled) 595 throw TraceUtility.ThrowHelperError(this.CreateBaseClassMethodNotCalledException("OnOpened"), Guid.Empty, this); 596 597 throwing = false; 598 } 599 finally 600 { 601 if (throwing) 602 { 603 if (DiagnosticUtility.ShouldTraceWarning) 604 { 605 TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.CommunicationObjectOpenFailed, SR.GetString(SR.TraceCodeCommunicationObjectOpenFailed, this.GetCommunicationObjectType().ToString()), this); 606 } 607 608 Fault(); 609 } 610 } 611 } 612 } 613 OnClosed()614 protected virtual void OnClosed() 615 { 616 this.onClosedCalled = true; 617 618 lock (ThisLock) 619 { 620 if (this.raisedClosed) 621 return; 622 this.raisedClosed = true; 623 this.state = CommunicationState.Closed; 624 } 625 626 if (DiagnosticUtility.ShouldTraceVerbose) 627 { 628 TraceUtility.TraceEvent(TraceEventType.Verbose, TraceCode.CommunicationObjectClosed, SR.GetString(SR.TraceCodeCommunicationObjectClosed, TraceUtility.CreateSourceString(this)), this); 629 } 630 631 EventHandler handler = Closed; 632 if (handler != null) 633 { 634 try 635 { 636 handler(eventSender, EventArgs.Empty); 637 } 638 catch (Exception exception) 639 { 640 if (Fx.IsFatal(exception)) 641 throw; 642 643 throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(exception); 644 } 645 } 646 } 647 OnClosing()648 protected virtual void OnClosing() 649 { 650 this.onClosingCalled = true; 651 652 lock (ThisLock) 653 { 654 if (this.raisedClosing) 655 return; 656 this.raisedClosing = true; 657 } 658 659 if (DiagnosticUtility.ShouldTraceVerbose) 660 { 661 TraceUtility.TraceEvent(TraceEventType.Verbose, TraceCode.CommunicationObjectClosing, SR.GetString(SR.TraceCodeCommunicationObjectClosing, TraceUtility.CreateSourceString(this)), this); 662 } 663 EventHandler handler = Closing; 664 if (handler != null) 665 { 666 try 667 { 668 handler(eventSender, EventArgs.Empty); 669 } 670 catch (Exception exception) 671 { 672 if (Fx.IsFatal(exception)) 673 throw; 674 675 throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(exception); 676 } 677 } 678 } 679 OnFaulted()680 protected virtual void OnFaulted() 681 { 682 lock (ThisLock) 683 { 684 if (this.raisedFaulted) 685 return; 686 this.raisedFaulted = true; 687 } 688 689 if (DiagnosticUtility.ShouldTraceWarning) 690 { 691 TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.CommunicationObjectFaulted, SR.GetString(SR.TraceCodeCommunicationObjectFaulted, this.GetCommunicationObjectType().ToString()), this); 692 } 693 694 EventHandler handler = Faulted; 695 if (handler != null) 696 { 697 try 698 { 699 handler(eventSender, EventArgs.Empty); 700 } 701 catch (Exception exception) 702 { 703 if (Fx.IsFatal(exception)) 704 throw; 705 706 throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(exception); 707 } 708 } 709 } 710 OnOpened()711 protected virtual void OnOpened() 712 { 713 this.onOpenedCalled = true; 714 715 lock (ThisLock) 716 { 717 if (this.aborted || this.state != CommunicationState.Opening) 718 return; 719 this.state = CommunicationState.Opened; 720 } 721 722 if (DiagnosticUtility.ShouldTraceVerbose) 723 TraceUtility.TraceEvent(TraceEventType.Verbose, TraceCode.CommunicationObjectOpened, SR.GetString(SR.TraceCodeCommunicationObjectOpened, TraceUtility.CreateSourceString(this)), this); 724 725 EventHandler handler = Opened; 726 if (handler != null) 727 { 728 try 729 { 730 handler(eventSender, EventArgs.Empty); 731 } 732 catch (Exception exception) 733 { 734 if (Fx.IsFatal(exception)) 735 throw; 736 737 throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(exception); 738 } 739 } 740 } 741 OnOpening()742 protected virtual void OnOpening() 743 { 744 this.onOpeningCalled = true; 745 746 if (DiagnosticUtility.ShouldTraceVerbose) 747 { 748 TraceUtility.TraceEvent(TraceEventType.Verbose, TraceCode.CommunicationObjectOpening, SR.GetString(SR.TraceCodeCommunicationObjectOpening, TraceUtility.CreateSourceString(this)), this); 749 } 750 751 EventHandler handler = Opening; 752 if (handler != null) 753 { 754 try 755 { 756 handler(eventSender, EventArgs.Empty); 757 } 758 catch (Exception exception) 759 { 760 if (Fx.IsFatal(exception)) 761 throw; 762 763 throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(exception); 764 } 765 } 766 } 767 ThrowIfFaulted()768 internal void ThrowIfFaulted() 769 { 770 this.ThrowPending(); 771 772 switch (this.state) 773 { 774 case CommunicationState.Created: 775 break; 776 777 case CommunicationState.Opening: 778 break; 779 780 case CommunicationState.Opened: 781 break; 782 783 case CommunicationState.Closing: 784 break; 785 786 case CommunicationState.Closed: 787 break; 788 789 case CommunicationState.Faulted: 790 throw TraceUtility.ThrowHelperError(this.CreateFaultedException(), Guid.Empty, this); 791 792 default: 793 throw Fx.AssertAndThrow("ThrowIfFaulted: Unknown CommunicationObject.state"); 794 } 795 } 796 ThrowIfAborted()797 internal void ThrowIfAborted() 798 { 799 if (this.aborted && !this.closeCalled) 800 { 801 throw TraceUtility.ThrowHelperError(CreateAbortedException(), Guid.Empty, this); 802 } 803 } 804 805 internal bool TraceOpenAndClose 806 { 807 get 808 { 809 return this.traceOpenAndClose; 810 } 811 set 812 { 813 this.traceOpenAndClose = value && DiagnosticUtility.ShouldUseActivity; 814 } 815 } 816 ThrowIfClosed()817 internal void ThrowIfClosed() 818 { 819 ThrowPending(); 820 821 switch (this.state) 822 { 823 case CommunicationState.Created: 824 break; 825 826 case CommunicationState.Opening: 827 break; 828 829 case CommunicationState.Opened: 830 break; 831 832 case CommunicationState.Closing: 833 break; 834 835 case CommunicationState.Closed: 836 throw TraceUtility.ThrowHelperError(this.CreateClosedException(), Guid.Empty, this); 837 838 case CommunicationState.Faulted: 839 throw TraceUtility.ThrowHelperError(this.CreateFaultedException(), Guid.Empty, this); 840 841 default: 842 throw Fx.AssertAndThrow("ThrowIfClosed: Unknown CommunicationObject.state"); 843 } 844 } 845 GetCommunicationObjectType()846 protected virtual Type GetCommunicationObjectType() 847 { 848 return this.GetType(); 849 } 850 ThrowIfDisposed()851 protected internal void ThrowIfDisposed() 852 { 853 ThrowPending(); 854 855 switch (this.state) 856 { 857 case CommunicationState.Created: 858 break; 859 860 case CommunicationState.Opening: 861 break; 862 863 case CommunicationState.Opened: 864 break; 865 866 case CommunicationState.Closing: 867 throw TraceUtility.ThrowHelperError(this.CreateClosedException(), Guid.Empty, this); 868 869 case CommunicationState.Closed: 870 throw TraceUtility.ThrowHelperError(this.CreateClosedException(), Guid.Empty, this); 871 872 case CommunicationState.Faulted: 873 throw TraceUtility.ThrowHelperError(this.CreateFaultedException(), Guid.Empty, this); 874 875 default: 876 throw Fx.AssertAndThrow("ThrowIfDisposed: Unknown CommunicationObject.state"); 877 } 878 } 879 ThrowIfClosedOrOpened()880 internal void ThrowIfClosedOrOpened() 881 { 882 ThrowPending(); 883 884 switch (this.state) 885 { 886 case CommunicationState.Created: 887 break; 888 889 case CommunicationState.Opening: 890 break; 891 892 case CommunicationState.Opened: 893 throw TraceUtility.ThrowHelperError(this.CreateImmutableException(), Guid.Empty, this); 894 895 case CommunicationState.Closing: 896 throw TraceUtility.ThrowHelperError(this.CreateImmutableException(), Guid.Empty, this); 897 898 case CommunicationState.Closed: 899 throw TraceUtility.ThrowHelperError(this.CreateClosedException(), Guid.Empty, this); 900 901 case CommunicationState.Faulted: 902 throw TraceUtility.ThrowHelperError(this.CreateFaultedException(), Guid.Empty, this); 903 904 default: 905 throw Fx.AssertAndThrow("ThrowIfClosedOrOpened: Unknown CommunicationObject.state"); 906 } 907 } 908 ThrowIfDisposedOrImmutable()909 protected internal void ThrowIfDisposedOrImmutable() 910 { 911 ThrowPending(); 912 913 switch (this.state) 914 { 915 case CommunicationState.Created: 916 break; 917 918 case CommunicationState.Opening: 919 throw TraceUtility.ThrowHelperError(this.CreateImmutableException(), Guid.Empty, this); 920 921 case CommunicationState.Opened: 922 throw TraceUtility.ThrowHelperError(this.CreateImmutableException(), Guid.Empty, this); 923 924 case CommunicationState.Closing: 925 throw TraceUtility.ThrowHelperError(this.CreateClosedException(), Guid.Empty, this); 926 927 case CommunicationState.Closed: 928 throw TraceUtility.ThrowHelperError(this.CreateClosedException(), Guid.Empty, this); 929 930 case CommunicationState.Faulted: 931 throw TraceUtility.ThrowHelperError(this.CreateFaultedException(), Guid.Empty, this); 932 933 default: 934 throw Fx.AssertAndThrow("ThrowIfDisposedOrImmutable: Unknown CommunicationObject.state"); 935 } 936 } 937 ThrowIfDisposedOrNotOpen()938 protected internal void ThrowIfDisposedOrNotOpen() 939 { 940 ThrowPending(); 941 942 switch (this.state) 943 { 944 case CommunicationState.Created: 945 throw TraceUtility.ThrowHelperError(this.CreateNotOpenException(), Guid.Empty, this); 946 947 case CommunicationState.Opening: 948 throw TraceUtility.ThrowHelperError(this.CreateNotOpenException(), Guid.Empty, this); 949 950 case CommunicationState.Opened: 951 break; 952 953 case CommunicationState.Closing: 954 throw TraceUtility.ThrowHelperError(this.CreateClosedException(), Guid.Empty, this); 955 956 case CommunicationState.Closed: 957 throw TraceUtility.ThrowHelperError(this.CreateClosedException(), Guid.Empty, this); 958 959 case CommunicationState.Faulted: 960 throw TraceUtility.ThrowHelperError(this.CreateFaultedException(), Guid.Empty, this); 961 962 default: 963 throw Fx.AssertAndThrow("ThrowIfDisposedOrNotOpen: Unknown CommunicationObject.state"); 964 } 965 } 966 ThrowIfNotOpened()967 internal void ThrowIfNotOpened() 968 { 969 if (this.state == CommunicationState.Created || this.state == CommunicationState.Opening) 970 throw TraceUtility.ThrowHelperError(this.CreateNotOpenException(), Guid.Empty, this); 971 } 972 ThrowIfClosedOrNotOpen()973 internal void ThrowIfClosedOrNotOpen() 974 { 975 ThrowPending(); 976 977 switch (this.state) 978 { 979 case CommunicationState.Created: 980 throw TraceUtility.ThrowHelperError(this.CreateNotOpenException(), Guid.Empty, this); 981 982 case CommunicationState.Opening: 983 throw TraceUtility.ThrowHelperError(this.CreateNotOpenException(), Guid.Empty, this); 984 985 case CommunicationState.Opened: 986 break; 987 988 case CommunicationState.Closing: 989 break; 990 991 case CommunicationState.Closed: 992 throw TraceUtility.ThrowHelperError(this.CreateClosedException(), Guid.Empty, this); 993 994 case CommunicationState.Faulted: 995 throw TraceUtility.ThrowHelperError(this.CreateFaultedException(), Guid.Empty, this); 996 997 default: 998 throw Fx.AssertAndThrow("ThrowIfClosedOrNotOpen: Unknown CommunicationObject.state"); 999 } 1000 } 1001 ThrowPending()1002 internal void ThrowPending() 1003 { 1004 ExceptionQueue queue = this.exceptionQueue; 1005 1006 if (queue != null) 1007 { 1008 Exception exception = queue.GetException(); 1009 1010 if (exception != null) 1011 { 1012 throw TraceUtility.ThrowHelperError(exception, Guid.Empty, this); 1013 } 1014 } 1015 } 1016 1017 // 1018 // State callbacks 1019 // 1020 OnAbort()1021 protected abstract void OnAbort(); 1022 OnClose(TimeSpan timeout)1023 protected abstract void OnClose(TimeSpan timeout); OnEndClose(IAsyncResult result)1024 protected abstract void OnEndClose(IAsyncResult result); OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)1025 protected abstract IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state); 1026 OnOpen(TimeSpan timeout)1027 protected abstract void OnOpen(TimeSpan timeout); OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)1028 protected abstract IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state); OnEndOpen(IAsyncResult result)1029 protected abstract void OnEndOpen(IAsyncResult result); 1030 1031 class AlreadyClosedAsyncResult : CompletedAsyncResult 1032 { AlreadyClosedAsyncResult(AsyncCallback callback, object state)1033 public AlreadyClosedAsyncResult(AsyncCallback callback, object state) 1034 : base(callback, state) 1035 { 1036 } 1037 } 1038 1039 class ExceptionQueue 1040 { 1041 Queue<Exception> exceptions = new Queue<Exception>(); 1042 object thisLock; 1043 ExceptionQueue(object thisLock)1044 internal ExceptionQueue(object thisLock) 1045 { 1046 this.thisLock = thisLock; 1047 } 1048 1049 object ThisLock 1050 { 1051 get { return this.thisLock; } 1052 } 1053 AddException(Exception exception)1054 public void AddException(Exception exception) 1055 { 1056 if (exception == null) 1057 { 1058 return; 1059 } 1060 1061 lock (this.ThisLock) 1062 { 1063 this.exceptions.Enqueue(exception); 1064 } 1065 } 1066 GetException()1067 public Exception GetException() 1068 { 1069 lock (this.ThisLock) 1070 { 1071 if (this.exceptions.Count > 0) 1072 { 1073 return this.exceptions.Dequeue(); 1074 } 1075 } 1076 1077 return null; 1078 } 1079 } 1080 1081 class OpenAsyncResult : AsyncResult 1082 { 1083 static AsyncCompletion onOpenCompletion = new AsyncCompletion(OnOpenCompletion); 1084 1085 CommunicationObject communicationObject; 1086 TimeoutHelper timeout; 1087 OpenAsyncResult(CommunicationObject communicationObject, TimeSpan timeout, AsyncCallback callback, object state)1088 public OpenAsyncResult(CommunicationObject communicationObject, TimeSpan timeout, AsyncCallback callback, object state) 1089 : base(callback, state) 1090 { 1091 this.communicationObject = communicationObject; 1092 this.timeout = new TimeoutHelper(timeout); 1093 1094 base.OnCompleting = new Action<AsyncResult, Exception>(OnOpenCompleted); 1095 1096 if (InvokeOpen()) 1097 { 1098 this.Complete(true); 1099 } 1100 } 1101 InvokeOpen()1102 bool InvokeOpen() 1103 { 1104 IAsyncResult result = this.communicationObject.OnBeginOpen(this.timeout.RemainingTime(), 1105 base.PrepareAsyncCompletion(onOpenCompletion), this); 1106 if (result.CompletedSynchronously) 1107 { 1108 return OnOpenCompletion(result); 1109 } 1110 else 1111 { 1112 return false; 1113 } 1114 } 1115 NotifyOpened()1116 void NotifyOpened() 1117 { 1118 this.communicationObject.OnOpened(); 1119 if (!this.communicationObject.onOpenedCalled) 1120 { 1121 throw TraceUtility.ThrowHelperError( 1122 this.communicationObject.CreateBaseClassMethodNotCalledException("OnOpened"), 1123 Guid.Empty, this.communicationObject); 1124 } 1125 } 1126 OnOpenCompleted(AsyncResult result, Exception exception)1127 void OnOpenCompleted(AsyncResult result, Exception exception) 1128 { 1129 if (exception != null) 1130 { 1131 if (DiagnosticUtility.ShouldTraceWarning) 1132 { 1133 TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.CommunicationObjectOpenFailed, 1134 SR.GetString(SR.TraceCodeCommunicationObjectOpenFailed, this.communicationObject.GetCommunicationObjectType().ToString()), 1135 this, exception); 1136 } 1137 1138 this.communicationObject.Fault(); 1139 } 1140 } 1141 OnOpenCompletion(IAsyncResult result)1142 static bool OnOpenCompletion(IAsyncResult result) 1143 { 1144 OpenAsyncResult thisPtr = (OpenAsyncResult)result.AsyncState; 1145 thisPtr.communicationObject.OnEndOpen(result); 1146 thisPtr.NotifyOpened(); 1147 return true; 1148 } 1149 End(IAsyncResult result)1150 public static void End(IAsyncResult result) 1151 { 1152 AsyncResult.End<OpenAsyncResult>(result); 1153 } 1154 } 1155 1156 class CloseAsyncResult : TraceAsyncResult 1157 { 1158 static AsyncCompletion onCloseCompletion = new AsyncCompletion(OnCloseCompletion); 1159 1160 CommunicationObject communicationObject; 1161 TimeoutHelper timeout; 1162 CloseAsyncResult(CommunicationObject communicationObject, TimeSpan timeout, AsyncCallback callback, object state)1163 public CloseAsyncResult(CommunicationObject communicationObject, TimeSpan timeout, AsyncCallback callback, object state) 1164 : base(callback, state) 1165 { 1166 this.communicationObject = communicationObject; 1167 this.timeout = new TimeoutHelper(timeout); 1168 1169 base.OnCompleting = new Action<AsyncResult, Exception>(OnCloseCompleted); 1170 if (InvokeClose()) 1171 { 1172 this.Complete(true); 1173 } 1174 } 1175 InvokeClose()1176 bool InvokeClose() 1177 { 1178 IAsyncResult result = this.communicationObject.OnBeginClose(this.timeout.RemainingTime(), 1179 base.PrepareAsyncCompletion(onCloseCompletion), this); 1180 if (result.CompletedSynchronously) 1181 { 1182 return OnCloseCompletion(result); 1183 } 1184 else 1185 { 1186 return false; 1187 } 1188 } 1189 NotifyClosed()1190 void NotifyClosed() 1191 { 1192 this.communicationObject.OnClosed(); 1193 if (!this.communicationObject.onClosedCalled) 1194 { 1195 throw TraceUtility.ThrowHelperError( 1196 this.communicationObject.CreateBaseClassMethodNotCalledException("OnClosed"), 1197 Guid.Empty, this.communicationObject); 1198 } 1199 } 1200 OnCloseCompleted(AsyncResult result, Exception exception)1201 void OnCloseCompleted(AsyncResult result, Exception exception) 1202 { 1203 if (exception != null) 1204 { 1205 if (DiagnosticUtility.ShouldTraceWarning) 1206 { 1207 TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.CommunicationObjectCloseFailed, 1208 SR.GetString(SR.TraceCodeCommunicationObjectCloseFailed, this.communicationObject.GetCommunicationObjectType().ToString()), 1209 this, exception); 1210 } 1211 1212 this.communicationObject.Abort(); 1213 } 1214 } 1215 OnCloseCompletion(IAsyncResult result)1216 static bool OnCloseCompletion(IAsyncResult result) 1217 { 1218 CloseAsyncResult thisPtr = (CloseAsyncResult)result.AsyncState; 1219 thisPtr.communicationObject.OnEndClose(result); 1220 thisPtr.NotifyClosed(); 1221 return true; 1222 } 1223 End(IAsyncResult result)1224 public static void End(IAsyncResult result) 1225 { 1226 AsyncResult.End<CloseAsyncResult>(result); 1227 } 1228 } 1229 } 1230 } 1231