4

I have a problem with message parsing on WCF service. I ran server-side of WCF application. Another company sends me such HTTP POST request:

POST /telemetry/telemetryWebService HTTP/1.1
Host: 192.168.0.160:12123
Content-Length: 15870
Expect: 100-continue
Connection: Keep-Alive

<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Header>
    <wsse:Security> ... </wsse:Security>
  </soapenv:Header>
<soapenv:Body>
...
</soapenv:Body>
</soapenv:Envelope>

How you can see this in this HTTP request missing 2 important headers: Soap Action and Content-type.That's why my service cannot process this request correctly.

I need to catch the request until it starts to be processed and manually add these headers.

I've already tried IDispatchMessageInspector, but whithout any result.

2
  • 3
    Can you tell us why the attempt with IDispatchMessageInspector didn't work, perhaps show (a sample of) the code and the problem/error with it? Note that you can edit your question at any time. (PS. I don't suppose fixing this on the client side is an option?) Commented Sep 30, 2012 at 12:09
  • 1
    I feel your pain :P "Hey, let's use this SOAP thing. It's just a bunch of XML, right? Wait, what? You mean there's a spec for it? And tools that will generate code to do the right thing for you?" Commented Sep 30, 2012 at 21:17

2 Answers 2

2

When working with SOAP messages the dispatching in the server side is done according to the soap action header, which instructs the dispatcher what is the corresponding method which should handle the message.

Sometimes soap action is empty or invalid (java interop).

I think you best option is to implement an IDispatchOperationSelector. With this, you can override the default way the server assigns incoming messages to operations.

In the next sample, the dispatcher will map the name of the first element inside the SOAP body to an operation name to which the message will be forward for processing.

 public class DispatchByBodyElementOperationSelector : IDispatchOperationSelector
    {
        #region fields

        private const string c_default = "default";
        readonly Dictionary<string, string> m_dispatchDictionary;

        #endregion

        #region constructor

        public DispatchByBodyElementOperationSelector(Dictionary<string, string> dispatchDictionary)
        {
            m_dispatchDictionary = dispatchDictionary;
            Debug.Assert(dispatchDictionary.ContainsKey(c_default), "dispatcher dictionary must contain a default value");
        }

        #endregion

        public string SelectOperation(ref Message message)
        {
            string operationName = null;
            var bodyReader = message.GetReaderAtBodyContents();
            var lookupQName = new
               XmlQualifiedName(bodyReader.LocalName, bodyReader.NamespaceURI);

            // Since when accessing the message body the messageis marked as "read"
            // the operation selector creates a copy of the incoming message 
            message = CommunicationUtilities.CreateMessageCopy(message, bodyReader);

            if (m_dispatchDictionary.TryGetValue(lookupQName.Name, out operationName))
            {
                return operationName;
            }
            return m_dispatchDictionary[c_default];
        }
    }
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you. This is a coorect answer. It works, but not for all problems.
0

Thank you all.

1) You need to create you own custom message encoder, where you can create the Content-type by default. Yщu can read it here with examples.

2) You need to create custom message filter because you need to skip messages without SoapAction

public class CustomFilter : MessageFilter
{
    private int minSize;
    private int maxSize;
    public CustomFilter()
        : base()
    {

    }
    public CustomFilter(string paramlist)
        : base()
    {
        string[] sizes = paramlist.Split(new char[1] { ',' });
        minSize = Convert.ToInt32(sizes[0]);
        maxSize = Convert.ToInt32(sizes[1]);
    }
    public override bool Match(System.ServiceModel.Channels.Message message)
    {
        return true;
    }
    public override bool Match(MessageBuffer buffer)
    {
        return true;
    }
}

3) You need to create custom message selector for assigning incoming messages to operations. Cybermaxs's example is very good.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.