Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / NetFx40 / System.ServiceModel.Routing / System / ServiceModel / Routing / SoapProcessingBehavior.cs / 1305376 / SoapProcessingBehavior.cs
//---------------------------------------------------------------- // Copyright (c) Microsoft Corporation. All rights reserved. //--------------------------------------------------------------- //Turn on to log info about the before and after headers/messages //#define DEBUG_MARSHALING namespace System.ServiceModel.Routing { using System; using System.Collections.Generic; using System.Globalization; using System.ServiceModel; using System.ServiceModel.Channels; using System.ServiceModel.Dispatcher; using System.Runtime; using System.ServiceModel.Description; using System.ServiceModel.Configuration; using System.ServiceModel.Security; using System.Xml; using SR2 = System.ServiceModel.Routing.SR; public class SoapProcessingBehavior : IEndpointBehavior { const string IncomingViaName = "IncomingVia"; const string IncomingHttpRequestName = "IncomingHttpRequest"; public SoapProcessingBehavior() { this.ProcessMessages = true; } public bool ProcessMessages { get; set; } public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { } public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { if (endpoint == null) { throw FxTrace.Exception.ArgumentNull("endpoint"); } if (this.ProcessMessages) { SoapProcessingInspector inspector = new SoapProcessingInspector(endpoint, clientRuntime); clientRuntime.MessageInspectors.Add(inspector); clientRuntime.CallbackDispatchRuntime.MessageInspectors.Add(inspector); foreach (ClientOperation clientOp in clientRuntime.Operations) { clientOp.ParameterInspectors.Add(inspector); } } } public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { throw FxTrace.Exception.AsError(new NotSupportedException(SR2.MarshalingBehaviorNotSupported)); } public void Validate(ServiceEndpoint endpoint) { } class SoapProcessingInspector : IClientMessageInspector, IDispatchMessageInspector, IParameterInspector { static HashSetaddressingHeadersToFlow = InitializeHeadersToFlow(); bool manualAddressing; MessageVersion sourceMessageVersion; MessageVersion sendMessageVersion; public SoapProcessingInspector(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { Fx.Assert(endpoint != null, "endpoint cannot be null"); this.sendMessageVersion = endpoint.Binding.MessageVersion; this.manualAddressing = clientRuntime.ManualAddressing; } void IParameterInspector.AfterCall(string operationName, object[] outputs, object returnValue, object correlationState) { // This call occurs AFTER IClientMessageInspector.AfterReceiveReply. // We don't need to do any additional marshaling here. } object IParameterInspector.BeforeCall(string operationName, object[] inputs) { if (inputs == null || inputs.Length == 0) { throw FxTrace.Exception.ArgumentNullOrEmpty("inputs"); } //We have to remove some addressing headers to avoid errors before the //Soap Processing MessageInspector gets called. See CSDMain 117167. Message request = (Message)inputs[0]; this.PreProcess(request); return null; } void IClientMessageInspector.AfterReceiveReply(ref Message reply, object correlationState) { if (reply != null) { Message originalMessage = (Message)correlationState; MessageHeaders originalHeaders = originalMessage.Headers; Uri to = originalHeaders.To; MessageVersion version = originalMessage.Version; reply = MarshalMessage(reply, to, version); //BasicHttpContext looks at the original request message when //constructing the Set-Cookie header, need to put these back. Uri incomingVia; MessageProperties originalProperties = originalMessage.Properties; if (originalProperties.TryGetValue (IncomingViaName, out incomingVia)) { originalProperties.Via = incomingVia; } object incomingHttpRequest; if (originalProperties.TryGetValue(IncomingHttpRequestName, out incomingHttpRequest)) { originalProperties[HttpRequestMessageProperty.Name] = incomingHttpRequest; } //Reponses from BasicHttp (Addressing.None) don't have any action. If we're marshaling //to any addressing version other than none, we create a ReplyAction here MessageHeaders replyHeaders = reply.Headers; if (replyHeaders.Action == null && version.Addressing != AddressingVersion.None && originalHeaders.Action != null) { replyHeaders.Action = originalHeaders.Action + "Response"; } } } object IClientMessageInspector.BeforeSendRequest(ref Message request, IClientChannel channel) { Message originalRequest = request; if (this.sourceMessageVersion == null) { this.sourceMessageVersion = originalRequest.Version; } request = MarshalMessage(request, request.Headers.To, sendMessageVersion); return originalRequest; } object IDispatchMessageInspector.AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext) { request = MarshalMessage(request, request.Headers.To, this.sourceMessageVersion); return null; } void IDispatchMessageInspector.BeforeSendReply(ref Message reply, object correlationState) { if (reply != null) { reply = MarshalMessage(reply, reply.Headers.To, sendMessageVersion); } } static HashSet InitializeHeadersToFlow() { HashSet headersToFlow = new HashSet (StringComparer.Ordinal); headersToFlow.Add("Action"); headersToFlow.Add("MessageID"); headersToFlow.Add("RelatesTo"); headersToFlow.Add("To"); return headersToFlow; } void PreProcess(Message message) { //If the user does not have manual addressing enabled then clear these out if (!this.manualAddressing) { MessageHeaders headers = message.Headers; string addressingNamespace = RoutingUtilities.GetAddressingNamespace(headers.MessageVersion.Addressing); //Go through in reverse to reduce shifting after RemoveAt(i) for (int i = headers.Count - 1; i >= 0; --i) { MessageHeaderInfo header = headers[i]; if (string.Equals(header.Namespace, addressingNamespace, StringComparison.Ordinal)) { if (!addressingHeadersToFlow.Contains(header.Name)) { headers.RemoveAt(i); } } } } } internal Message MarshalMessage(Message source, Uri to, MessageVersion targetVersion) { Message result; MessageHeaders sourceHeaders = source.Headers; MessageVersion sourceVersion = source.Version; UnderstoodHeaders understoodHeaders = sourceHeaders.UnderstoodHeaders; HashSet understoodHeadersSet = CreateKeys(understoodHeaders); #if DEBUG_MARSHALING System.Text.StringBuilder details = new System.Text.StringBuilder(); details.AppendFormat("Original Message:\r\n{0}\r\n", source); details.AppendLine("Understood Headers:"); foreach (MessageHeaderInfo understoodHeader in understoodHeaders) { details.AppendFormat("\t{0}\t({1})\r\n", understoodHeader.Name, understoodHeader.Namespace); } details.AppendLine("Properties:"); foreach (KeyValuePair item in source.Properties) { details.AppendFormat("\t{0}\t({1})\r\n", item.Key, item.Value); } #endif //DEBUG_MARSHALING //if we've understood and verified the security of the message, we need to create a new message if (sourceVersion == targetVersion && !RoutingUtilities.IsMessageUsingWSSecurity(understoodHeaders)) { FilterHeaders(sourceHeaders, understoodHeadersSet); FilterProperties(source.Properties); result = source; } else { if (source.IsFault) { MessageFault messageFault = MessageFault.CreateFault(source, int.MaxValue); string action = sourceHeaders.Action; if (string.Equals(action, sourceVersion.Addressing.DefaultFaultAction, StringComparison.Ordinal)) { //The action was the default for the sourceVersion set it to the default for the targetVersion. action = targetVersion.Addressing.DefaultFaultAction; } result = Message.CreateMessage(targetVersion, messageFault, action); } else if (source.IsEmpty) { result = Message.CreateMessage(targetVersion, sourceHeaders.Action); } else { XmlDictionaryReader bodyReader = source.GetReaderAtBodyContents(); result = Message.CreateMessage(targetVersion, sourceHeaders.Action, bodyReader); } CloneHeaders(result.Headers, sourceHeaders, to, understoodHeadersSet); CloneProperties(result.Properties, source.Properties); } #if DEBUG_MARSHALING details.AppendFormat("\r\nMarshaled Message:\r\n{0}\r\n", result); details.AppendLine("Properties:"); foreach (KeyValuePair item in result.Properties) { details.AppendFormat("\t{0}\t({1})\r\n", item.Key, item.Value); } System.Diagnostics.Trace.WriteLine(details); TD.RoutingServiceDisplayConfig(details.ToString(), ""); #endif //DEBUG_MARSHALING return result; } static HashSet CreateKeys(UnderstoodHeaders headers) { HashSet toReturn = new HashSet (); foreach (MessageHeaderInfo header in headers) { toReturn.Add(MessageHeaderKey(header)); } return toReturn; } static string MessageHeaderKey(MessageHeaderInfo header) { return header.Name + "+" + header.Namespace; } void FilterHeaders(MessageHeaders headers, HashSet understoodHeadersSet) { string addressingNamespace = RoutingUtilities.GetAddressingNamespace(headers.MessageVersion.Addressing); //Go in reverse to reduce shifting after RemoveAt(i) for (int i = headers.Count - 1; i >= 0; --i) { MessageHeaderInfo header = headers[i]; bool removeHeader = false; if (string.Equals(header.Namespace, addressingNamespace, StringComparison.Ordinal) && (addressingHeadersToFlow.Contains(header.Name) || this.manualAddressing)) { continue; } if (understoodHeadersSet.Contains(MessageHeaderKey(header))) { // This header was understood at this endpoint, do _not_ flow it removeHeader = true; } else if (ActorIsNextDestination(header, headers.MessageVersion)) { //This was a header targeted at the SOAP Intermediary ("actor/next", which is us) //It can explicitly tell us to relay this header when we don't understand it. if (!header.Relay) { removeHeader = true; } } if (removeHeader) { headers.RemoveAt(i); } } } static bool ActorIsNextDestination(MessageHeaderInfo header, MessageVersion messageVersion) { return (header.Actor != null && string.Equals(header.Actor, messageVersion.Envelope.NextDestinationActorValue)); } void CloneHeaders(MessageHeaders targetHeaders, MessageHeaders sourceHeaders, Uri to, HashSet understoodHeadersSet) { for (int i = 0; i < sourceHeaders.Count; ++i) { MessageHeaderInfo header = sourceHeaders[i]; if (!understoodHeadersSet.Contains(MessageHeaderKey(header))) { //If Actor is SOAP Intermediary ("*actor/next" which is us) check the Relay flag if (!ActorIsNextDestination(header, sourceHeaders.MessageVersion) || header.Relay) { //Always wrap the header because BufferedHeader isn't smart enough to allow custom //headers to switch message versions MessageHeader messageHeader = new DelegatingHeader(header, sourceHeaders); targetHeaders.Add(messageHeader); } } } // To and Action (already specified) are 'special' and may be set even with AddressingVersion.None targetHeaders.To = to; if (targetHeaders.MessageVersion.Addressing != AddressingVersion.None) { //These are used as correlation IDs. Copy these regardless of manual addressing. targetHeaders.MessageId = sourceHeaders.MessageId; targetHeaders.RelatesTo = sourceHeaders.RelatesTo; if (this.manualAddressing) { //These are addresses, only copy when ManualAddressing is enabled targetHeaders.FaultTo = sourceHeaders.FaultTo; targetHeaders.ReplyTo = sourceHeaders.ReplyTo; targetHeaders.From = sourceHeaders.From; } } } static void CloneProperties(MessageProperties destination, MessageProperties source) { MessageEncoder encoder = destination.Encoder; destination.CopyProperties(source); destination.Encoder = encoder; FilterProperties(destination); } static void FilterProperties(MessageProperties destination) { // We have the clear out the HTTP Req/Resp props, so we don't accidentally // tell the outbound binding to use whatever Content-Type/Method/QueryString // that the inboudnd message/response used. Otherwise BasicHttp<->WsHttp won't work. object incomingHttpRequest; if (destination.TryGetValue(HttpRequestMessageProperty.Name, out incomingHttpRequest)) { //Store the inbound value for later retoration destination[IncomingHttpRequestName] = incomingHttpRequest; destination.Remove(HttpRequestMessageProperty.Name); } destination.Remove(HttpResponseMessageProperty.Name); //Preserve the Via on the outbound message, HTTP Context using cookies looks at this value //on the original request when sending the response "Set-Cookie" header. Uri incomingVia = destination.Via; if (incomingVia != null) { destination[IncomingViaName] = incomingVia; } } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- WSSecurityTokenSerializer.cs
- NativeCppClassAttribute.cs
- OperationInfo.cs
- ApplicationHost.cs
- SqlAggregateChecker.cs
- HeaderedContentControl.cs
- PrePrepareMethodAttribute.cs
- RightsController.cs
- TransformPatternIdentifiers.cs
- CreateUserWizard.cs
- WebHttpSecurityModeHelper.cs
- EndEvent.cs
- InkCanvasFeedbackAdorner.cs
- TargetInvocationException.cs
- ParallelTimeline.cs
- SmiContextFactory.cs
- EdmEntityTypeAttribute.cs
- HiddenField.cs
- DocumentPageHost.cs
- KeyTime.cs
- CommonDialog.cs
- MessageHeader.cs
- XmlProcessingInstruction.cs
- ExternalCalls.cs
- SqlDataSourceCustomCommandEditor.cs
- TcpSocketManager.cs
- UnicastIPAddressInformationCollection.cs
- SqlInfoMessageEvent.cs
- BitStack.cs
- ContainerUIElement3D.cs
- SecurityElement.cs
- OrderedDictionary.cs
- OpCodes.cs
- AttachedPropertyMethodSelector.cs
- StringValidator.cs
- ActionMessageFilterTable.cs
- ItemsPresenter.cs
- CompilerInfo.cs
- BamlLocalizerErrorNotifyEventArgs.cs
- CheckBox.cs
- ContravarianceAdapter.cs
- SelectionRangeConverter.cs
- ExpressionValueEditor.cs
- ThemeDirectoryCompiler.cs
- DataGridColumnCollection.cs
- HScrollBar.cs
- TrustLevelCollection.cs
- ImplicitInputBrush.cs
- ObjectList.cs
- XmlSerializableWriter.cs
- ParameterRetriever.cs
- EndOfStreamException.cs
- StyleConverter.cs
- Paragraph.cs
- ParallelLoopState.cs
- UniqueTransportManagerRegistration.cs
- CodeTypeDeclarationCollection.cs
- AutomationFocusChangedEventArgs.cs
- CallSiteOps.cs
- CodeThrowExceptionStatement.cs
- DataRowChangeEvent.cs
- XmlSerializerAssemblyAttribute.cs
- ContentElement.cs
- BinaryObjectWriter.cs
- FileDialogCustomPlace.cs
- NativeWindow.cs
- CorrelationTokenTypeConvertor.cs
- WebPartConnectionsEventArgs.cs
- UniqueSet.cs
- ISessionStateStore.cs
- ExtendLockCommand.cs
- BadImageFormatException.cs
- DecimalConverter.cs
- WorkerProcess.cs
- SchemaMapping.cs
- NonParentingControl.cs
- XmlWriterSettings.cs
- PrivateFontCollection.cs
- DateTimePicker.cs
- CalendarDateRange.cs
- LambdaCompiler.Logical.cs
- QilIterator.cs
- BitmapPalette.cs
- BamlWriter.cs
- ControlAdapter.cs
- FileIOPermission.cs
- _SslStream.cs
- TransformerInfoCollection.cs
- MetadataCache.cs
- ResourceSet.cs
- NameObjectCollectionBase.cs
- XmlEnumAttribute.cs
- RepeaterCommandEventArgs.cs
- CleanUpVirtualizedItemEventArgs.cs
- SafeEventLogWriteHandle.cs
- SqlDependency.cs
- LicenseContext.cs
- ProfileService.cs
- OutputCacheSettingsSection.cs
- DigitalSignature.cs