Sreerag Sreerag - 4 months ago 36
reST (reStructuredText) Question

Intercepting SOAP web service calls using HttpModule and making REST API call to deliver response

I have this requirement to intercept web method calls in an existing legacy .asmx web service, read the request to identify the business case which needs to be handled by a new Web API end point.

The client that talks to the asmx service is also some legacy system that probably has service reference added and makes web method calls and not aware of the new rest api to make direct calls. Hence, should be unaware of the change and consumes the SOAP response as always.

So far i've managed to add a custom HttpModule class, intercept the request, read the input stream and make an api call to get the response from it. But how do i send the SOAP response back to the client and end the request so that it doesn't go to the targeted web method.

Here is my Custom HttpModule class :

public class CustomHttpModule : IHttpModule
{
public void Dispose()
{
throw new NotImplementedException();
}

public void Init(HttpApplication application)
{
application.BeginRequest += (new EventHandler(this.Application_BeginRequest));
}

private void Application_BeginRequest(Object source, EventArgs e)
{
// Create HttpApplication and HttpContext objects to access
// request and response properties.
HttpApplication application = (HttpApplication)source;
HttpContext context = application.Context;

// Initialize soap request XML
XmlDocument xmlSoapRequest = new XmlDocument();

// Move to begining of input stream and read
context.Request.InputStream.Position = 0;

StreamReader readStream = new StreamReader(context.Request.InputStream, Encoding.UTF8);
// Load into XML document
if (readStream.BaseStream != null && readStream.BaseStream.Length > 0)
{
//string streamString = readStream.ReadToEnd();
xmlSoapRequest.Load(readStream);
}

context.Request.InputStream.Position = 0;

// Check if the request is for the web method to be intercepted
if (xmlSoapRequest.GetElementsByTagName("SomeWebMethodName").Count > 0)
{

string response = "";
using (WebClient wc = new WebClient())
{
string URI = "http://localhost:19875/api/home";

wc.Headers[HttpRequestHeader.Accept] = "application/xml";
wc.Headers[HttpRequestHeader.ContentType] = "application/xml";
response = wc.UploadString(URI, xmlSoapRequest.InnerText);
}

context.Response.ContentType = "text/xml";
context.Response.Write(response);
context.Response.End();

}
}
}


I get the error "Unrecognized message version." on the client now.
I'm guessing the response needs to be a SOAP response, how can i create that? also, is there a better approach to the whole ask?
Thank you.

Answer

I've got this working. Basically I had to embed the output in the SOAP response body structure like so

                var soapResponse = new StringBuilder("<?xml version=\"1.0\" encoding=\"utf-8\"?>")
                                   .Append("<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\">")
                                   .Append("<soap:Body>")
                                   .Append("<WebMethodResponse xmlns=\"http://tempuri.org/\">")
                                   .Append(String.Format("<WebMethodResult>{0}</WebMethodResult>",HttpUtility.HtmlEncode(webApiResponse)))
                                   .Append("</WebMethodResponse>")
                                   .Append("</soap:Body>")
                                   .Append("</soap:Envelope>");

                context.Response.ContentType = "text/xml";
                context.Response.Write(soapResponse);
                context.Response.End();

To manually create the SOAP response like above, I had to know what the response xml is like when the request is served by the web method directly. For this, we can plug in a SOAP extension to intercept the outgoing message stream and read it like shown in http://www.codeproject.com/Articles/445007/Intercept-a-raw-SOAP-message