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
- IUnknownConstantAttribute.cs
- InstanceData.cs
- DXD.cs
- Predicate.cs
- DBPropSet.cs
- IPipelineRuntime.cs
- UserControlDocumentDesigner.cs
- ContainerTracking.cs
- ApplicationSecurityInfo.cs
- PtsHost.cs
- XsdCachingReader.cs
- Operator.cs
- EdmTypeAttribute.cs
- ColumnResizeAdorner.cs
- DataGridViewColumnCollection.cs
- Config.cs
- ThicknessAnimation.cs
- DataGridViewLinkColumn.cs
- ImageInfo.cs
- FolderNameEditor.cs
- ResourceWriter.cs
- AuthStoreRoleProvider.cs
- precedingsibling.cs
- Canvas.cs
- StylusButtonCollection.cs
- SqlPersonalizationProvider.cs
- VariableAction.cs
- ToolStripProgressBar.cs
- DefaultDiscoveryService.cs
- PropertyMapper.cs
- SerialStream.cs
- ExecutorLocksHeldException.cs
- OrthographicCamera.cs
- CryptoSession.cs
- EntityContainerEmitter.cs
- ReadOnlyNameValueCollection.cs
- ZipIOCentralDirectoryDigitalSignature.cs
- EditorPartChrome.cs
- DataGridViewCheckBoxColumn.cs
- BStrWrapper.cs
- ArrangedElement.cs
- BaseTemplateBuildProvider.cs
- COM2ComponentEditor.cs
- Models.cs
- XmlSchemaObjectTable.cs
- DrawingGroupDrawingContext.cs
- AttributeEmitter.cs
- ModifierKeysValueSerializer.cs
- NativeMethods.cs
- DateTimeEditor.cs
- ImmComposition.cs
- HttpProfileGroupBase.cs
- ReservationCollection.cs
- SimpleFileLog.cs
- _SslSessionsCache.cs
- LineSegment.cs
- ProviderCollection.cs
- WeakHashtable.cs
- DetailsViewRow.cs
- TemplateBindingExpressionConverter.cs
- Environment.cs
- DetailsView.cs
- PanelStyle.cs
- DateTimeOffsetConverter.cs
- Rules.cs
- ProgressBar.cs
- CodeCommentStatementCollection.cs
- EntityDataReader.cs
- DescendantOverDescendantQuery.cs
- VisualBasicSettingsConverter.cs
- ClientProtocol.cs
- ClockGroup.cs
- XmlDataFileEditor.cs
- DataTemplate.cs
- UnsafeNativeMethods.cs
- XmlBindingWorker.cs
- WriteLine.cs
- ListControl.cs
- DesignerEditorPartChrome.cs
- PropertyEntry.cs
- SerializationStore.cs
- DetailsViewDeletedEventArgs.cs
- Window.cs
- OpenFileDialog.cs
- SpeakCompletedEventArgs.cs
- XmlStreamStore.cs
- ObjectToIdCache.cs
- LocalizabilityAttribute.cs
- SamlAudienceRestrictionCondition.cs
- ToolStripItemEventArgs.cs
- DataControlFieldCollection.cs
- XappLauncher.cs
- DataTableNewRowEvent.cs
- SetterTriggerConditionValueConverter.cs
- AmbientProperties.cs
- ContentElement.cs
- WebContext.cs
- Subtree.cs
- ScriptControlManager.cs
- Attributes.cs