Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Services / Web / System / Web / Services / Protocols / SoapServerProtocol.cs / 1305376 / SoapServerProtocol.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- namespace System.Web.Services.Protocols { using System; using System.Diagnostics; using System.Collections; using System.IO; using System.Reflection; using System.Xml.Serialization; using System.Xml; using System.Xml.Schema; using System.Web.Services.Description; using System.Text; using System.Net; using System.Web.Services.Configuration; using System.Threading; using System.Security.Policy; using System.Security.Permissions; using System.Web.Services.Diagnostics; [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")] public sealed class SoapServerType : ServerType { Hashtable methods = new Hashtable(); Hashtable duplicateMethods = new Hashtable(); internal SoapReflectedExtension[] HighPriExtensions; internal SoapReflectedExtension[] LowPriExtensions; internal object[] HighPriExtensionInitializers; internal object[] LowPriExtensionInitializers; internal string serviceNamespace; internal bool serviceDefaultIsEncoded; internal bool routingOnSoapAction; internal WebServiceProtocols protocolsSupported; public string ServiceNamespace { get { return serviceNamespace; } } public bool ServiceDefaultIsEncoded { get { return serviceDefaultIsEncoded; } } public bool ServiceRoutingOnSoapAction { get { return routingOnSoapAction; } } public SoapServerType(Type type, WebServiceProtocols protocolsSupported) : base(type) { this.protocolsSupported = protocolsSupported; bool soap11 = (protocolsSupported & WebServiceProtocols.HttpSoap) != 0; bool soap12 = (protocolsSupported & WebServiceProtocols.HttpSoap12) != 0; LogicalMethodInfo[] methodInfos = WebMethodReflector.GetMethods(type); ArrayList mappings = new ArrayList(); WebServiceAttribute serviceAttribute = WebServiceReflector.GetAttribute(type); object soapServiceAttribute = SoapReflector.GetSoapServiceAttribute(type); routingOnSoapAction = SoapReflector.GetSoapServiceRoutingStyle(soapServiceAttribute) == SoapServiceRoutingStyle.SoapAction; serviceNamespace = serviceAttribute.Namespace; serviceDefaultIsEncoded = SoapReflector.ServiceDefaultIsEncoded(type); SoapReflectionImporter soapImporter = SoapReflector.CreateSoapImporter(serviceNamespace, serviceDefaultIsEncoded); XmlReflectionImporter xmlImporter = SoapReflector.CreateXmlImporter(serviceNamespace, serviceDefaultIsEncoded); SoapReflector.IncludeTypes(methodInfos, soapImporter); WebMethodReflector.IncludeTypes(methodInfos, xmlImporter); SoapReflectedMethod[] soapMethods = new SoapReflectedMethod[methodInfos.Length]; SoapExtensionTypeElementCollection extensionTypes = WebServicesSection.Current.SoapExtensionTypes; ArrayList highPri = new ArrayList(); ArrayList lowPri = new ArrayList(); for (int i = 0; i < extensionTypes.Count; i++) { SoapExtensionTypeElement element = extensionTypes[i]; if (element == null) continue; SoapReflectedExtension extension = new SoapReflectedExtension(element.Type, null, element.Priority); if (element.Group == PriorityGroup.High) highPri.Add(extension); else lowPri.Add(extension); } HighPriExtensions = (SoapReflectedExtension[]) highPri.ToArray(typeof(SoapReflectedExtension)); LowPriExtensions = (SoapReflectedExtension[]) lowPri.ToArray(typeof(SoapReflectedExtension)); Array.Sort(HighPriExtensions); Array.Sort(LowPriExtensions); HighPriExtensionInitializers = SoapReflectedExtension.GetInitializers(type, HighPriExtensions); LowPriExtensionInitializers = SoapReflectedExtension.GetInitializers(type, LowPriExtensions); for (int i = 0; i < methodInfos.Length; i++) { LogicalMethodInfo methodInfo = methodInfos[i]; SoapReflectedMethod soapMethod = SoapReflector.ReflectMethod(methodInfo, false, xmlImporter, soapImporter, serviceAttribute.Namespace); mappings.Add(soapMethod.requestMappings); if (soapMethod.responseMappings != null) mappings.Add(soapMethod.responseMappings); mappings.Add(soapMethod.inHeaderMappings); if (soapMethod.outHeaderMappings != null) mappings.Add(soapMethod.outHeaderMappings); soapMethods[i] = soapMethod; } XmlMapping[] xmlMappings = (XmlMapping[])mappings.ToArray(typeof(XmlMapping)); TraceMethod caller = Tracing.On ? new TraceMethod(this, ".ctor", type, protocolsSupported) : null; if (Tracing.On) Tracing.Enter(Tracing.TraceId(Res.TraceCreateSerializer), caller, new TraceMethod(typeof(XmlSerializer), "FromMappings", xmlMappings, this.Evidence)); XmlSerializer[] serializers = null; if (AppDomain.CurrentDomain.IsHomogenous) { serializers = XmlSerializer.FromMappings(xmlMappings); } else { #pragma warning disable 618 // If we're in a non-homogenous domain, legacy CAS mode is enabled, so passing through evidence will not fail serializers = XmlSerializer.FromMappings((xmlMappings), this.Evidence); #pragma warning restore 618 } if (Tracing.On) Tracing.Exit(Tracing.TraceId(Res.TraceCreateSerializer), caller); int count = 0; for (int i = 0; i < soapMethods.Length; i++) { SoapServerMethod serverMethod = new SoapServerMethod(); SoapReflectedMethod soapMethod = soapMethods[i]; serverMethod.parameterSerializer = serializers[count++]; if (soapMethod.responseMappings != null) serverMethod.returnSerializer = serializers[count++]; serverMethod.inHeaderSerializer = serializers[count++]; if (soapMethod.outHeaderMappings != null) serverMethod.outHeaderSerializer = serializers[count++]; serverMethod.methodInfo = soapMethod.methodInfo; serverMethod.action = soapMethod.action; serverMethod.extensions = soapMethod.extensions; serverMethod.extensionInitializers = SoapReflectedExtension.GetInitializers(serverMethod.methodInfo, soapMethod.extensions); serverMethod.oneWay = soapMethod.oneWay; serverMethod.rpc = soapMethod.rpc; serverMethod.use = soapMethod.use; serverMethod.paramStyle = soapMethod.paramStyle; serverMethod.wsiClaims = soapMethod.binding == null ? WsiProfiles.None : soapMethod.binding.ConformsTo; ArrayList inHeaders = new ArrayList(); ArrayList outHeaders = new ArrayList(); for (int j = 0; j < soapMethod.headers.Length; j++) { SoapHeaderMapping mapping = new SoapHeaderMapping(); SoapReflectedHeader soapHeader = soapMethod.headers[j]; mapping.memberInfo = soapHeader.memberInfo; mapping.repeats = soapHeader.repeats; mapping.custom = soapHeader.custom; mapping.direction = soapHeader.direction; mapping.headerType = soapHeader.headerType; if (mapping.direction == SoapHeaderDirection.In) inHeaders.Add(mapping); else if (mapping.direction == SoapHeaderDirection.Out) outHeaders.Add(mapping); else { inHeaders.Add(mapping); outHeaders.Add(mapping); } } serverMethod.inHeaderMappings = (SoapHeaderMapping[])inHeaders.ToArray(typeof(SoapHeaderMapping)); if (serverMethod.outHeaderSerializer != null) serverMethod.outHeaderMappings = (SoapHeaderMapping[])outHeaders.ToArray(typeof(SoapHeaderMapping)); // check feasibility of routing on request element for soap 1.1 if (soap11 && !routingOnSoapAction && soapMethod.requestElementName.IsEmpty) throw new SoapException(Res.GetString(Res.TheMethodDoesNotHaveARequestElementEither1, serverMethod.methodInfo.Name), new XmlQualifiedName(Soap.Code.Client, Soap.Namespace)); // we can lookup methods by action or request element if (methods[soapMethod.action] == null) methods[soapMethod.action] = serverMethod; else { // duplicate soap actions not allowed in soap 1.1 if we're routing on soap action if (soap11 && routingOnSoapAction) { SoapServerMethod duplicateMethod = (SoapServerMethod)methods[soapMethod.action]; throw new SoapException(Res.GetString(Res.TheMethodsAndUseTheSameSoapActionWhenTheService3, serverMethod.methodInfo.Name, duplicateMethod.methodInfo.Name, soapMethod.action), new XmlQualifiedName(Soap.Code.Client, Soap.Namespace)) ; } duplicateMethods[soapMethod.action] = serverMethod; } if (methods[soapMethod.requestElementName] == null) methods[soapMethod.requestElementName] = serverMethod; else { // duplicate request elements not allowed in soap 1.1 if we're routing on request element if (soap11 && !routingOnSoapAction) { SoapServerMethod duplicateMethod = (SoapServerMethod)methods[soapMethod.requestElementName]; throw new SoapException(Res.GetString(Res.TheMethodsAndUseTheSameRequestElementXmlns4, serverMethod.methodInfo.Name, duplicateMethod.methodInfo.Name, soapMethod.requestElementName.Name, soapMethod.requestElementName.Namespace), new XmlQualifiedName(Soap.Code.Client, Soap.Namespace)); } duplicateMethods[soapMethod.requestElementName] = serverMethod; } } } public SoapServerMethod GetMethod(object key) { return (SoapServerMethod)methods[key]; } public SoapServerMethod GetDuplicateMethod(object key) { return (SoapServerMethod)duplicateMethods[key]; } } [PermissionSet(SecurityAction.InheritanceDemand, Name = "FullTrust")] [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")] public class SoapServerProtocolFactory : ServerProtocolFactory { // POST requests without pathinfo (the "/Foo" in "foo.asmx/Foo") // are treated as soap. if the server supports both versions we route requests // with soapaction to 1.1 and other requests to 1.2 protected override ServerProtocol CreateIfRequestCompatible(HttpRequest request){ if (request.PathInfo.Length > 0) return null; if (request.HttpMethod != "POST") // MethodNotAllowed = 405, return new UnsupportedRequestProtocol(405); // at this point we know it's probably soap. we're still not sure of the version // but we leave that to the SoapServerProtocol to figure out return new SoapServerProtocol(); } } [PermissionSet(SecurityAction.InheritanceDemand, Name = "FullTrust")] [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")] public class SoapServerProtocol : ServerProtocol { SoapServerType serverType; SoapServerMethod serverMethod; SoapServerMessage message; bool isOneWay; Exception onewayInitException; SoapProtocolVersion version; WebServiceProtocols protocolsSupported; SoapServerProtocolHelper helper; // // Default constructor is provided since WebServicesConfiguration is inaccessible // protected internal SoapServerProtocol() { this.protocolsSupported = WebServicesSection.Current.EnabledProtocols; } ////// /// [PermissionSet(SecurityAction.LinkDemand | SecurityAction.InheritanceDemand, Name="FullTrust")] protected virtual XmlWriter GetWriterForMessage(SoapServerMessage message, int bufferSize) { if (bufferSize < 512) bufferSize = 512; return new XmlTextWriter(new StreamWriter(message.Stream, new UTF8Encoding(false), bufferSize)); /* XmlWriterSettings ws = new XmlWriterSettings(); ws.Encoding = new UTF8Encoding(false); ws.Indent = false; ws.NewLineHandling = NewLineHandling.None; return XmlWriter.Create(message.Stream, ws); */ } ////// Allows to intercept XmlWriter creation. /// ////// /// [PermissionSet(SecurityAction.LinkDemand | SecurityAction.InheritanceDemand, Name="FullTrust")] protected virtual XmlReader GetReaderForMessage(SoapServerMessage message, int bufferSize) { Encoding enc = RequestResponseUtils.GetEncoding2(message.ContentType); if (bufferSize < 512) bufferSize = 512; int readTimeout = WebServicesSection.Current.SoapEnvelopeProcessing.ReadTimeout; Int64 timeout = readTimeout < 0 ? 0L : (Int64)readTimeout*10000000; Int64 nowTicks = DateTime.UtcNow.Ticks; Int64 timeoutTicks = Int64.MaxValue - timeout <= nowTicks ? Int64.MaxValue : nowTicks + timeout; XmlTextReader reader; if (enc != null) { if (timeoutTicks == Int64.MaxValue) { reader = new XmlTextReader(new StreamReader(message.Stream, enc, true, bufferSize)); } else { reader = new SoapEnvelopeReader(new StreamReader(message.Stream, enc, true, bufferSize), timeoutTicks); } } else { if (timeoutTicks == Int64.MaxValue) { reader = new XmlTextReader(message.Stream); } else { reader = new SoapEnvelopeReader(message.Stream, timeoutTicks); } } reader.DtdProcessing = DtdProcessing.Prohibit; reader.Normalization = true; reader.XmlResolver = null; return reader; } internal override bool Initialize() { // try to guess the request version so we can handle any exceptions that might come up GuessVersion(); message = new SoapServerMessage(this); onewayInitException = null; serverType = (SoapServerType)GetFromCache(typeof(SoapServerProtocol), Type); if (serverType == null) { lock (InternalSyncObject) { serverType = (SoapServerType)GetFromCache(typeof(SoapServerProtocol), Type); if (serverType == null) { serverType = new SoapServerType(Type, protocolsSupported); AddToCache(typeof(SoapServerProtocol), Type, serverType); } } } // We delay throwing any exceptions out of the extension until we determine if the method is one-way or not. Exception extensionException = null; try { message.highPriConfigExtensions = SoapMessage.InitializeExtensions(serverType.HighPriExtensions, serverType.HighPriExtensionInitializers); // // Allow derived classes to modify the high priority extensions list. // message.highPriConfigExtensions = ModifyInitializedExtensions(PriorityGroup.High, message.highPriConfigExtensions); // For one-way methods we rely on Request.InputStream guaranteeing that the entire request body has arrived message.SetStream(Request.InputStream); #if DEBUG //Debug.Assert(message.Stream.CanSeek, "Web services SOAP handler assumes a seekable stream."); // use exception in the place of Debug.Assert to avoid throwing asserts from a server process such as aspnet_ewp.exe if (!message.Stream.CanSeek) throw new InvalidOperationException("Non-Seekable stream " + message.Stream.GetType().FullName + " Web services SOAP handler assumes a seekable stream."); #endif message.InitExtensionStreamChain(message.highPriConfigExtensions); message.SetStage(SoapMessageStage.BeforeDeserialize); message.ContentType = Request.ContentType; message.ContentEncoding = Request.Headers[ContentType.ContentEncoding]; message.RunExtensions(message.highPriConfigExtensions, false); extensionException = message.Exception; } catch (Exception e) { if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) { throw; } if (Tracing.On) Tracing.ExceptionCatch(TraceEventType.Warning, this, "Initialize", e); extensionException = e; } // set this here since we might throw before we init the other extensions message.allExtensions = message.highPriConfigExtensions; // maybe the extensions that just ran changed some of the request data so we can make a better version guess GuessVersion(); try { this.serverMethod = RouteRequest(message); // the RouteRequest impl should throw an exception if it can't route the request but just in case... if (this.serverMethod == null) throw new SoapException(Res.GetString(Res.UnableToHandleRequest0), new XmlQualifiedName(Soap.Code.Server, Soap.Namespace)); } catch (Exception e) { if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) { throw; } if (helper.RequestNamespace != null) SetHelper(SoapServerProtocolHelper.GetHelper(this, helper.RequestNamespace)); // version mismatches override other errors CheckHelperVersion(); throw; } this.isOneWay = serverMethod.oneWay; if (extensionException == null) { try { SoapReflectedExtension[] otherReflectedExtensions = (SoapReflectedExtension[]) CombineExtensionsHelper(serverMethod.extensions, serverType.LowPriExtensions, typeof(SoapReflectedExtension)); object[] otherInitializers = (object[]) CombineExtensionsHelper(serverMethod.extensionInitializers, serverType.LowPriExtensionInitializers, typeof(object)); message.otherExtensions = SoapMessage.InitializeExtensions(otherReflectedExtensions, otherInitializers); // // Allow derived classes to modify the other extensions list. // message.otherExtensions = ModifyInitializedExtensions(PriorityGroup.Low, message.otherExtensions); message.allExtensions = (SoapExtension[]) CombineExtensionsHelper(message.highPriConfigExtensions, message.otherExtensions, typeof(SoapExtension)); } catch (Exception e) { if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) { throw; } if (Tracing.On) Tracing.ExceptionCatch(TraceEventType.Warning, this, "Initialize", e); extensionException = e; } } if (extensionException != null) { if(isOneWay) onewayInitException = extensionException; else if (extensionException is SoapException) throw extensionException; else throw SoapException.Create(Version, Res.GetString(Res.WebConfigExtensionError), new XmlQualifiedName(Soap.Code.Server, Soap.Namespace), extensionException); } return true; } ////// Allows to intercept XmlReader creation. /// ////// Allows derived classes to reorder or to replace intialized soap extensions prior to /// the system calling ChainStream or executing them in any stage. /// protected virtual SoapExtension[] ModifyInitializedExtensions(PriorityGroup group, SoapExtension[] extensions) { return extensions; } ////// Determines which SoapMethod should be invoked for a particular /// message. /// protected virtual SoapServerMethod RouteRequest(SoapServerMessage message) { return helper.RouteRequest(); } private void GuessVersion() { // make a best guess as to the version. we'll get more info when we ---- the envelope if (IsSupported(WebServiceProtocols.AnyHttpSoap)) { // both versions supported, we need to pick one if (Request.Headers[Soap.Action] == null || ContentType.MatchesBase(Request.ContentType, ContentType.ApplicationSoap)) SetHelper(new Soap12ServerProtocolHelper(this)); else SetHelper(new Soap11ServerProtocolHelper(this)); } else if (IsSupported(WebServiceProtocols.HttpSoap)) { SetHelper(new Soap11ServerProtocolHelper(this)); } else if (IsSupported(WebServiceProtocols.HttpSoap12)) { SetHelper(new Soap12ServerProtocolHelper(this)); } } internal bool IsSupported(WebServiceProtocols protocol) { return ((protocolsSupported & protocol) == protocol); } internal override ServerType ServerType { get { return serverType; } } internal override LogicalMethodInfo MethodInfo { get { return serverMethod.methodInfo; } } internal SoapServerMethod ServerMethod { get { return serverMethod; } } internal SoapServerMessage Message { get { return message; } } internal override bool IsOneWay { get { return this.isOneWay; } } internal override Exception OnewayInitException { get { Debug.Assert(isOneWay || (onewayInitException == null), "initException is meant to be used for oneWay methods only."); return this.onewayInitException; } } internal SoapProtocolVersion Version { get { return version; } } /* internal bool IsInitialized { get { return serverMethod != null; } } */ internal override void CreateServerInstance() { base.CreateServerInstance(); message.SetStage(SoapMessageStage.AfterDeserialize); message.RunExtensions(message.allExtensions, true); SoapHeaderHandling.SetHeaderMembers(message.Headers, this.Target, serverMethod.inHeaderMappings, SoapHeaderDirection.In, false); } /* #if DEBUG private static void CopyStream(Stream source, Stream dest) { byte[] bytes = new byte[1024]; int numRead = 0; while ((numRead = source.Read(bytes, 0, 1024)) > 0) dest.Write(bytes, 0, numRead); } #endif */ private void SetHelper(SoapServerProtocolHelper helper) { this.helper = helper; this.version = helper.Version; Context.Items[WebService.SoapVersionContextSlot] = helper.Version; } private static Array CombineExtensionsHelper(Array array1, Array array2, Type elementType) { if (array1 == null) return array2; if (array2 == null) return array1; int length = array1.Length + array2.Length; if (length == 0) return null; Array result = null; if (elementType == typeof(SoapReflectedExtension)) result = new SoapReflectedExtension[length]; else if (elementType == typeof(SoapExtension)) result = new SoapExtension[length]; else if (elementType == typeof(object)) result = new object[length]; else throw new ArgumentException(Res.GetString(Res.ElementTypeMustBeObjectOrSoapExtensionOrSoapReflectedException),"elementType"); Array.Copy(array1, 0, result, 0, array1.Length); Array.Copy(array2, 0, result, array1.Length, array2.Length); return result; } private void CheckHelperVersion() { if (helper.RequestNamespace == null) return; // looks at the helper request namespace and version information to see if we need to return a // version mismatch fault (and if so, what version fault). there are two conditions to check: // unknown envelope ns and known but unsupported envelope ns. there are a few rules this code must follow: // * a 1.1 node responds with a 1.1 fault. // * a 1.2 node responds to a 1.1 request with a 1.1 fault but responds to an unknown request with a 1.2 fault. // * a both node can respond with either but we prefer 1.1. // GetHelper returns an arbitrary helper when the envelope ns is unknown, so we can check the helper's // expected envelope against the actual request ns to see if the request ns is unknown if (helper.RequestNamespace != helper.EnvelopeNs) { // unknown envelope ns -- version mismatch // respond with the version we support or 1.1 if we support both string requestNamespace = helper.RequestNamespace; if (IsSupported(WebServiceProtocols.HttpSoap)) SetHelper(new Soap11ServerProtocolHelper(this)); else SetHelper(new Soap12ServerProtocolHelper(this)); throw new SoapException(Res.GetString(Res.WebInvalidEnvelopeNamespace, requestNamespace, helper.EnvelopeNs), SoapException.VersionMismatchFaultCode); } else if (!IsSupported(helper.Protocol)) { // known envelope ns but we don't support this version -- version mismatch // always respond with 1.1 string requestNamespace = helper.RequestNamespace; string expectedNamespace = IsSupported(WebServiceProtocols.HttpSoap) ? Soap.Namespace : Soap12.Namespace; SetHelper(new Soap11ServerProtocolHelper(this)); throw new SoapException(Res.GetString(Res.WebInvalidEnvelopeNamespace, requestNamespace, expectedNamespace), SoapException.VersionMismatchFaultCode); } } internal override object[] ReadParameters() { message.InitExtensionStreamChain(message.otherExtensions); message.RunExtensions(message.otherExtensions, true); // do a sanity check on the content-type before we check the version since otherwise the error might be really nasty if (!ContentType.IsSoap(message.ContentType)) throw new SoapException(Res.GetString(Res.WebRequestContent, message.ContentType, helper.HttpContentType), new XmlQualifiedName(Soap.Code.Client, Soap.Namespace), new SoapFaultSubCode(Soap12FaultCodes.UnsupportedMediaTypeFaultCode)); // now that all the extensions have run, establish the real version of the request XmlReader reader = null; try { reader = GetXmlReader(); reader.MoveToContent(); SetHelper(SoapServerProtocolHelper.GetHelper(this, reader.NamespaceURI)); } catch (XmlException e) { throw new SoapException(Res.GetString(Res.WebRequestUnableToRead), new XmlQualifiedName(Soap.Code.Client, Soap.Namespace), e); } CheckHelperVersion(); // now do a more specific content-type check for soap 1.1 only (soap 1.2 allows various xml content types) if (version == SoapProtocolVersion.Soap11 && !ContentType.MatchesBase(message.ContentType, helper.HttpContentType)) throw new SoapException(Res.GetString(Res.WebRequestContent, message.ContentType, helper.HttpContentType), new XmlQualifiedName(Soap.Code.Client, Soap.Namespace), new SoapFaultSubCode(Soap12FaultCodes.UnsupportedMediaTypeFaultCode)); if (message.Exception != null) { throw message.Exception; } try { if (!reader.IsStartElement(Soap.Element.Envelope, helper.EnvelopeNs)) throw new InvalidOperationException(Res.GetString(Res.WebMissingEnvelopeElement)); if (reader.IsEmptyElement) throw new InvalidOperationException(Res.GetString(Res.WebMissingBodyElement)); int depth = reader.Depth; reader.ReadStartElement(Soap.Element.Envelope, helper.EnvelopeNs); reader.MoveToContent(); // run time check for R2738 A MESSAGE MUST include all soapbind:headers specified on a wsdl:input or wsdl:output of a wsdl:operationwsdl:binding that describes it. bool checkRequiredHeaders = (this.serverMethod.wsiClaims & WsiProfiles.BasicProfile1_1) != 0 && version != SoapProtocolVersion.Soap12; string missingHeader = new SoapHeaderHandling().ReadHeaders(reader, serverMethod.inHeaderSerializer, message.Headers, serverMethod.inHeaderMappings, SoapHeaderDirection.In, helper.EnvelopeNs, serverMethod.use == SoapBindingUse.Encoded ? helper.EncodingNs : null, checkRequiredHeaders); if (missingHeader != null) { throw new SoapHeaderException(Res.GetString(Res.WebMissingHeader, missingHeader), new XmlQualifiedName(Soap.Code.MustUnderstand, Soap.Namespace)); } if (!reader.IsStartElement(Soap.Element.Body, helper.EnvelopeNs)) throw new InvalidOperationException(Res.GetString(Res.WebMissingBodyElement)); reader.ReadStartElement(Soap.Element.Body, helper.EnvelopeNs); reader.MoveToContent(); object[] values; bool isEncodedSoap = serverMethod.use == SoapBindingUse.Encoded; TraceMethod caller = Tracing.On ? new TraceMethod(this, "ReadParameters") : null; if (Tracing.On) Tracing.Enter(Tracing.TraceId(Res.TraceReadRequest), caller, new TraceMethod(serverMethod.parameterSerializer, "Deserialize", reader, serverMethod.use == SoapBindingUse.Encoded ? helper.EncodingNs : null)); bool useDeserializationEvents = !isEncodedSoap && (WebServicesSection.Current.SoapEnvelopeProcessing.IsStrict || Tracing.On); if (useDeserializationEvents) { XmlDeserializationEvents events = Tracing.On ? Tracing.GetDeserializationEvents() : RuntimeUtils.GetDeserializationEvents(); values = (object[])serverMethod.parameterSerializer.Deserialize(reader, null, events); } else { values = (object[])serverMethod.parameterSerializer.Deserialize(reader, isEncodedSoap ? helper.EncodingNs : null); } if (Tracing.On) Tracing.Exit(Tracing.TraceId(Res.TraceReadRequest), caller); // Consume soap:Body and soap:Envelope closing tags while (depth < reader.Depth && reader.Read()) { // Nothing, just read on } // consume end tag if (reader.NodeType == XmlNodeType.EndElement) { reader.Read(); } message.SetParameterValues(values); return values; } catch (SoapException) { throw; } catch (Exception e) { if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) { throw; } throw new SoapException(Res.GetString(Res.WebRequestUnableToRead), new XmlQualifiedName(Soap.Code.Client, Soap.Namespace), e); } } internal override void WriteReturns(object[] returnValues, Stream outputStream) { if (serverMethod.oneWay) return; bool isEncoded = serverMethod.use == SoapBindingUse.Encoded; SoapHeaderHandling.EnsureHeadersUnderstood(message.Headers); message.Headers.Clear(); SoapHeaderHandling.GetHeaderMembers(message.Headers, this.Target, serverMethod.outHeaderMappings, SoapHeaderDirection.Out, false); if (message.allExtensions != null) message.SetExtensionStream(new SoapExtensionStream()); message.InitExtensionStreamChain(message.allExtensions); message.SetStage(SoapMessageStage.BeforeSerialize); message.ContentType = ContentType.Compose(helper.HttpContentType, Encoding.UTF8); message.SetParameterValues(returnValues); message.RunExtensions(message.allExtensions, true); message.SetStream(outputStream); Response.ContentType = message.ContentType; if (message.ContentEncoding != null && message.ContentEncoding.Length > 0) Response.AppendHeader(ContentType.ContentEncoding, message.ContentEncoding); XmlWriter writer = GetWriterForMessage(message, 1024); if (writer == null) throw new InvalidOperationException(Res.GetString(Res.WebNullWriterForMessage)); writer.WriteStartDocument(); writer.WriteStartElement("soap", Soap.Element.Envelope, helper.EnvelopeNs); writer.WriteAttributeString("xmlns", "soap", null, helper.EnvelopeNs); if (isEncoded) { writer.WriteAttributeString("xmlns", "soapenc", null, helper.EncodingNs); writer.WriteAttributeString("xmlns", "tns", null, serverType.serviceNamespace); writer.WriteAttributeString("xmlns", "types", null, SoapReflector.GetEncodedNamespace(serverType.serviceNamespace, serverType.serviceDefaultIsEncoded)); } if (serverMethod.rpc && version == SoapProtocolVersion.Soap12) { writer.WriteAttributeString("xmlns", "rpc", null, Soap12.RpcNamespace); } writer.WriteAttributeString("xmlns", "xsi", null, XmlSchema.InstanceNamespace); writer.WriteAttributeString("xmlns", "xsd", null, XmlSchema.Namespace); SoapHeaderHandling.WriteHeaders(writer, serverMethod.outHeaderSerializer, message.Headers, serverMethod.outHeaderMappings, SoapHeaderDirection.Out, isEncoded, serverType.serviceNamespace, serverType.serviceDefaultIsEncoded, helper.EnvelopeNs); writer.WriteStartElement(Soap.Element.Body, helper.EnvelopeNs); if (isEncoded && version != SoapProtocolVersion.Soap12) // don't write encodingStyle on soap:Body for soap 1.2 writer.WriteAttributeString("soap", Soap.Attribute.EncodingStyle, null, helper.EncodingNs); TraceMethod caller = Tracing.On ? new TraceMethod(this, "WriteReturns") : null; if (Tracing.On) Tracing.Enter(Tracing.TraceId(Res.TraceWriteResponse), caller, new TraceMethod(serverMethod.returnSerializer, "Serialize", writer, returnValues, null, isEncoded ? helper.EncodingNs : null)); serverMethod.returnSerializer.Serialize(writer, returnValues, null, isEncoded ? helper.EncodingNs : null); if (Tracing.On) Tracing.Exit(Tracing.TraceId(Res.TraceWriteResponse), caller); writer.WriteEndElement(); writer.WriteEndElement(); writer.Flush(); message.SetStage(SoapMessageStage.AfterSerialize); message.RunExtensions(message.allExtensions, true); } internal override bool WriteException(Exception e, Stream outputStream) { if (message == null) return false; message.Headers.Clear(); if (serverMethod != null && this.Target != null) SoapHeaderHandling.GetHeaderMembers(message.Headers, this.Target, serverMethod.outHeaderMappings, SoapHeaderDirection.Fault, false); SoapException soapException; if (e is SoapException) soapException = (SoapException)e; else if (serverMethod != null && serverMethod.rpc && helper.Version == SoapProtocolVersion.Soap12 && e is ArgumentException) // special case to handle soap 1.2 rpc "BadArguments" fault soapException = SoapException.Create(Version, Res.GetString(Res.WebRequestUnableToProcess), new XmlQualifiedName(Soap.Code.Client, Soap.Namespace), null, null, null, new SoapFaultSubCode(Soap12FaultCodes.RpcBadArgumentsFaultCode), e); else soapException = SoapException.Create(Version, Res.GetString(Res.WebRequestUnableToProcess), new XmlQualifiedName(Soap.Code.Server, Soap.Namespace), e); if (SoapException.IsVersionMismatchFaultCode(soapException.Code)) { if (IsSupported(WebServiceProtocols.HttpSoap12)) { SoapUnknownHeader unknownHeader = CreateUpgradeHeader(); if (unknownHeader != null) Message.Headers.Add(unknownHeader); } } Response.ClearHeaders(); Response.Clear(); HttpStatusCode statusCode = helper.SetResponseErrorCode(Response, soapException); bool disableExtensions = false; SoapExtensionStream extensionStream = new SoapExtensionStream(); if (message.allExtensions != null) message.SetExtensionStream(extensionStream); try { message.InitExtensionStreamChain(message.allExtensions); } catch (Exception ex) { if (ex is ThreadAbortException || ex is StackOverflowException || ex is OutOfMemoryException) { throw; } if (Tracing.On) Tracing.ExceptionCatch(TraceEventType.Warning, this, "WriteException", ex); disableExtensions = true; } message.SetStage(SoapMessageStage.BeforeSerialize); message.ContentType = ContentType.Compose(helper.HttpContentType, Encoding.UTF8); message.Exception = soapException; if (!disableExtensions) { try { message.RunExtensions(message.allExtensions, false); } catch (Exception ex) { if (ex is ThreadAbortException || ex is StackOverflowException || ex is OutOfMemoryException) { throw; } if (Tracing.On) Tracing.ExceptionCatch(TraceEventType.Warning, this, "WriteException", ex); disableExtensions = true; } } message.SetStream(outputStream); Response.ContentType = message.ContentType; if (message.ContentEncoding != null && message.ContentEncoding.Length > 0) { Response.AppendHeader(ContentType.ContentEncoding, message.ContentEncoding); } XmlWriter writer = GetWriterForMessage(message, 512); if (writer == null) throw new InvalidOperationException(Res.GetString(Res.WebNullWriterForMessage)); helper.WriteFault(writer, message.Exception, statusCode); if (!disableExtensions) { SoapException extensionException = null; try { message.SetStage(SoapMessageStage.AfterSerialize); message.RunExtensions(message.allExtensions, false); } catch (Exception ex) { if (ex is ThreadAbortException || ex is StackOverflowException || ex is OutOfMemoryException) { throw; } if (Tracing.On) Tracing.ExceptionCatch(TraceEventType.Warning, this, "WriteException", ex); if (!extensionStream.HasWritten) { // if we haven't already written to the stream, we may be able to send an error extensionException = SoapException.Create(Version, Res.GetString(Res.WebExtensionError), new XmlQualifiedName(Soap.Code.Server, Soap.Namespace), ex); } } if (extensionException != null) { Response.ContentType = ContentType.Compose(ContentType.TextPlain, Encoding.UTF8); StreamWriter sw = new StreamWriter(outputStream, new UTF8Encoding(false)); sw.WriteLine(GenerateFaultString(message.Exception)); sw.Flush(); } } return true; } bool WriteException_TryWriteFault(SoapServerMessage message, Stream outputStream, HttpStatusCode statusCode, bool disableExtensions) { return true; } internal SoapUnknownHeader CreateUpgradeHeader() { XmlDocument doc = new XmlDocument(); XmlElement upgradeElement = doc.CreateElement(Soap12.Prefix, Soap12.Element.Upgrade, Soap12.Namespace); if (IsSupported(WebServiceProtocols.HttpSoap)) upgradeElement.AppendChild(CreateUpgradeEnvelope(doc, Soap.Prefix, Soap.Namespace)); if (IsSupported(WebServiceProtocols.HttpSoap12)) upgradeElement.AppendChild(CreateUpgradeEnvelope(doc, Soap12.Prefix, Soap12.Namespace)); SoapUnknownHeader upgradeHeader = new SoapUnknownHeader(); upgradeHeader.Element = upgradeElement; return upgradeHeader; } private static XmlElement CreateUpgradeEnvelope(XmlDocument doc, string prefix, string envelopeNs) { XmlElement envelopeElement = doc.CreateElement(Soap12.Prefix, Soap12.Element.UpgradeEnvelope, Soap12.Namespace); XmlAttribute xmlnsAttr = doc.CreateAttribute("xmlns", prefix, "http://www.w3.org/2000/xmlns/"); xmlnsAttr.Value = envelopeNs; XmlAttribute qnameAttr = doc.CreateAttribute(Soap12.Attribute.UpgradeEnvelopeQname); qnameAttr.Value = prefix + ":" + Soap.Element.Envelope; envelopeElement.Attributes.Append(qnameAttr); envelopeElement.Attributes.Append(xmlnsAttr); return envelopeElement; } internal XmlReader GetXmlReader() { Encoding enc = RequestResponseUtils.GetEncoding2(Message.ContentType); // in the case of conformant service check that input encodig is utg8 or urf16 // bool checkEncoding = serverMethod != null && (serverMethod.wsiClaims & WsiProfiles.BasicProfile1_1) != 0 && Version != SoapProtocolVersion.Soap12; if (checkEncoding && enc != null) { // WS-I BP 1.1: R1012: A MESSAGE MUST be serialized as either UTF-8 or UTF-16. if (!(enc is UTF8Encoding) && !(enc is UnicodeEncoding)) { throw new InvalidOperationException(Res.GetString(Res.WebWsiContentTypeEncoding)); } } XmlReader reader = GetReaderForMessage(Message, RequestResponseUtils.GetBufferSize(Request.ContentLength)); if (reader == null) throw new InvalidOperationException(Res.GetString(Res.WebNullReaderForMessage)); return reader; } internal class SoapEnvelopeReader : XmlTextReader { Int64 readerTimedout; internal SoapEnvelopeReader(TextReader input, Int64 timeout) : base(input) { this.readerTimedout = timeout; } internal SoapEnvelopeReader(Stream input, Int64 timeout) : base(input) { this.readerTimedout = timeout; } public override bool Read() { CheckTimeout(); return base.Read(); } public override bool MoveToNextAttribute() { CheckTimeout(); return base.MoveToNextAttribute(); } public override XmlNodeType MoveToContent() { CheckTimeout(); return base.MoveToContent(); } private void CheckTimeout() { if (DateTime.UtcNow.Ticks > readerTimedout) { throw new InvalidOperationException(Res.GetString(Res.WebTimeout)); } } } } internal abstract class SoapServerProtocolHelper { SoapServerProtocol protocol; string requestNamespace; protected SoapServerProtocolHelper(SoapServerProtocol protocol) { this.protocol = protocol; } protected SoapServerProtocolHelper(SoapServerProtocol protocol, string requestNamespace) { this.protocol = protocol; this.requestNamespace = requestNamespace; } internal static SoapServerProtocolHelper GetHelper(SoapServerProtocol protocol, string envelopeNs) { SoapServerProtocolHelper helper; if (envelopeNs == Soap.Namespace) helper = new Soap11ServerProtocolHelper(protocol, envelopeNs); else if (envelopeNs == Soap12.Namespace) helper = new Soap12ServerProtocolHelper(protocol, envelopeNs); else // just return a soap 1.1 helper -- the fact that the requestNs doesn't match will signal a version mismatch helper = new Soap11ServerProtocolHelper(protocol, envelopeNs); return helper; } internal HttpStatusCode SetResponseErrorCode(HttpResponse response, SoapException soapException) { if (soapException.SubCode != null && soapException.SubCode.Code == Soap12FaultCodes.UnsupportedMediaTypeFaultCode) { response.StatusCode = (int) HttpStatusCode.UnsupportedMediaType; soapException.ClearSubCode(); } else if (SoapException.IsClientFaultCode(soapException.Code)) { System.Web.Services.Protocols.ServerProtocol.SetHttpResponseStatusCode(response, (int)HttpStatusCode.InternalServerError); for (Exception inner = soapException; inner != null; inner = inner.InnerException) { if (inner is XmlException) { response.StatusCode = (int) HttpStatusCode.BadRequest; } } } else { System.Web.Services.Protocols.ServerProtocol.SetHttpResponseStatusCode(response, (int)HttpStatusCode.InternalServerError); } response.StatusDescription = HttpWorkerRequest.GetStatusDescription(response.StatusCode); return (HttpStatusCode)response.StatusCode; } internal abstract void WriteFault(XmlWriter writer, SoapException soapException, HttpStatusCode statusCode); internal abstract SoapServerMethod RouteRequest(); internal abstract SoapProtocolVersion Version { get; } internal abstract WebServiceProtocols Protocol { get; } internal abstract string EnvelopeNs { get; } internal abstract string EncodingNs { get; } internal abstract string HttpContentType { get; } internal string RequestNamespace { get { return requestNamespace; } } protected SoapServerProtocol ServerProtocol { get { return protocol; } } protected SoapServerType ServerType { get { return (SoapServerType)protocol.ServerType; } } // tries to get to the first child element of body, ignoring details // such as the namespace of Envelope and Body (a version mismatch check will come later) protected XmlQualifiedName GetRequestElement() { SoapServerMessage message = ServerProtocol.Message; long savedPosition = message.Stream.Position; XmlReader reader = protocol.GetXmlReader(); reader.MoveToContent(); requestNamespace = reader.NamespaceURI; if (!reader.IsStartElement(Soap.Element.Envelope, requestNamespace)) throw new InvalidOperationException(Res.GetString(Res.WebMissingEnvelopeElement)); if (reader.IsEmptyElement) throw new InvalidOperationException(Res.GetString(Res.WebMissingBodyElement)); reader.ReadStartElement(Soap.Element.Envelope, requestNamespace); reader.MoveToContent(); while (!reader.EOF && !reader.IsStartElement(Soap.Element.Body, requestNamespace)) reader.Skip(); if (reader.EOF) { throw new InvalidOperationException(Res.GetString(Res.WebMissingBodyElement)); } XmlQualifiedName element; if (reader.IsEmptyElement) { element = XmlQualifiedName.Empty; } else { reader.ReadStartElement(Soap.Element.Body, requestNamespace); reader.MoveToContent(); element = new XmlQualifiedName(reader.LocalName, reader.NamespaceURI); } message.Stream.Position = savedPosition; return element; } } } // 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
- MethodBuilderInstantiation.cs
- OracleConnectionFactory.cs
- EncryptedReference.cs
- TransactionManager.cs
- CollectionViewGroup.cs
- GPStream.cs
- WinEventTracker.cs
- TableRow.cs
- rsa.cs
- HtmlAnchor.cs
- TableColumn.cs
- ToolStripSeparatorRenderEventArgs.cs
- SpinLock.cs
- AudioFormatConverter.cs
- XmlWrappingReader.cs
- DataGridTable.cs
- CrossAppDomainChannel.cs
- ProtectedConfigurationSection.cs
- TableLayoutRowStyleCollection.cs
- TextRangeEditLists.cs
- NativeActivityTransactionContext.cs
- CodeCompiler.cs
- TreeBuilderBamlTranslator.cs
- MailWebEventProvider.cs
- ColumnBinding.cs
- ToolStripPanelCell.cs
- MSHTMLHost.cs
- ResourceAssociationSet.cs
- ResourcesChangeInfo.cs
- CodeExporter.cs
- CellTreeNode.cs
- FileDialog.cs
- OracleInternalConnection.cs
- BamlMapTable.cs
- XmlEncoding.cs
- ActivationServices.cs
- DataBindingList.cs
- DrawingDrawingContext.cs
- DbDataSourceEnumerator.cs
- FacetEnabledSchemaElement.cs
- StorageFunctionMapping.cs
- DynamicResourceExtension.cs
- PasswordTextNavigator.cs
- DynamicQueryableWrapper.cs
- XmlParser.cs
- DatatypeImplementation.cs
- SelectionRange.cs
- MarginsConverter.cs
- TableItemPattern.cs
- ChineseLunisolarCalendar.cs
- EditorZone.cs
- NetStream.cs
- PerfService.cs
- UrlAuthFailureHandler.cs
- UmAlQuraCalendar.cs
- InputProcessorProfilesLoader.cs
- BoolExpressionVisitors.cs
- WebHttpBinding.cs
- addressfiltermode.cs
- ListViewDeleteEventArgs.cs
- TextServicesManager.cs
- ToggleButtonAutomationPeer.cs
- ErrorHandler.cs
- LinqDataSourceHelper.cs
- WebBrowserUriTypeConverter.cs
- TypedElement.cs
- IntSecurity.cs
- ApplicationException.cs
- SafeNativeMethods.cs
- SqlNodeAnnotation.cs
- PeerTransportListenAddressValidator.cs
- ValidationErrorEventArgs.cs
- MediaElementAutomationPeer.cs
- Vector3DAnimationUsingKeyFrames.cs
- IdentitySection.cs
- XmlLanguage.cs
- RSAProtectedConfigurationProvider.cs
- StylusSystemGestureEventArgs.cs
- HttpCachePolicyElement.cs
- TextEndOfSegment.cs
- EngineSite.cs
- TransactionChannel.cs
- ProcessInputEventArgs.cs
- ComboBoxRenderer.cs
- XamlPathDataSerializer.cs
- WebPartEventArgs.cs
- WebPartVerbsEventArgs.cs
- XPathNavigatorReader.cs
- AttributeQuery.cs
- SortQueryOperator.cs
- NameValueSectionHandler.cs
- CommandBinding.cs
- LocalizedNameDescriptionPair.cs
- ChannelServices.cs
- OperationResponse.cs
- WeakHashtable.cs
- TextDecorations.cs
- ToolStrip.cs
- RequestQueue.cs
- OwnerDrawPropertyBag.cs