I'm trying to consume a SOAP service using WCF in .NET 5. The service provider expects the content type of the request to be text/xml but sends a response with content type application/xml.
The following code throws a ProtocolException because is expects both request and response to have content type text/xml.
var binding = new BasicHttpBinding();
var endpoint = new EndpointAddress("http://[...]/inquiry");
var channelFactory = new ChannelFactory<InquiryServiceSoapPort>(binding, endpoint);
var serviceClient = channelFactory.CreateChannel();
var inquiry = new Inquiry();
var result = serviceClient.createInquiry(inquiry);
I was able to change the content type to application/xml using a custom encoder, but that changes it for both request and response, and my request then is rejected by the server.
Is there a way to change the content type of the response only?
Edit
I am writing client-side code, not server-side code, mind you. As of now, it seems I can only catch and swallow the exception or re-implement the code either using another framework or from scratch.
Have a look at the WCF architecture here:
https://learn.microsoft.com/en-us/dotnet/framework/wcf/architecture
So we have the ABC of WCF is the Address, Binding and Contract, and here we are in the contract serialization
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/data-transfer-and-serialization
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/data-contract-serializer
in detail:
https://learn.microsoft.com/en-us/dotnet/api/system.runtime.serialization.datacontractserializer?view=net-5.0
the are the concept i recommend diving into, the http header type "content-type" is really a function of the rest in case You make the BasicHttp binding
https://learn.microsoft.com/en-us/dotnet/api/system.servicemodel.basichttpbinding?view=dotnet-plat-ext-5.0
Which is sort of only the corner of a much bigger tool available in WCF. for instance wsHttpBinding which is really preferable in many scenarios, could alone solve your problem if the endpoint is available.
In the wsHttpBinding You can control the message encoding
https://learn.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/wcf/wshttpbinding
Ultimately choosing your Message encoder will determine how headers are set, there is a wealth of abstraction level(s) compared to REST io model, but it's there:
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/choosing-a-message-encoder
And You can even roll You own.
I have a client that does send Soap11 content, but with a different content type. It does not send text/xml but application/some-custom-header.
The client receives the following exception
Cannot process the message because the content type 'application/some-custom-header; charset=utf-8' was not the expected type 'text/xml; charset=utf-8'.
what do i need to change?
I got it. I combined the encoding elements from the Invoking a web service returning ISO-8859-1 encoded data with BizTalk 2010 example, but replaced the Read/WriteMessage methods from the CustomMessageEncoder with the calls to a MessageEncoder retrieved from a TextMessageEncodingBindingElement and its MessageEncoderFactory.
I created a Web API which accepts Json string and returns an XML.
I am trying to test my web API using fiddler and unable to test it.
My get method in code:
[HttpGet]
public XmlDocument GetXML([FromBody]string JsonString)
{
System.Xml.XmlDocument xmlDocument = Newtonsoft.Json.JsonConvert.DeserializeXmlNode(JsonString);
In fiddler :When I provide the content type as application json(below is screen shot). It throws a HTTP 500 error.
"An error has occurred.No MediaTypeFormatter is available to read an object of type 'String' from content with media type 'application/json'."
But when I provide the content-Type :application/xml. It successfully makes a connection to the web api but the Input parameter "JsonString" is null.
From your screenshot though it looks like you ARE in fact passing a string because it start with an equals and quotes like ="{ ... }". This looks like a JSONP body. JSON would look start with curl braces like { ... }
If you need to accept JSONP have a look at this answer:
JSONP with ASP.NET Web API
I created C# project and add a "web service" as a "Service Reference".
my service almost allways works good, but sometimes, occures this error:
The content type text/html of the response message does not match the
content type of the binding (text/xml; charset=utf-8). If using a
custom encoder, be sure that the IsContentTypeSupported method is
implemented properly. The first 13 bytes of the response were:
'<HTML></HTML>'.
I google this error, but i didnt find anything related to this
all my search results relates to WCF
most important point on this error is "response were: '<HTML></HTML>'"
client expect "xml response", but server response an empty "html response"
Could you please advice what could be wrong?
[edited]
my code is very simple:
webserv.Insert_ImageSoapClient myservice = new webserv.Insert_ImageSoapClient();
string response = myservice.insert_x(station_id_x, time_t);
Sounds like the web service is erroring out and returning an HTML page.
I can see the object in Fiddler but the object is not deserializing on my end. Has anyone seen this before?
"Response is null" or "Response contains nulls" or "Request is null" or "Request contains null" almost always mean that you have a namespace mismatch. For instance, the response may contain:
<response xmlns="http://foo.com"/>
but should in fact be
<response xmlns="http://bar.com"/>
In this case, null will be received.
I had the same problem, and as suggested the namespace problem was the root cause.However, my proxy class has nested classes and long chain of nested namespace.
It was confusing to identify the correct namespace to apply in Cs code for proxy class. Here, i describe how to figure out the namespace which is required to be updated in client proxy.
What i did was intercept the request in ClientMessageInspector class, AfterReceiveReply method (Enables inspection or modification of a message after a reply message is received but prior to passing it back to the client application.) Verified the namespace of the object which were returning null in Response by using XMLDocument. I updated the proxy class with the namespace retreived from XML. After making the changes, the objects were not null in response.
public class MyMessageInspector : IClientMessageInspector
{
public void AfterReceiveReply(ref System.ServiceModel.Channels.Message request, object correlationState)
{
MemoryStream ms = new MemoryStream();
XmlWriter writer = XmlWriter.Create(ms);
request.WriteMessage(writer);
writer.Flush();
ms.Position = 0;
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(ms);
this.ReadMessage(xmlDoc);
ms = new MemoryStream();
xmlDoc.Save(ms);
ms.Position = 0;
XmlReader reader = XmlReader.Create(ms);
Message newMessage = Message.CreateMessage(reader, int.MaxValue, request.Version);
newMessage.Properties.CopyProperties(request.Properties);
request = newMessage;
}
private void ReadMessage(XmlDocument xmlDoc)
{
XmlNode v1 = xmlDoc.GetElementsByTagName("XPAth");
//Actual Namespace in XML, which should be used in Proxy Class
string namespaceURIForObjectInXML = v1.NamespaceURI;
}
public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
{
}
}
I had a similar case where I created a client via SVCUTIL / Service Reference from VS. The response was received successfully with correct data (confirmed via IClientMessageInspector.AfterReceiveReply method) however the values at the object level were not being populated. There were no de-serialization errors (confirmed via system.diagnostics output)
The problem was twofold:
1) Certain objects were named exactly as their types but had different namespaces from their types. This seems to have confused the proxy generator in assigning the namespace parameter (in the System.Xml.Serialization.XmlElementAttribute annotation) of the class to the one of the object
2) The order parameter (in the System.Xml.Serialization.XmlElementAttribute annotation) of the properties was not required and also the namespace parameter was missing
so from: [System.Xml.Serialization.XmlElementAttribute(IsNullable=true, Order=0)]
to: [System.Xml.Serialization.XmlElementAttribute(IsNullable=true, Namespace="http://www.whathevernamespaceiscorrect.com")]
So basically, in the generated proxy I needed to fix the namespace of the class to the one specified in the type, and replace the order parameter with the namespace parameter setting it to the correct namespace according to the wsdl
The only reason I can think of is a contract mismatch. Although it's strange if no validation error is thrown. Are you using a client generated from the correct WSDL? Is it a WCF client or a SOAP one? The former one does validation, I'm sure, but schema mismatches may slip through the latter.
Every time this happens to me, it's because I need to update my service references. Try that and let me know what happens :)
Solved it... or at least have workaround. In the Java code the #XmlElementRefs and #XmlElementRef should have been #XmlElements and #XmlElement respectively (as well as the "type" attribute it needed a "name" attribute).
Guessing if I'd posted this as a new question with a Java tag as well as C# and web-services some hawk-eyed stackoverflower would have spotted this schoolboy error.
I had a similar issue which i resolved by checking the Order value in the Reference.cs.
[System.Xml.Serialization.XmlElementAttribute(Order=0)]
The order of the return parameters had changed but updating my service reference in visual studio didn't change the "Order" value.
Check that parameters returned in Fiddler/SoapUI are the same as in your proxy generated class.
Ensure the definition / specification matches the output. Compare the WSDL (in browser) and the response (in SOAP-UI, Fiddler), e.g.
WSDL uses camel case (lastName) and
response uses underscores (last_name).