Rick Strahl's Web Log

Wind, waves, code and everything in between...
ASP.NET • C# • HTML5 • JavaScript • AngularJs
Contact   •   Articles   •   Products   •   Support   •   Search
Ad-free experience sponsored by:
ASPOSE - the market leader of .NET and Java APIs for file formats – natively work with DOCX, XLSX, PPT, PDF, images and more

Syncing up external WSDL Schemas with a stock .ASMX Web Service?


On this page:

 

I’ve been involved in a project where I’m interfacing with a partner Web Service that asynchronously processes messages. Messages are sent to the Web Service and then at some point in the future (hours or days later) the host application sends a SOAP message back to our server at URL we provide.

 

The Web Service on the host consists basically of a single endpoint - it receives only a very complex message structure which serves the entire system. The message hold both the input data and the result data that is sent back, so effectively there's a single message entity to encompasses the entire messaging in the service.

 

The message in question is defined by the main Web Service – there’s WSDL and with some tweaking of the WSDL I was able to call the Web Service and pass this very complex hierarchical object to the Web Service. So far so good.

 

The Host Web Service is not a .NET service – it looks like a homegrown implementation, but I can’t really tell exactly. In any case the WSDL for the service has allowed me to pick up this very complex type in my client application. Sending the message seems to work just fine using standard a .NET Web Reference interface. Through this interface I can pick up the entire message type, which is great because I'll need it on the inbound end to receive messages. The WSDL provides this interface luckily so no manual type creation!

 

So now my problem is that I need to implement the receiving Web Service but I can’t get ASMX to generate the structure necessary to accept this SOAP message sent by this non-.NET host application server. What I’ve done so far is use the types that the WSDL import for the Web Reference imported and then use that as an input parameter for my own Service method:

 

[WebMethod(MessageName="NotifyRequest")]

public string ReceiveMessage(OmniCellProvider.OmniConnectService.MetaOMNIConnect MetaOMNIConnect)

{

    return MetaOMNIConnect.OMNIConnectMessage.BulkMessageHeader.RecipientList[0].PartnerID;

}

 

When the call comes in though, the inbound parameter is null, which is caused by the mismatch in the message formats I assume.

 

 

The problem is that the service definition of the host service doesn’t match the signature that .NET ASMX services generate. Basically the Host service sends the message without a top level message root element. The body root node is the top level object, which has caused some problems in a variety of places (for COM interop, because .NET marks the top level ‘object’ as a SoapHeader type which is not ComVisible for example).

 

Here’s the top level of the message as sent by the host server:

 

<?xml version="1.0" encoding="UTF-8" ?>

<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"

                   xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">

  <SOAP-ENV:Body>

    <MetaOMNIConnect xmlns="http://www.omnimoving.com/OMNIConnect">

        <OMNIConnectMessage>

            <BulkMessageHeader>

                <Sender>

 

And this is what the .NET Web Service expects:

 

<?xml version="1.0" encoding="utf-8"?>

<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">

  <soap:Body>

    <NotifyRequest xmlns="http://www.omnimoving.com/OMNIConnect">

      <MetaOMNIConnect>

        <OMNIConnectMessage>

          <BulkMessageHeader>

 

Notice that the .NET Service has a root node above the actual message object (MetaOMNIConnect).

 

Is there any way to force the .NET Web Service to expose its interface so that it matches the calling service?

 

 

In the meantime I’ve worked around this issue with a combination of an ASP.NET HTTP Handler and XML Serialization. Rather than using a Web Service, I just have the handler pick up the file, then read the input buffer directly and deserialize it with an XmlReader. Here’s the rough test code I hacked together for this:

 

public void ProcessRequest(HttpContext context)

{

    HttpRequest Request = context.Request;

    HttpResponse Response = context.Response;

 

    string XmlString = null;

 

    XmlReader xr = XmlReader.Create(Request.InputStream);

    while (xr.Read())

    {

        if (xr.NodeType == XmlNodeType.Element && xr.Name == "MetaOMNIConnect")

        {

            MetaOMNIConnect Message = this.DeSerializeMessage(xr);

 

            // *** Echo back a value from the result

XmlString = Message.RateResponse.ServiceQuote.Rate.Value.ToString();

            break;

        }

    }

 

    Response.ContentType = "text/plain";

    Response.Write(XmlString);

}

 

