Code:
/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / TransactionBridge / Microsoft / Transactions / Wsat / Protocol / Enlistment.cs / 1 / Enlistment.cs
//------------------------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- // This file contains classes representing various types of enlistments using System; using System.ServiceModel.Channels; using System.Collections; using System.Collections.Generic; using System.ServiceModel; using System.ServiceModel.Transactions; using System.Diagnostics; using System.ServiceModel.Security; using System.Threading; using Microsoft.Transactions.Bridge; using Microsoft.Transactions.Wsat.InputOutput; using Microsoft.Transactions.Wsat.Messaging; using Microsoft.Transactions.Wsat.StateMachines; using Activity = System.ServiceModel.Diagnostics.Activity; using DiagnosticUtility = Microsoft.Transactions.Bridge.DiagnosticUtility; namespace Microsoft.Transactions.Wsat.Protocol { // Base class for all enlistment objects abstract class TransactionEnlistment { protected ProtocolState state; protected StateMachine stateMachine; protected TransactionContextManager ourContextManager; protected Enlistment enlistment; protected Guid enlistmentId; protected ProtocolProviderCallback lastCallback; protected object lastCallbackState; int retries; bool removeEnlistmentFromLookupTable; protected TransactionEnlistment(ProtocolState state) : this(state, Guid.NewGuid()) { } protected TransactionEnlistment(ProtocolState state, Guid enlistmentId) { this.state = state; this.enlistmentId = enlistmentId; } public override string ToString() { return this.enlistmentId.ToString(); } public ProtocolState State { get { return this.state; } } public TransactionContextManager ContextManager { get { return this.ourContextManager; } set { this.ourContextManager = value; } } public Enlistment Enlistment { get { return this.enlistment; } } public Guid EnlistmentId { get { return this.enlistmentId; } } public StateMachine StateMachine { get { return this.stateMachine; } } public int Retries { get { return this.retries; } set { this.retries = value; } } public void SetCallback(ProtocolProviderCallback callback, object callbackState) { this.lastCallback = callback; this.lastCallbackState = callbackState; } public void DeliverCallback(Status status) { this.lastCallback(this.enlistment, status, this.lastCallbackState); this.lastCallback = null; this.lastCallbackState = null; } // Calculate a timespan derived from the input (TimeSpan.Zero means invalid timeout) TimeSpan CalculateTimeout(uint expires, bool expiresPresent) { if (!expiresPresent) { // No value was provided. Use the default return state.Config.DefaultTimeout; } if (expires == 0) { // An explicit zero value was provided. Enforce the maximum timeout. // A value of zero means no timeout for both the MaxTimeout property and the TM return state.Config.MaxTimeout; } TimeSpan timeout = TimeoutHelper.FromMilliseconds(expires); if (state.Config.MaxTimeout != TimeSpan.Zero && state.Config.MaxTimeout < timeout) { timeout = state.Config.MaxTimeout; } return timeout; } public EnlistmentOptions CreateEnlistmentOptions(uint expires, bool expiresPresent, System.Transactions.IsolationLevel isoLevel, IsolationFlags isoFlags, string description) { EnlistmentOptions options = new EnlistmentOptions(); // Expires options.Expires = CalculateTimeout(expires, expiresPresent); // IsoLevel options.IsoLevel = isoLevel; if (options.IsoLevel == System.Transactions.IsolationLevel.Unspecified) { options.IsoLevel = System.Transactions.IsolationLevel.Serializable; } // IsoFlags options.IsolationFlags = isoFlags; // Description options.Description = description; return options; } protected void VerifyAndTraceEnlistmentOptions() { EnlistmentOptions options = this.enlistment.EnlistmentOptions; // By the time that TransactionEnlistment.SetTransactionContext is called, // the EnlistmentOptions property must be properly setup. The // TransactionEnlistment type is internal to the implementation. // Therefore, the assumptions are things that only a Microsoft dev could // violate. Violations of these assumptions is a bug that needs to be // reported back to Microsoft immediately. if (options == null) { DiagnosticUtility.FailFast("Need EnlistmentOptions for context"); } if (options.IsoLevel == System.Transactions.IsolationLevel.Unspecified) { DiagnosticUtility.FailFast("Need IsolationLevel for context"); } if (this.enlistment.LocalTransactionId == Guid.Empty) { DiagnosticUtility.FailFast("Need LocalTransactionId for context"); } if (string.IsNullOrEmpty(this.enlistment.RemoteTransactionId)) { DiagnosticUtility.FailFast("Need RemoteTransactionId for context"); } if (DebugTrace.Info) { DebugTrace.TxTrace(TraceLevel.Info, this.enlistmentId, "Local transactionId is {0}", this.enlistment.LocalTransactionId); DebugTrace.TxTrace(TraceLevel.Info, this.enlistmentId, "Remote transactionId is {0}", this.enlistment.RemoteTransactionId); DebugTrace.TxTrace(TraceLevel.Info, this.enlistmentId, "Transaction timeout is {0} seconds", options.Expires.TotalSeconds); DebugTrace.TxTrace(TraceLevel.Info, this.enlistmentId, "Transaction isolation level is {0}", options.IsoLevel); } } protected void TraceTransferEvent() { // Associate the enlistment identifier with the transaction identifier // We could do this elsewhere, but this is a good place to do it if (Microsoft.Transactions.Bridge.DiagnosticUtility.ShouldUseActivity) { using (Activity.CreateActivity(this.enlistment.LocalTransactionId)) { Microsoft.Transactions.Bridge.DiagnosticUtility.DiagnosticTrace.TraceTransfer(this.enlistmentId); } } } protected void FindAndActivateTransactionContextManager() { // Find the context manager - there must be one in the table when this is called string identifier = this.enlistment.RemoteTransactionId; TransactionContextManager contextManager = state.Lookup.FindTransactionContextManager(identifier); Debug.Assert(contextManager != null, "Must have a contextManager in FindAndActivateTransactionContextManager"); ActivateTransactionContextManager(contextManager); } protected void ActivateTransactionContextManager(TransactionContextManager contextManager) { TransactionContext context = CreateTransactionContext(); contextManager.StateMachine.Enqueue(new TransactionContextCreatedEvent(contextManager, context)); } TransactionContext CreateTransactionContext() { EnlistmentOptions options = this.enlistment.EnlistmentOptions; string contextId = this.enlistment.RemoteTransactionId; Guid transactionId = this.enlistment.LocalTransactionId; CoordinationContext context = new CoordinationContext(this.state.ProtocolVersion); RequestSecurityTokenResponse issuedToken = null; context.Expires = (uint) TimeoutHelper.ToMilliseconds(options.Expires); context.Identifier = contextId; context.LocalTransactionId = transactionId; context.IsolationLevel = options.IsoLevel; context.IsolationFlags = options.IsolationFlags; context.Description = options.Description; string identifier = CoordinationContext.IsNativeIdentifier(contextId, transactionId) ? null : contextId; string tokenId = null; if (state.Config.PortConfiguration.SupportingTokensEnabled) { CoordinationServiceSecurity.CreateIssuedToken(transactionId, contextId, this.state.ProtocolVersion, out issuedToken, out tokenId); } AddressHeader refParam = new WsatRegistrationHeader(transactionId, identifier, tokenId); context.RegistrationService = state.RegistrationCoordinatorListener.CreateEndpointReference(refParam); return new TransactionContext(context, issuedToken); } public virtual void OnStateMachineComplete() { if (this.removeEnlistmentFromLookupTable) { state.Lookup.RemoveEnlistment(this); this.removeEnlistmentFromLookupTable = false; } if (this.ourContextManager != null) { this.ourContextManager.StateMachine.Enqueue( new TransactionContextTransactionDoneEvent(this.ourContextManager)); } } protected void AddToLookupTable() { state.Lookup.AddEnlistment(this); this.removeEnlistmentFromLookupTable = true; } } abstract class CoordinatorEnlistmentBase : TransactionEnlistment { // This EPR represents our protocol service. It is used to send // register messages and as the 'from' field when sending protocol messages protected EndpointAddress participantService; protected TwoPhaseCommitCoordinatorProxy coordinatorProxy; protected CoordinatorEnlistmentBase(ProtocolState state) : base(state) { } protected CoordinatorEnlistmentBase(ProtocolState state, Guid enlistmentId) : base(state, enlistmentId) { } public TwoPhaseCommitCoordinatorProxy CoordinatorProxy { get { return this.coordinatorProxy; } } public EndpointAddress ParticipantService { get { return this.participantService; } } public void SetCoordinatorProxy (TwoPhaseCommitCoordinatorProxy proxy) { if (this.participantService == null) { // Documents the assumption that CreateParticipantService is always // called before SetCoordinatorProxy. If this assumption is violated, // we have a product bug that needs to be reported back to Microsoft. DiagnosticUtility.FailFast("participantService needed for coordinatorProxy"); } proxy.AddRef(); this.coordinatorProxy = proxy; this.coordinatorProxy.From = this.participantService; } public override void OnStateMachineComplete() { base.OnStateMachineComplete(); if (this.coordinatorProxy != null) { this.coordinatorProxy.Release(); } } public void CreateParticipantService() { // Create a header representing the enlistment EnlistmentHeader header = new EnlistmentHeader(this.enlistmentId); this.participantService = state.TwoPhaseCommitParticipantListener.CreateEndpointReference(header); // In non-recovery scenarios, the coordinator proxy is set at RegisterResponse time, // so when CreateParticipantService is called this.coordinatorProxy will be null. // // In recovery scenarios, we will have the coordinator proxy in hand in the constructor, // but we won't be able to create the participant service until later if (this.coordinatorProxy != null) { this.coordinatorProxy.From = this.participantService; } } } // Representation of a remote coordinator (superior) volatile enlistment class VolatileCoordinatorEnlistment : CoordinatorEnlistmentBase { CoordinatorEnlistment coordinator; public VolatileCoordinatorEnlistment(ProtocolState state, CoordinatorEnlistment coordinator) : base(state) { this.coordinator = coordinator; // We use the same enlistment and state machine as the main coordinator this.enlistment = this.coordinator.Enlistment; this.stateMachine = this.coordinator.StateMachine; CreateParticipantService(); } public CoordinatorEnlistment Coordinator { get { return this.coordinator; } } } // Representation of a remote coordinator (superior) enlistment class CoordinatorEnlistment : CoordinatorEnlistmentBase { // The volatile coordinator that is either registering or registered, VolatileCoordinatorEnlistment registerVolatileCoordinator; // The volatile coordinator for which we are currently processing a volatile Prepare VolatileCoordinatorEnlistment preparingVolatileCoordinator; // The last volatile coordinator for which we processed a volatile Prepare VolatileCoordinatorEnlistment lastCompletedVolatileCoordinator; // The recovered coordinator service // This is only set for recovered enlistments EndpointAddress recoveredCoordinatorService; // We send register messages to this endpoint CoordinationContext superiorContext; RequestSecurityTokenResponse superiorRstr; RegistrationProxy registrationProxy; TmEnlistPrePrepareEvent enlistPrePrepareEvent; // The list of volatile coordinators we've created ListvolatileCoordinators; // This constructor is called for new non-root transactions // Every such transaction is created thanks to a CCC w/ context message // Therefore, we will always be entrusted with a TransactionContextManager // instance at this point in time. public CoordinatorEnlistment(ProtocolState state, TransactionContextManager contextManager, CoordinationContext context, RequestSecurityTokenResponse rstr) : base(state) { this.ourContextManager = contextManager; this.superiorContext = context; this.superiorRstr = rstr; ConfigureEnlistment(context); this.stateMachine = new CoordinatorStateMachine (this); this.stateMachine.ChangeState(state.States.CoordinatorInitializing); } // This constructor is called during recovery public CoordinatorEnlistment (ProtocolState state, Enlistment enlistment, Guid enlistmentId, EndpointAddress service) : base (state, enlistmentId) { this.enlistment = enlistment; this.enlistment.ProtocolProviderContext = this; this.recoveredCoordinatorService = service; this.stateMachine = new CoordinatorStateMachine (this); this.coordinatorProxy = state.TryCreateTwoPhaseCommitCoordinatorProxy (service); if (this.coordinatorProxy == null) { // We have recovered an endpoint for which we cannot create a proxy // We can't just drop this enlistment, because we'd risk sending a polite message // under the wrong circumstances. So we keep the enlistment around in a failed // state, with a null proxy. Incoming messages will check for that null // proxy and send InvalidPolicy faults in response to any new messages. if (RecoveredCoordinatorInvalidMetadataRecord.ShouldTrace) { RecoveredCoordinatorInvalidMetadataRecord.Trace( this.enlistmentId, enlistment.RemoteTransactionId, service, this.state.ProtocolVersion ); } this.stateMachine.ChangeState(state.States.CoordinatorFailedRecovery); } else { this.stateMachine.ChangeState(state.States.CoordinatorRecovering); } AddToLookupTable(); } void ConfigureEnlistment(CoordinationContext context) { Enlistment enlistment = new Enlistment(); string transactionId = context.Identifier; if (transactionId == null) { // The assumption in this code is that by the time the ConfigureEnlistment // method is called, the context in the WS-AT message was already validated // and proper error handling already occurred in case things like the // TransactionId were not set. If this assumption is violated, we no longer // have a way to communicate to the user how to fix things-- somehow we got // to this place in the code and that just shouldn't happen. This is a bug // that needs to be reported back to Microsoft. DiagnosticUtility.FailFast("Need transactionId to create enlistment"); } enlistment.RemoteTransactionId = transactionId; enlistment.LocalTransactionId = Ports.GetGuidFromTransactionId(transactionId); enlistment.ProtocolProviderContext = this; this.enlistment = enlistment; } // // Properties // public CoordinationContext SuperiorContext { get { return this.superiorContext; } } public RequestSecurityTokenResponse SuperiorIssuedToken { get { return this.superiorRstr; } } public RegistrationProxy RegistrationProxy { get { return this.registrationProxy; } } public VolatileCoordinatorEnlistment RegisterVolatileCoordinator { get { return this.registerVolatileCoordinator; } set { this.registerVolatileCoordinator = value; } } public VolatileCoordinatorEnlistment PreparingVolatileCoordinator { get { return this.preparingVolatileCoordinator; } set { this.preparingVolatileCoordinator = value; } } public VolatileCoordinatorEnlistment LastCompletedVolatileCoordinator { get { return this.lastCompletedVolatileCoordinator; } set { this.lastCompletedVolatileCoordinator = value; } } public TmEnlistPrePrepareEvent EnlistPrePrepareEvent { get { return this.enlistPrePrepareEvent; } set { if (this.enlistPrePrepareEvent != null && value != null) { // The event can only be set by internal code. The event should // not have a value and then be set by a caller to a new, non-null // value. Doing so indicates a product bug that must be reported back // to Microsoft. DiagnosticUtility.FailFast("Cannot clobber EnlistPrePrepareEvent"); } this.enlistPrePrepareEvent = value; } } public void SetRegistrationProxy(RegistrationProxy proxy) { proxy.AddRef(); this.registrationProxy = proxy; } public void OnEnlistPrePrepare(TmEnlistPrePrepareEvent e) { this.enlistPrePrepareEvent = e; // Fault in the list. We can do this safely because we're in the // state machine's synchronization domain if (this.volatileCoordinators == null) { this.volatileCoordinators = new List (); } // Make the next volatile coordinator enlistment VolatileCoordinatorEnlistment enlistment = new VolatileCoordinatorEnlistment(state, this); this.volatileCoordinators.Add(enlistment); state.Lookup.AddEnlistment(enlistment); if (this.registerVolatileCoordinator != null) { // If the VolatileCoordinatorEnlistment that is registering/registered is // already set, then this method was called in error. Since the code path // is only accessible by internal code, calling the method twice indicates // a product bug that must be reported back to Microsoft. DiagnosticUtility.FailFast("Duplicate EnlistPrePrepare from TM"); } this.registerVolatileCoordinator = enlistment; } public void OnCoordinatorEnlisted() { CreateParticipantService(); AddToLookupTable(); VerifyAndTraceEnlistmentOptions(); TraceTransferEvent(); } public void OnDurableCoordinatorActive() { // It's very important that we do this here and no sooner // See MB 50939 for more details FindAndActivateTransactionContextManager(); } public override void OnStateMachineComplete() { base.OnStateMachineComplete(); if (this.registrationProxy != null) { this.registrationProxy.Release(); } if (this.volatileCoordinators != null) { foreach (VolatileCoordinatorEnlistment volatileEnlistment in this.volatileCoordinators) { state.Lookup.RemoveEnlistment(volatileEnlistment); } } // We don't clean up any pending EnlistPrePrepare events because the TM doesn't care // We might be sending too many callbacks in a row, which could confuse a PPL implementation } } class ParticipantEnlistment : TransactionEnlistment { ControlProtocol protocol; // This EPR is ours. It is used to send a register response message and as the 'from' // when sending protocol messages EndpointAddress coordinatorService; TwoPhaseCommitParticipantProxy participantProxy; TimeSpan timeoutEstimate; long lastMessageTime; // This constructor is called during recovery public ParticipantEnlistment(ProtocolState state, Enlistment enlistment, Guid enlistmentId, EndpointAddress service) : base(state, enlistmentId) { this.enlistment = enlistment; this.enlistment.ProtocolProviderContext = this; this.protocol = ControlProtocol.Durable2PC; this.stateMachine = new DurableStateMachine (this); this.participantProxy = state.TryCreateTwoPhaseCommitParticipantProxy (service); if (this.participantProxy == null) { // This means that we are recovering an endpoint whose policy no longer intersects // with our own. This can happen. For example, we were interoperating with some // other system, and then the administrator turned off our interop endpoint. // // There is also the possibility for another MS endpoint to be configured in such a // way that while we can no longer talk to it, given the EPR it provided at registration time. // That endpoint might then be reconfigured to intersect with us again using a // different policy choice. // // We can't just drop this enlistment, because we'd risk sending a polite message // under the wrong circumstances. So we keep the enlistment around in a failed // state, with a null proxy. Incoming messages will check for that null // proxy and send InvalidPolicy faults in response to any new messages. if (RecoveredParticipantInvalidMetadataRecord.ShouldTrace) { RecoveredParticipantInvalidMetadataRecord.Trace( this.enlistmentId, enlistment.RemoteTransactionId, service, this.state.ProtocolVersion ); } this.stateMachine.ChangeState(state.States.DurableFailedRecovery); } else { this.stateMachine.ChangeState(state.States.DurableRecovering); } AddToLookupTable(); } // This constructor is called for new participant enlistments public ParticipantEnlistment(ProtocolState state, WsatRegistrationHeader header, ControlProtocol protocol, TwoPhaseCommitParticipantProxy proxy) : base(state) { this.protocol = protocol; proxy.AddRef(); this.participantProxy = proxy; ConfigureEnlistment(header); CreateCoordinatorService(); switch (protocol) { case ControlProtocol.Durable2PC: this.stateMachine = new DurableStateMachine (this); this.stateMachine.ChangeState(state.States.DurableRegistering); break; case ControlProtocol.Volatile2PC: this.stateMachine = new VolatileStateMachine (this); this.stateMachine.ChangeState(state.States.VolatileRegistering); break; default: // An invalid Enum value on this internal code path indicates // a product bug and violates assumptions about // valid values in MSDTC. DiagnosticUtility.FailFast("Invalid protocol"); break; // Keep the compiler happy } } // This constructor is called for new dummy subordinate enlistments public ParticipantEnlistment(ProtocolState state, Enlistment coordinatorEnlistment, TransactionContextManager contextManager) : base(state) { this.protocol = ControlProtocol.Volatile2PC; // Take ownership of the context manager this.ourContextManager = contextManager; // Create a 2PC enlistment so that when we transition to the SubordinateFinished state, // it will be Phase 1 already: there won't be any more legitimate CCC w/ context messages this.enlistment = new Enlistment(); this.enlistment.LocalTransactionId = coordinatorEnlistment.LocalTransactionId; this.enlistment.RemoteTransactionId = coordinatorEnlistment.RemoteTransactionId; this.enlistment.NotificationMask = Notifications.TwoPhaseCommit | Notifications.Volatile; this.enlistment.ProtocolProviderContext = this; this.stateMachine = new SubordinateStateMachine(this); this.stateMachine.ChangeState(state.States.SubordinateInitializing); } public TimeSpan TimeoutEstimate { get { return this.timeoutEstimate; } } public override void OnStateMachineComplete() { base.OnStateMachineComplete(); if (this.participantProxy != null) { this.participantProxy.Release(); } } void ConfigureEnlistment(WsatRegistrationHeader header) { Enlistment enlistment = new Enlistment(); string contextId = header.ContextId; if (contextId == null) { contextId = CoordinationContext.CreateNativeIdentifier(header.TransactionId); } enlistment.LocalTransactionId = header.TransactionId; enlistment.RemoteTransactionId = contextId; // Some volatile enlistments might not want outcome, but they'll only tell us that // when we tell them to Prepare. Consequently, all participants must register // in advance for 2PC Notifications mask = Notifications.TwoPhaseCommit; switch (this.protocol) { case ControlProtocol.Volatile2PC: // Volatile registrants expect Phase Zero messages // We also add the volatile flag which ensures no recovery mask |= Notifications.Phase0 | Notifications.Volatile; break; case ControlProtocol.Durable2PC: break; default: // An invalid Enum value on this internal code path indicates // a product bug and violates assumptions about // valid values in MSDTC. DiagnosticUtility.FailFast("Invalid protocol"); break; // Keep the compiler happy } enlistment.NotificationMask = mask; enlistment.ProtocolProviderContext = this; this.enlistment = enlistment; } public void CreateCoordinatorService() { if ((this.protocol != ControlProtocol.Durable2PC) && (this.protocol != ControlProtocol.Volatile2PC)) { // The CoordinatorService should only be created for // Durable|Volatile2PC. Anything else is a bug. DiagnosticUtility.FailFast("Need protocol for coordinator service"); } EnlistmentHeader header = new EnlistmentHeader(this.enlistmentId, this.protocol); this.coordinatorService = state.TwoPhaseCommitCoordinatorListener.CreateEndpointReference (header); this.participantProxy.From = this.coordinatorService; } public void OnParticipantRegistered() { AddToLookupTable(); VerifyAndTraceEnlistmentOptions(); TraceTransferEvent(); // Calculate the approximate time when the transaction will time out // This is used later by the preparing timer this.timeoutEstimate = state.ElapsedTime + this.enlistment.EnlistmentOptions.Expires; } public void OnSubordinateRegistered() { FindAndActivateTransactionContextManager(); VerifyAndTraceEnlistmentOptions(); TraceTransferEvent(); // We don't need to add ourselves to the lookup table } // // Properties // public ControlProtocol ControlProtocol { get { return this.protocol; } } public long LastMessageTime { get { return this.lastMessageTime; } set { this.lastMessageTime = value; } } public EndpointAddress CoordinatorService { get { return this.coordinatorService; } } public TwoPhaseCommitParticipantProxy ParticipantProxy { get { return this.participantProxy; } } } class CompletionEnlistment : TransactionEnlistment { // This EPR is ours. It is used to send a register response message and as the 'from' // when sending protocol messages EndpointAddress coordinatorService; CompletionParticipantProxy participantProxy; // // Construction // public CompletionEnlistment(ProtocolState state) : base(state, Guid.Empty) { ConfigureEnlistment(); this.stateMachine = new CompletionStateMachine(this); this.stateMachine.ChangeState(state.States.CompletionInitializing); } public override void OnStateMachineComplete() { base.OnStateMachineComplete(); if (this.participantProxy != null) { this.participantProxy.Release(); } } void ConfigureEnlistment() { Enlistment enlistment = new Enlistment(); enlistment.ProtocolProviderContext = this; this.enlistment = enlistment; } public EndpointAddress CoordinatorService { get { return this.coordinatorService; } } public CompletionParticipantProxy ParticipantProxy { get { return this.participantProxy; } } public void SetCompletionProxy(CompletionParticipantProxy proxy) { proxy.AddRef(); this.participantProxy = proxy; } public void OnRootTransactionCreated() { this.enlistmentId = this.enlistment.LocalTransactionId; this.enlistment.RemoteTransactionId = CoordinationContext.CreateNativeIdentifier(this.enlistmentId); EnlistmentHeader header = new EnlistmentHeader(this.enlistmentId); this.coordinatorService = state.CompletionCoordinatorListener.CreateEndpointReference(header); this.ourContextManager = new TransactionContextManager(state, this.enlistment.RemoteTransactionId); state.Lookup.AddTransactionContextManager(this.ourContextManager); ActivateTransactionContextManager(this.ourContextManager); AddToLookupTable(); VerifyAndTraceEnlistmentOptions(); TraceTransferEvent(); } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- PageContentAsyncResult.cs
- MetricEntry.cs
- CompositeFontFamily.cs
- InvalidProgramException.cs
- SqlServer2KCompatibilityAnnotation.cs
- InplaceBitmapMetadataWriter.cs
- Debug.cs
- XmlTypeMapping.cs
- Formatter.cs
- HtmlElement.cs
- RectAnimationUsingKeyFrames.cs
- InlineObject.cs
- CompilationLock.cs
- BitVector32.cs
- GenericTextProperties.cs
- ColumnResizeUndoUnit.cs
- AvTrace.cs
- TypeConstant.cs
- ZipIOCentralDirectoryDigitalSignature.cs
- StringFreezingAttribute.cs
- SamlSubjectStatement.cs
- SharedPersonalizationStateInfo.cs
- RadioButtonBaseAdapter.cs
- UserInitiatedNavigationPermission.cs
- WebColorConverter.cs
- ConfigurationPropertyAttribute.cs
- ParseNumbers.cs
- DataGridViewRowConverter.cs
- X509Certificate.cs
- EventWaitHandle.cs
- ReferencedAssembly.cs
- XmlElementElementCollection.cs
- DesignerTransaction.cs
- VisualCollection.cs
- PropertyValueChangedEvent.cs
- ConnectionPoint.cs
- DescendentsWalkerBase.cs
- RC2.cs
- XmlSequenceWriter.cs
- OrderPreservingPipeliningSpoolingTask.cs
- MemberAssignmentAnalysis.cs
- Win32SafeHandles.cs
- SecureStringHasher.cs
- SpoolingTaskBase.cs
- SweepDirectionValidation.cs
- VariableAction.cs
- TransformValueSerializer.cs
- HttpModuleAction.cs
- EffectiveValueEntry.cs
- SizeConverter.cs
- StyleTypedPropertyAttribute.cs
- SortDescriptionCollection.cs
- RequestCachePolicy.cs
- CommentEmitter.cs
- Menu.cs
- StringFreezingAttribute.cs
- RadioButtonBaseAdapter.cs
- Size.cs
- sqlstateclientmanager.cs
- RSAOAEPKeyExchangeFormatter.cs
- StringDictionaryCodeDomSerializer.cs
- WindowsSspiNegotiation.cs
- linebase.cs
- ThreadInterruptedException.cs
- OdbcError.cs
- HtmlInputButton.cs
- TemplatedEditableDesignerRegion.cs
- X509ChainPolicy.cs
- JsonReader.cs
- PenContext.cs
- EraserBehavior.cs
- IIS7UserPrincipal.cs
- DataRelationPropertyDescriptor.cs
- AuthenticatingEventArgs.cs
- RegexMatch.cs
- MobileComponentEditorPage.cs
- CrossContextChannel.cs
- SignedXml.cs
- BrowserCapabilitiesFactory.cs
- DbConvert.cs
- TextRangeAdaptor.cs
- CommandID.cs
- ScriptingScriptResourceHandlerSection.cs
- CodeCompileUnit.cs
- TerminateSequence.cs
- ParallelRangeManager.cs
- RTTypeWrapper.cs
- ExecutionContext.cs
- XmlNamespaceDeclarationsAttribute.cs
- WebPartRestoreVerb.cs
- ParenthesizePropertyNameAttribute.cs
- SessionSymmetricTransportSecurityProtocolFactory.cs
- StackOverflowException.cs
- TraceListeners.cs
- UIElementAutomationPeer.cs
- CompilerInfo.cs
- InvalidOperationException.cs
- Matrix3DConverter.cs
- FillRuleValidation.cs
- FollowerQueueCreator.cs