![]() |
Client found response content type of '', but expected 'text/xml'
On day 3 of debugging this. I've implemented a simple soap extension
to intercept the servers outgoing soap message stream and replace it with my own (code below). Everything seems to work in the code step through except the server side afterserialize stage is called twice (2 times!) but why? It should only fire once afaik. In the second fire, afterserialize writes an empty stream to the output stream, but I already wrote to the output stream correctly on the first fire! My client says, expectedly, the above error, the service returns nothing==empty stream. I've found many hits on the net, but no answers. Day 4 is coming. Argggh! The only post I found with an answer was this one: http://www.thescripts.com/forum/thread375954.html but I don't think it applies in my case as I rewound the stream correctly (or at least I think I did). I'm using vs 2005 and I'm running on XP pro. I'm using the embedded webserver in 2005 (cassini?) As I said, everything appears to work fine. On the server side It takes the input message, transforms it, and then writes it to the output stream. I checked the stream it copies to the output (in afterserialize on the first time it fires) and everything looks hunky-dory. However, the second time afterserialize fires everything is messed up and the streams are empty (appoutputstream and httpoutputstream). all code below here --********************* Here is the soap extension --********************** using System; using System.Web; using System.Web.Services; using System.IO; using System.Web.Services.Protocols; using System.Xml; public class XmlStreamSoapExtension : System.Web.Services.Protocols.SoapExtension { bool output = false; Stream httpOutputStream; Stream chainedOutputStream; Stream appOutputStream; public override Stream ChainStream(Stream stream) { Stream result = stream; if ((output)) { httpOutputStream = stream; chainedOutputStream = new MemoryStream(); result = chainedOutputStream; } else { output = true; } return result; } public override object GetInitializer(System.Type serviceType) { return null; } public override object GetInitializer(System.Web.Services.Protocols.Logic alMethodInfo methodInfo, System.Web.Services.Protocols.SoapExtensionAttribu te attribute) { return null; } public override void Initialize(object initializer) { } public override void ProcessMessage(SoapMessage message) { if (message.Stage == SoapMessageStage.AfterDeserialize) { HttpContext.Current.Request.InputStream.Position = 0; HttpContext.Current.Items["SoapInputStream"] = HttpContext.Current.Request.InputStream; appOutputStream = new MemoryStream(); HttpContext.Current.Items["SoapOutputStream"] = appOutputStream; } else if (message.Stage == SoapMessageStage.AfterSerialize) { chainedOutputStream.Position = 0; XmlReader reader = new XmlTextReader(chainedOutputStream); reader.ReadStartElement("Envelope", "http://schemas.xmlsoap.org/soap/envelope/"); reader.MoveToContent(); if ((reader.LocalName == "Header")) { reader.Skip(); } reader.ReadStartElement("Body", "http://schemas.xmlsoap.org/soap/envelope/"); reader.MoveToContent(); if ((reader.LocalName == "Fault" & reader.NamespaceURI == "http://schemas.xmlsoap.org/soap/envelope/")) { chainedOutputStream.Position = 0; CopyStream(chainedOutputStream, httpOutputStream); } else { appOutputStream.Flush(); appOutputStream.Position = 0; CopyStream(appOutputStream, httpOutputStream); } appOutputStream.Close(); } } private void CopyStream(Stream src, Stream dest) { StreamReader reader = new StreamReader(src); StreamWriter writer = new StreamWriter(dest); writer.Write(reader.ReadToEnd()); writer.Flush(); } public class SoapStreams { public static Stream InputMessage { get { return ((Stream)(HttpContext.Current.Items["SoapInputStream"])); } } public static Stream OutputMessage { get { return ((Stream)(HttpContext.Current.Items["SoapOutputStream"])); } } } [AttributeUsage(AttributeTargets.Method)] public class XmlStreamSoapExtensionAttribute : SoapExtensionAttribute { private int m_priority; public override Type ExtensionType { get{ return typeof(XmlStreamSoapExtension);} } public override int Priority { get {return m_priority;} set{m_priority = 1;} } } --********************* end of soap extension class --********************** --********************* --here is the asmx file --all it does is a simple transform of the input message --********************* using System; using System.Web; using System.Collections; using System.Web.Services; using System.Web.Services.Protocols; using System.Xml; using System.Xml.Xsl; using System.Xml.Serialization; [System.Web.Services.WebServiceBindingAttribute(Nam e = "Arithmetic", Namespace = "urn:msdn-microsoft-com:hows")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] public class arithmetic : WebService { private const string soapURI = "http://schemas.xmlsoap.org/soap/envelope/"; private const string nsURI = "urn:msdn-microsoft-com:hows"; [XmlStreamSoapExtension] [WebMethod] [SoapDocumentMethod("urn:msdn-microsoft-com:hows/Add", Use = System.Web.Services.Description.SoapBindingUse.Lit eral, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.B are)] [return: XmlElement("AddResponse", Namespace = "urn:msdn-microsoft-com:hows")] public /* AddResponse */ void Add(/* Add Add1 */) { //************ //this will transform the input stream (in a reader) directly to output stream //************ XslCompiledTransform docXsl = new XslCompiledTransform(); XsltSettings xslset = new XsltSettings(); xslset.EnableDocumentFunction = true; string xslsource = "add.xslt"; XmlUrlResolver resolver = new XmlUrlResolver(); string pathxsl = HttpContext.Current.Server.MapPath(xslsource); docXsl.Load(new XmlTextReader(pathxsl), xslset, resolver); docXsl.Transform(xReader, new XmlTextWriter(SoapStreams.OutputMessage, System.Text.Encoding.UTF8)); } public arithmetic () { //Uncomment the following line if using designed components //InitializeComponent(); } } --*************************** --end of the asmx file --**************************** --********************** --here is the xml message sent to the service by the client w/soap action of --"urn:msdn-microsoft-com:hows/Add" --which works fine as it fires the service up --************************ <?xml version='1.0' encoding='utf-8'?><soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema'><soap:Body><Add xmlns='urn:msdn-microsoft-com:hows'><n1>10</n1><n2>20</n2></Add></soap:Body></soap:Envelope> --***************** --end of the input message --***************** --***************** --here is the add.xslt file --**************** <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xsl:version="1.0"> <soap:Body> <ns:AddResponse xmlns:ns="urn:msdn-microsoft-com:hows"> <ns:sum> <xsl:value-of select="sum(//ns:Add/*/text())"/> </ns:sum> </ns:AddResponse> </soap:Body> </soap:Envelope> --****************** --end of add.xslt file --****************** |
Re: Client found response content type of '', but expected 'text/xml'
sorry forgot to include the xreader creation in the asmx code file.
Here it is, insert this into the asmx code before you use the xreader XmlReaderSettings settings = new XmlReaderSettings(); SoapStreams.InputMessage.Position = 0; XmlReader xReader = XmlReader.Create(new XmlTextReader(SoapStreams.InputMessage),settings); while (xReader.Read()) { } |
Re: Client found response content type of '', but expected 'text/xml'
could this be due to the new plumbing in vs 2005 webservices? It wants
all the code in the app_code directory and maybe when you put classes in there they don't know what is really going on, i.e., in the process they are losing their connection to the webservices http pipeline? maybe there is a parallel pipeline created that is running too and that is why I hit afterserialize twice? btw, in case you didn't figure it out, all the .cs code for this app is in the app_code directory except for the asmx file (even the asmx.cs is in app_code) per the recommendation of VS when you create these classes. If app_code classes are running in a parallel (disconnected) process then why do my soap exceptions work? For example, if I purposely put a exception in the asmx.cs file, e.g,, int x = 1/0;, then the afterserialize event sees the exception and correctly sends the regular output stream (do you call this the chained stream?) and not my appoutputstream. |
Re: Client found response content type of '', but expected 'text/xml'
BTW, the only changes I made to the web.config are below. I really
don't like using 'App_Code' as the class for my soap extension type, but that is what it took to make it work and apparently that is what VS 2005 wants you to do, i.e., put everything in that directory. <webServices> <soapExtensionTypes> <add type="XmlStreamSoapExtension, App_Code" priority="1" group="High"/> </soapExtensionTypes> <protocols> <remove name="HttpGet" /> <remove name="HttpPost" /> <remove name="Documentation" /> </protocols> </webServices> |
Re: Client found response content type of '', but expected 'text/xml'
|
Re: Client found response content type of '', but expected 'text/xml'
|
| All times are GMT. The time now is 04:57 AM. |
Powered by vBulletin®. Copyright ©2000 - 2013, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.