protected MetaOMNIConnect DeSerializeMessage(XmlReader xr)

{

    object Instance = null;

    XmlSerializer serializer = null;

    try

    {

        // Create an instance of the XmlSerializer specifying type and namespace.

        serializer = new XmlSerializer(typeof(MetaOMNIConnect));

 

        Instance = serializer.Deserialize(xr);

    }

    catch (Exception ex)

    {

        string ErrorMessage = ex.Message;

        return null;

    }

 

    return Instance as MetaOMNIConnect;

}

 

This works, but it’s not exactly proper SOA implementation <bg>… And I should count myself lucky there's only a single message that is actually sent here, otherwise this would get much uglier.

 

When it really comes down to it, I would like to use a proper Web Service on our Server to handle this for me, but I’m not inclined to hand code my own WSDL and service definition for this monster message type definition.

 

So the questions are:

 

  • Is there a way to modify the ASMX input message format so it fits the message schema sent by the host service?
  • If not, what would be the recommended approach to make this happen?
  • Does WCF help in this respect at all? I know on the client end WCF provides a lot more control over the SOAP messages sent – I suspect there might be more control on the hosting end as well.

I’m a little out of my range on this one, so I appreciate any feedback provided even if it’s just some general thoughts on this subject.


The Voices of Reason


 

Christian Weyer
July 28, 2006

# re: Syncing up external WSDL Schemas with a stock .ASMX Web Service?

Did you try generating the service stub code from the WSDL? E.g. with wsdl.exe or WSCF?

Cheers,
Christian

Travis Laborde
July 28, 2006

# re: Syncing up external WSDL Schemas with a stock .ASMX Web Service?

I'm not sure if this will help you but I've faced a similar situation recently.

I needed to create a webservice that would accept messages whose format was dictated by the client.

My input was always coming in as NULL, even though through packet sniffing and ws extensions I was able to see that the xml was indeed coming in, and in the correct format...

As it turns out, the client was not sending it using what I'd call a standard SOAP request but was instead just doing an HTTP POST to my webservice.

In my case I was able to just grab the REQUEST object and cast it to string and load it into an XML document and parse it accordingly. Their supplied WSDL was correct after that so it was easy then to use their message.

Hope this helps!

Steve from Pleasant Hill
July 28, 2006

# re: Syncing up external WSDL Schemas with a stock .ASMX Web Service?

I too had to handle a "SOAP message" which was really just some malformed XML that I had to clean up in the stream before I loaded it into an XML doc. There was never a WSDL to begin with, but once the stream was in an XML doc things worked well and I was thankful for the XML features in .NET!

Used a WinForm app and socket communications to send the HTTP POST and waited for the XML to show up, then it would clean it, parse it, and take whatever actions necessary. Guess I never thought about doing a Web Service...

Rick Strahl
July 28, 2006

# re: Syncing up external WSDL Schemas with a stock .ASMX Web Service?

Chris... DUHHH... Little embarrased but I didn't actually realize WSDL.EXE also can generate server implementations. I've done things the hard way for so many years without .NET it's sometimes easy to overlook some important feature like this <s>..

It worked and I was able to pick up my type with the test messages, althrough I had to tweak the WSDL some more to get past some binding problems. Thanks Chris!!!

Steve, what you're describing is basically what I am currently doing with the HTTP Handler.

I agree on the XML features in .NET. The ability to pick up very complex WSDL and create types through Web Service imports, then read in an XML document, and match one of those imported types manually, and then use XML Serialization to read in that type, is nothing short of awesome - that is if you ever had to do this shit manually...


Michael Freidgeim's Blog
July 09, 2007

# Tools to generate WSDL from SOAP Sample?

 

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2018