Code:
/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / ServiceModel / System / ServiceModel / Channels / PeerConnector.cs / 1 / PeerConnector.cs
//------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //----------------------------------------------------------- namespace System.ServiceModel.Channels { using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Runtime.Serialization; using System.ServiceModel; using System.ServiceModel.Description; using System.ServiceModel.Diagnostics; using System.Threading; // Connector is responsible for transitioning neighbors to connected state. class PeerConnector: IPeerConnectorContract { enum State { Created, Opened, Closed, Closing } PeerNodeConfig config; PeerMaintainer maintainer; PeerNeighborManager neighborManager; State state; object thisLock; // TypedMessageConverters: TypedMessageConverter connectInfoMessageConverter; TypedMessageConverter disconnectInfoMessageConverter; TypedMessageConverter refuseInfoMessageConverter; TypedMessageConverter welcomeInfoMessageConverter; // To keep track of timers to transition neighbors to connected state DictionarytimerTable; public PeerConnector(PeerNodeConfig config, PeerNeighborManager neighborManager, PeerMaintainer maintainer) { DiagnosticUtility.DebugAssert(config != null, "Config is expected to non-null"); DiagnosticUtility.DebugAssert(neighborManager != null, "NeighborManager is expected to be non-null"); DiagnosticUtility.DebugAssert(maintainer != null, "Maintainer is expected to be non-null"); DiagnosticUtility.DebugAssert(config.NodeId != PeerTransportConstants.InvalidNodeId, "Invalid NodeId"); DiagnosticUtility.DebugAssert(config.MaxNeighbors > 0, "MaxNeighbors is expected to be non-zero positive value"); DiagnosticUtility.DebugAssert(config.ConnectTimeout > 0, "ConnectTimeout is expected to be non-zero positive value"); this.thisLock = new object(); this.config = config; this.neighborManager = neighborManager; this.maintainer = maintainer; this.timerTable = new Dictionary (); this.state = State.Created; } object ThisLock { get { return this.thisLock; } } internal TypedMessageConverter ConnectInfoMessageConverter { get { if (connectInfoMessageConverter == null) { connectInfoMessageConverter = TypedMessageConverter.Create(typeof(ConnectInfo), PeerStrings.ConnectAction); } return connectInfoMessageConverter; } } internal TypedMessageConverter DisconnectInfoMessageConverter { get { if (disconnectInfoMessageConverter == null) { disconnectInfoMessageConverter = TypedMessageConverter.Create(typeof(DisconnectInfo), PeerStrings.DisconnectAction); } return disconnectInfoMessageConverter; } } internal TypedMessageConverter RefuseInfoMessageConverter { get { if (refuseInfoMessageConverter == null) { refuseInfoMessageConverter = TypedMessageConverter.Create(typeof(RefuseInfo), PeerStrings.RefuseAction); } return refuseInfoMessageConverter; } } internal TypedMessageConverter WelcomeInfoMessageConverter { get { if (welcomeInfoMessageConverter == null) { welcomeInfoMessageConverter = TypedMessageConverter.Create(typeof(WelcomeInfo), PeerStrings.WelcomeAction); } return welcomeInfoMessageConverter; } } // Add a timer for the specified neighbor to the timer table. The timer is only added // if Connector is open and the neighbor is in Connecting state. bool AddTimer (IPeerNeighbor neighbor) { bool added = false; lock (ThisLock) { if (state == State.Opened && neighbor.State == PeerNeighborState.Connecting) { IOThreadTimer timer = new IOThreadTimer(new WaitCallback(OnConnectTimeout), neighbor, true); timer.Set(this.config.ConnectTimeout); this.timerTable.Add(neighbor, timer); added = true; } } return added; } //this method takes care of closing the message. void SendMessageToNeighbor(IPeerNeighbor neighbor, Message message, PeerMessageHelpers.CleanupCallback cleanupCallback) { bool fatal = false; try { neighbor.Send(message); } catch (Exception e) { if (DiagnosticUtility.IsFatal(e)) { fatal = true; throw; } if (e is CommunicationException || e is QuotaExceededException || e is ObjectDisposedException || e is TimeoutException) { DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information); // Message failed to transmit due to quota exceeding or channel failure if (cleanupCallback != null) { cleanupCallback(neighbor, PeerCloseReason.InternalFailure, e); } } else { throw; } } finally { if(!fatal) message.Close(); } } // If neighbor cannot transition to connected state, this method cleans up the timer and // closes the neighbor void CleanupOnConnectFailure(IPeerNeighbor neighbor, PeerCloseReason reason, Exception exception) { // timer will not be found if neighbor is already closed or connected. if (RemoveTimer(neighbor)) { this.neighborManager.CloseNeighbor(neighbor, reason, PeerCloseInitiator.LocalNode, exception); } } public void Close() { Dictionary table; lock (ThisLock) { table = this.timerTable; this.timerTable = null; this.state = State.Closed; } // Cancel each timer if (table != null) { foreach (IOThreadTimer timer in table.Values) timer.Cancel(); } } public void Closing() { lock (ThisLock) { this.state = State.Closing; } } // Complete processing of Disconnect or Refuse message from the neighbor void CompleteTerminateMessageProcessing(IPeerNeighbor neighbor, PeerCloseReason closeReason, IList referrals) { // Close the neighbor after setting the neighbor state to Disconnected. // The set can fail if the neighbor is already being closed and that is ok. if (neighbor.TrySetState(PeerNeighborState.Disconnected)) this.neighborManager.CloseNeighbor(neighbor, closeReason, PeerCloseInitiator.RemoteNode); else if (!(neighbor.State >= PeerNeighborState.Disconnected)) { DiagnosticUtility.DebugAssert("Unexpected neighbor state"); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } // Hand over the referrals to maintainer this.maintainer.AddReferrals(referrals, neighbor); } void OnConnectFailure (IPeerNeighbor neighbor, PeerCloseReason reason, Exception exception) { CleanupOnConnectFailure(neighbor, reason, exception); } void OnConnectTimeout (object asyncState) { CleanupOnConnectFailure( (IPeerNeighbor)asyncState, PeerCloseReason.ConnectTimedOut, null); } // Process neighbor closed notification. public void OnNeighborClosed(IPeerNeighbor neighbor) { // If the neighbor is closed abruptly by the remote node, OnNeighborClosing will // not be invoked. Remove neighbor's timer from the table. RemoveTimer (neighbor); } // Process neighbor closing notification. public void OnNeighborClosing (IPeerNeighbor neighbor, PeerCloseReason closeReason) { // Send Disconnect message to a Connected neighbor if (neighbor.IsConnected) SendTerminatingMessage(neighbor, PeerStrings.DisconnectAction, closeReason); } // Process neighbor authenticated notification public void OnNeighborAuthenticated(IPeerNeighbor neighbor) { if (!(this.state != State.Created)) { DiagnosticUtility.DebugAssert("Connector not expected to be in Created state"); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } if (!(PeerNeighborStateHelper.IsAuthenticatedOrClosed(neighbor.State))) { DiagnosticUtility.DebugAssert(string.Format(CultureInfo.InvariantCulture, "Neighbor state expected to be Authenticated or Closed, actual state: {0}", neighbor.State)); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } // setting the state fails if neighbor is already closed or closing // If so, we have nothing to do. if (!neighbor.TrySetState(PeerNeighborState.Connecting)) { if (!(neighbor.State >= PeerNeighborState.Faulted)) { DiagnosticUtility.DebugAssert(string.Format(CultureInfo.InvariantCulture, "Neighbor state expected to be Faulted or Closed, actual state: {0}", neighbor.State)); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } return; } // Add a timer to timer table to transition the neighbor to connected state // within finite duration. The neighbor is closed if the timer fires and the // neighbor has not reached connected state. // The timer is not added if neighbor or connector are closed if (AddTimer(neighbor)) { // Need to send connect message if the neighbor is the initiator if (neighbor.IsInitiator) { if (this.neighborManager.ConnectedNeighborCount < this.config.MaxNeighbors) SendConnect(neighbor); else { // We have max connected neighbors already. So close this one. this.neighborManager.CloseNeighbor(neighbor, PeerCloseReason.NodeBusy, PeerCloseInitiator.LocalNode); } } } } public void Open() { lock (ThisLock) { if (!(this.state == State.Created)) { DiagnosticUtility.DebugAssert("Connector expected to be in Created state"); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } this.state = State.Opened; } } // // Process Connect from the neighbor public void Connect(IPeerNeighbor neighbor, ConnectInfo connectInfo) { // Don't bother processing the message if Connector has closed if (this.state != State.Opened) return; PeerCloseReason closeReason = PeerCloseReason.None; // A connect message should only be received by a responder neighbor that is // in Connecting state. If not, we close the neighbor without bothering // to send a Refuse message // A malicious neighbor can format a message with a null connectInfo as an argument if (neighbor.IsInitiator || !connectInfo.HasBody() || (neighbor.State != PeerNeighborState.Connecting && neighbor.State != PeerNeighborState.Closed) ) { closeReason = PeerCloseReason.InvalidNeighbor; } // Remove the timer from the timer table for this neighbor. If the timer is not // present, the neighbor is already being closed and the Connect message should // be ignored. else if (RemoveTimer(neighbor)) { // Determine if Welcome or Refuse should be sent // Refuse if node has maximum allowed connected neighbors? if (this.neighborManager.ConnectedNeighborCount >= this.config.MaxNeighbors) closeReason = PeerCloseReason.NodeBusy; else { // Deserialization failed or connect info is invalid? if (!PeerValidateHelper.ValidNodeAddress(connectInfo.Address)) { closeReason = PeerCloseReason.InvalidNeighbor; } else { // Determine if neighbor should be accepted. PeerCloseReason closeReason2; IPeerNeighbor neighborToClose; string action = PeerStrings.RefuseAction; ValidateNeighbor(neighbor, connectInfo.NodeId, out neighborToClose, out closeReason2, out action); if (neighbor != neighborToClose) // new neighbor should be accepted { SendWelcome(neighbor); try { neighbor.ListenAddress = connectInfo.Address; } catch (ObjectDisposedException e) { DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information); } if (! neighbor.TrySetState(PeerNeighborState.Connected)) if (!(neighbor.State >= PeerNeighborState.Disconnecting)) { DiagnosticUtility.DebugAssert("Neighbor state expected to be >= Disconnecting; it is " + neighbor.State.ToString()); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } if (neighborToClose != null) { // The other neighbor should be closed SendTerminatingMessage(neighborToClose, action, closeReason2); this.neighborManager.CloseNeighbor(neighborToClose, closeReason2, PeerCloseInitiator.LocalNode); } } else closeReason = closeReason2; } } } if (closeReason != PeerCloseReason.None) { SendTerminatingMessage(neighbor, PeerStrings.RefuseAction, closeReason); this.neighborManager.CloseNeighbor (neighbor, closeReason, PeerCloseInitiator.LocalNode); } } // Process Disconnect message from the neighbor public void Disconnect(IPeerNeighbor neighbor, DisconnectInfo disconnectInfo) { // Don't bother processing the message if Connector has closed if (this.state != State.Opened) return; PeerCloseReason closeReason = PeerCloseReason.InvalidNeighbor; IList referrals = null; if (disconnectInfo.HasBody()) { // We should only receive Disconnect message after the neighbor has transitioned // to connected state. if (neighbor.State >= PeerNeighborState.Connected) { if (PeerConnectorHelper.IsDefined(disconnectInfo.Reason)) { closeReason = (PeerCloseReason)disconnectInfo.Reason; referrals = disconnectInfo.Referrals; } } } // Complete processing of disconnect message CompleteTerminateMessageProcessing (neighbor, closeReason, referrals); } // Process Refuse message from the neighbor public void Refuse(IPeerNeighbor neighbor, RefuseInfo refuseInfo) { // Don't bother processing the message if Connector has closed if (this.state != State.Opened) return; PeerCloseReason closeReason = PeerCloseReason.InvalidNeighbor; IList referrals = null; if (refuseInfo.HasBody()) { // Refuse message should only be received when neighbor is the initiator // and is in connecting state --we accept in closed state to account for // timeouts. if (neighbor.IsInitiator && (neighbor.State == PeerNeighborState.Connecting || neighbor.State == PeerNeighborState.Closed)) { // Remove the entry from timer table for this neighbor RemoveTimer(neighbor); if (PeerConnectorHelper.IsDefined(refuseInfo.Reason)) { closeReason = (PeerCloseReason)refuseInfo.Reason; referrals = refuseInfo.Referrals; } } } // Complete processing of refuse message CompleteTerminateMessageProcessing(neighbor, closeReason, referrals); } // Process Welcome message from the neighbor public void Welcome(IPeerNeighbor neighbor, WelcomeInfo welcomeInfo) { // Don't bother processing the message if Connector has closed if (this.state != State.Opened) return; PeerCloseReason closeReason = PeerCloseReason.None; // Welcome message should only be received when neighbor is the initiator // and is in connecting state --we accept in closed state to account for // timeouts. if (!neighbor.IsInitiator || !welcomeInfo.HasBody() || (neighbor.State != PeerNeighborState.Connecting && neighbor.State != PeerNeighborState.Closed)) { closeReason = PeerCloseReason.InvalidNeighbor; } // Remove the entry from timer table for this neighbor. If entry is still present, // RemoveTimer returns true. Otherwise, neighbor is already being closed and // welcome message will be ignored. else if (RemoveTimer(neighbor)) { // It is allowed for a node to have more than MaxNeighbours when processing a welcome message // Determine if neighbor should be accepted. PeerCloseReason closeReason2; IPeerNeighbor neighborToClose; string action = PeerStrings.RefuseAction; ValidateNeighbor(neighbor, welcomeInfo.NodeId, out neighborToClose, out closeReason2, out action); if (neighbor != neighborToClose) { // Neighbor should be accepted AddReferrals validates the referrals, // if they are valid then the neighbor is accepted. if (this.maintainer.AddReferrals(welcomeInfo.Referrals, neighbor)) { if (!neighbor.TrySetState(PeerNeighborState.Connected)) { if (!(neighbor.State >= PeerNeighborState.Faulted)) { DiagnosticUtility.DebugAssert("Neighbor state expected to be >= Faulted; it is " + neighbor.State.ToString()); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } } if (neighborToClose != null) { // The other neighbor should be closed SendTerminatingMessage(neighborToClose, action, closeReason2); this.neighborManager.CloseNeighbor(neighborToClose, closeReason2, PeerCloseInitiator.LocalNode); } } else { // Referrals were invalid this node is suspicous closeReason = PeerCloseReason.InvalidNeighbor; } } else { closeReason = closeReason2; } } if (closeReason != PeerCloseReason.None) { SendTerminatingMessage(neighbor, PeerStrings.DisconnectAction, closeReason); this.neighborManager.CloseNeighbor(neighbor, closeReason, PeerCloseInitiator.LocalNode); } } bool RemoveTimer (IPeerNeighbor neighbor) { IOThreadTimer timer = null; bool removed = false; // Remove the timer from the table and cancel it. Do this if Connector is // still open. Otherwise, Close method will have already cancelled the timers. lock (ThisLock) { if (this.state == State.Opened && this.timerTable.TryGetValue(neighbor, out timer)) { removed = this.timerTable.Remove(neighbor); } } if (timer != null) { timer.Cancel(); if (!(removed)) { DiagnosticUtility.DebugAssert("Neighbor key should have beeen removed from the table"); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } } return removed; } void SendConnect (IPeerNeighbor neighbor) { // We do not attempt to send the message if PeerConnector is not open if (neighbor.State == PeerNeighborState.Connecting && this.state == State.Opened) { // Retrieve the local address. The retrieved address may be null if the node // is shutdown. In that case, don't bother to send connect message since the // node is closing... PeerNodeAddress listenAddress = this.config.GetListenAddress(true); if (listenAddress != null) { ConnectInfo connectInfo = new ConnectInfo(this.config.NodeId, listenAddress); Message message = ConnectInfoMessageConverter.ToMessage(connectInfo, MessageVersion.Soap12WSAddressing10); SendMessageToNeighbor(neighbor, message, OnConnectFailure); } } } // Send Disconnect or Refuse message void SendTerminatingMessage(IPeerNeighbor neighbor, string action, PeerCloseReason closeReason) { // We do not attempt to send the message if Connector is not open // or if the close reason is InvalidNeighbor. if (this.state != State.Opened || closeReason == PeerCloseReason.InvalidNeighbor) return; // Set the neighbor state to disconnecting. TrySetState can fail if the // neighbor is already being closed. Disconnect/Refuse msg not sent in that case. if (neighbor.TrySetState(PeerNeighborState.Disconnecting)) { // Get referrals from the maintainer Referral[] referrals = maintainer.GetReferrals(); // Build and send the message Message message; if (action == PeerStrings.DisconnectAction) { DisconnectInfo disconnectInfo = new DisconnectInfo((DisconnectReason)closeReason, referrals); message = DisconnectInfoMessageConverter.ToMessage(disconnectInfo, MessageVersion.Soap12WSAddressing10); } else { RefuseInfo refuseInfo = new RefuseInfo((RefuseReason)closeReason, referrals); message = RefuseInfoMessageConverter.ToMessage(refuseInfo, MessageVersion.Soap12WSAddressing10); } SendMessageToNeighbor(neighbor, message, null); } else if (!(neighbor.State >= PeerNeighborState.Disconnecting)) { DiagnosticUtility.DebugAssert("Neighbor state expected to be >= Disconnecting; it is " + neighbor.State.ToString()); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } } void SendWelcome (IPeerNeighbor neighbor) { // We do not attempt to send the message if PeerConnector is not open if (state == State.Opened) { // Get referrals from the maintainer Referral[] referrals = maintainer.GetReferrals(); WelcomeInfo welcomeInfo = new WelcomeInfo(this.config.NodeId, referrals); Message message = WelcomeInfoMessageConverter.ToMessage(welcomeInfo, MessageVersion.Soap12WSAddressing10); SendMessageToNeighbor(neighbor, message, OnConnectFailure); } } // Validates the new neighbor based on its node ID. If it detects duplicate neighbor condition, // it will return reference to the neighbor that should be closed. void ValidateNeighbor(IPeerNeighbor neighbor, ulong neighborNodeId, out IPeerNeighbor neighborToClose, out PeerCloseReason closeReason, out string action) { neighborToClose = null; closeReason = PeerCloseReason.None; action = null; // Invalid neighbor node Id? if (neighborNodeId == PeerTransportConstants.InvalidNodeId) { neighborToClose = neighbor; closeReason = PeerCloseReason.InvalidNeighbor; } // Neighbor's node ID matches local node Id? else if (neighborNodeId == this.config.NodeId) { neighborToClose = neighbor; closeReason = PeerCloseReason.DuplicateNodeId; } else { // Check for duplicate neighbors (i.e., if another neighbor has the // same node Id as the new neighbor). // Set neighbor's node Id prior to calling FindDuplicateNeighbor. try { neighbor.NodeId = neighborNodeId; } catch (ObjectDisposedException e) { DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information); return; } IPeerNeighbor duplicateNeighbor = this.neighborManager.FindDuplicateNeighbor(neighborNodeId, neighbor); if(duplicateNeighbor != null && this.neighborManager.PingNeighbor(duplicateNeighbor)) { // We have a duplicate neighbor. Determine which one should be closed closeReason = PeerCloseReason.DuplicateNeighbor; // In the corner case where both neighbors are initiated by the same node, // close the new neighbor -- Maintainer is expected to check if there is // already a connection to a node prior to initiating a new connection. if (neighbor.IsInitiator == duplicateNeighbor.IsInitiator) neighborToClose = neighbor; // Otherwise, close the neighbor that was initiated by the node with the // larger node ID -- this ensures that both nodes tear down the same link. else if (this.config.NodeId > neighborNodeId) neighborToClose = (neighbor.IsInitiator ? neighbor : duplicateNeighbor); else neighborToClose = (neighbor.IsInitiator ? duplicateNeighbor : neighbor); } } if (neighborToClose != null) { // If we decided to close the other neighbor, go ahead and do it. if (neighborToClose != neighbor) { // Send Disconnect or Refuse message depending on its state if (neighborToClose.State == PeerNeighborState.Connected) { action = PeerStrings.DisconnectAction; } else if (!neighborToClose.IsInitiator && neighborToClose.State == PeerNeighborState.Connecting) { action = PeerStrings.RefuseAction; } } } } } } // 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
- OleDbEnumerator.cs
- Select.cs
- CompilerTypeWithParams.cs
- wmiprovider.cs
- HandledEventArgs.cs
- SafeHandles.cs
- EntityDataSourceEntityTypeFilterConverter.cs
- Rules.cs
- ArraySegment.cs
- XPathBinder.cs
- DataGridRelationshipRow.cs
- WindowsGraphics.cs
- IListConverters.cs
- OrderedEnumerableRowCollection.cs
- ConfigurationStrings.cs
- BaseParagraph.cs
- WebBrowserNavigatedEventHandler.cs
- XmlTextReader.cs
- CompilerGeneratedAttribute.cs
- MenuScrollingVisibilityConverter.cs
- DbProviderFactory.cs
- ViewStateAttachedPropertyFeature.cs
- ColumnHeader.cs
- DataPagerCommandEventArgs.cs
- ListDictionary.cs
- Soap12ProtocolReflector.cs
- IgnoreDeviceFilterElement.cs
- RelationshipEndMember.cs
- FilterableAttribute.cs
- UpdateEventArgs.cs
- Vector3DAnimationBase.cs
- DelayedRegex.cs
- SiteMapPath.cs
- XmlSchemaObject.cs
- ToolStripTextBox.cs
- LockRecoveryTask.cs
- AttachedAnnotation.cs
- PeerContact.cs
- BatchParser.cs
- ToolStripLocationCancelEventArgs.cs
- DeferredSelectedIndexReference.cs
- HandlerBase.cs
- storepermission.cs
- ListManagerBindingsCollection.cs
- IdentityValidationException.cs
- RangeValidator.cs
- GlobalItem.cs
- TabletCollection.cs
- EventProviderBase.cs
- SafeLocalAllocation.cs
- ByteStack.cs
- IndicFontClient.cs
- TimelineCollection.cs
- ChangePassword.cs
- GridViewPageEventArgs.cs
- ProcessHostMapPath.cs
- XmlHierarchicalDataSourceView.cs
- unsafeIndexingFilterStream.cs
- KnownBoxes.cs
- LookupNode.cs
- MSAANativeProvider.cs
- OledbConnectionStringbuilder.cs
- EntityProviderServices.cs
- DateTimeUtil.cs
- ThousandthOfEmRealPoints.cs
- UnsafeNativeMethods.cs
- XmlWrappingReader.cs
- ThumbAutomationPeer.cs
- safelinkcollection.cs
- MoveSizeWinEventHandler.cs
- CellParaClient.cs
- ForwardPositionQuery.cs
- PartitionResolver.cs
- ToolStripPanelRenderEventArgs.cs
- XmlValueConverter.cs
- PolyLineSegmentFigureLogic.cs
- CodeGenerator.cs
- RecognitionResult.cs
- Utils.cs
- grammarelement.cs
- HashCodeCombiner.cs
- XmlTypeAttribute.cs
- EntityDataReader.cs
- CompressionTracing.cs
- HuffModule.cs
- MgmtConfigurationRecord.cs
- TypeGeneratedEventArgs.cs
- Win32PrintDialog.cs
- MobileControlsSectionHandler.cs
- Math.cs
- RadioButton.cs
- DataServiceQueryOfT.cs
- ParentQuery.cs
- WriteableBitmap.cs
- SafeLibraryHandle.cs
- TypeDescriptorFilterService.cs
- SoapElementAttribute.cs
- WebPartPersonalization.cs
- HttpHeaderCollection.cs
- XmlSchemaAppInfo.cs