tags:

views:

119

answers:

1

I am in the process of setting up a web service for an external client to connect to my client's application and update some information. I went the ASMX route (the rest of the application runs on WCF) because I knew the external client could be very difficult to deal with and I was trying to keep everything as simple as possible. They also aren't a .Net shop which makes things worse. After getting the service setup for them I provided the ASMX URL for them to see how to format the SOAP headers/message content. They have since come back and told me their tool is unable to send them in the format required by .Net and I can either come up with a different way to accept messages or we have to go with FTP.

Based on this I have been researching how to intercept their message, reformat it the way my service requires it (which means adding two lines), and then let it process. This path led me to SOAP Extensions which I have been trying to work with but can't seem to figure out. When I have my sample application call the web service from the generated code Add Web Reference provides everything works great until I add in my extension. All it currently does is override ChainStream setting an internal stream equal to the one being passed in and returning a new stream, like this:

private Stream newStream = null;
private Stream oldStream = null;

public override Stream ChainStream(Stream stream)
{
    this.oldStream = stream;
    this.newStream = new MemoryStream();
    return newStream;
}

I also override ProcessMessage and in it take the contents of oldStream and set newStream equal to that and then write to a different stream with an XmlWriter. I take that new stream and using a StreamReader read it into a string, with the end goal being manipulating it here and setting newStream (which is being used by ChainStream) equal to the contents of this. Here is that piece:

    public override void ProcessMessage(SoapMessage message)
{
    switch (message.Stage)
    {
        case SoapMessageStage.BeforeDeserialize:
            this.Process();
            break;

        default: break;
    }
}

private void Process()
{
    this.newStream.Position = 0L;
    XmlTextReader reader = new XmlTextReader(this.oldStream);
    MemoryStream outStream = new MemoryStream();
    using (XmlWriter writer = XmlWriter.Create(outStream))
    {
        do { writer.WriteNode(reader, true); } while (reader.Read());
        writer.Flush();
    }
    outStream.Seek(0, SeekOrigin.Begin);
    StreamReader streamReader = new StreamReader(outStream);
    string message = streamReader.ReadToEnd();
    newStream = outStream;
    newStream.Seek(0, SeekOrigin.Begin);
    streamReader.Close();

}

By running this, which seems to me like it would be fine, my test application gets a 400 Bad Request back from the service. If I either don't use the extension or I don't do anything in ProcessMessage everything seems fine. Any suggestions to this?

As a side note, once I get this working with the generated code from the WSDL I will be moving to a WebRequest to try sending the message to the service. Currently that bombs out with a 415 Unsupported Media Type response. I'm trying to keep this post to one question but if anyone has any tips with using a WebRequest to connect to an ASMX service it would be much appreciated!

+1  A: 

I realise this isn't the answer you're looking for but why not just use REST instead of SOAP? Since the main (only?) consumer of the service isn't going to comply, trying to 'fix' their calls is just an extra layer of complexity.

Instead, just use an aspx page that accepts data on the query string or with an xml request body, process it and then stream the xml (or other format) response back to them.

You lose the Visual Studio SOAP "magic" which auto-generates type info etc. but since they aren't using (or aren't admitting to using) a language with a SOAP library, this doesn't really help anyone.

Zarigani
Interesting...I hadn't thought of that, but it definitely makes sense. I'll investigate it a bit further as, if nothing else, a standard POST to a page could be perfect (albeit not ideal) just to get past this.Thanks!
digitall
It looks like this is going to take me down the path I need. Thanks again!
digitall