1
votes

How to configure WCF client to work with third party WS service hosted on the server that doesn't return content-type in the reply?

Problem is that such WCF client configured to use basicHttpBinding throw an exception: "content-type is required"...

Should I use custom bindings or refuse WCF?

P.S. .NET 3.5

P.P.S Message: An HTTP Content-Type header is required for SOAP messaging and none was found Server stack trace: at System.ServiceModel.Channels.HttpChannelUtilities.ValidateRequestReplyResponse(HttpWebRequest request, HttpWebResponse response, HttpChannelFactory factory, WebException responseException)

at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout) at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout) at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout) at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout) at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs) at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation) at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Exception rethrown at [0]: at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg) at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type) at blablabla (custom code)

2
Or maybe you should "refuse" the third-party WS which does not follow standards?John Saunders
BTW, after reading w3c documentation I have a strong sense that content-type header is not mandatory by SOAP 1.1 (as well as by HTTP 1.1), and is mandatory only from SOAP 1.2 version... So this is WCF bug, or if you want, basicHttpBinding feature.Roman Pokrovskij

2 Answers

0
votes

I can say that this is impossible. I want to show why:

Very deep internal code (System.ServiceModel.Channels.HttpChannelFactory+HttpRequestChannel+HttpChannelRequest class, WaitForReply method) - you will never want to do inheritance and reflecetion focuses there with those inner classes - contains two lines

var response = (HttpWebResponse) this.webRequest.GetResponse(); // webRequest is type of HttpWebRequest HttpInput input = HttpChannelUtilities.ValidateRequestReplyResponse(this.webRequest, response, this.factory, responseException);

since HttpWebRequest is public and GetResponse is virtual seems that it's possible to override it this way

public class FakedHttpWebRequest: HttpWebRequest
{

        protected FakedHttpWebRequest(SerializationInfo serializationInfo, StreamingContext streamingContext) : base(serializationInfo, streamingContext)
        {
        }

        public override WebResponse GetResponse()
        {
            WebResponse wr = base.GetResponse();
            wr.ContentType = "text/xml";
            return wr;
        }
}

and then we need using reflection somewhere create FakedHttpWebRequest instead of HttpWebRequest...

Unfortunately this time "somewhere" appear to be static(!) method (WebRequest.Create), so there are no chance to stay in "small hack" scope.

0
votes

I feel I found the scheme how it can be hacked.

Inherit new class from System.ServiceModel.Channels.HttpChannelFactory+HttpRequestChannel+HttpChannelRequest and override WaitForReply virtual method

Inherit new class from System.ServiceModel.Channels.HttpChannelFactory+HttpRequestChannel and override CreateRequest(Message) interface method

Inherit new class form System.ServiceModel.Channels.HttpChannelFactory and override OnCreateChannel(EndpointAddress remoteAddress, Uri via) method

problem: all those classes are private and internal (!). solution, create them on run-time using: reflection/emit/TypeBuilder/codedom. All mentioned methods are short (only WaitForReply is verbose) and all methods are virtual - there we are really lucky.

then inherit from Http(s)TransportBindingElement and override BuildChannelFactory(BindingContext context);

and then create custom binding

:)

P.S. I'm not sure is it possible to create new type inheriting it from internal, protected class, from other assembly, but I guess it is possible.