Consume SOAP webservice with GET instead of POST - c#

I need to call an external SOAP webservice over HTTP.
I have the WSDL file and added it in Visual Studio via 'Add service reference'. Visual studio then added a number of files, in the reference file i can find this:
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(ConfigurationName="Service.IService")]
public interface IService {
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IService/Function", ReplyAction="http://tempuri.org/IService/FunctionResponse")]
namespace.Service.ExecuteFunctionResponse ExecuteFunction(namespace.Service.FunctionRequest request);
}
With additionaly the async version of this call and the objects for sending an receiving, etc.
To call the service I added the folowing code:
BasicHttpBinding binding = new BasicHttpBinding();
EndpointAddress endpointAddress = new EndpointAddress("the address");
serviceChannel = new ServiceClient(binding, endpointAddress).ChannelFactory.CreateChannel();
Response response = serviceChannel.ExecuteFunction(new Request(...));
This results in me getting an exception, error 405 method not allowed.
So it appears I must use a HTTP GET request instead of the default POST request. But i cannot find where this can be altered in with this way of working.
So, where can i set the HTTP method for this call to a webservice?

SOAP services are using HTTP POST because they exchange XML messages (which tend to be complex) and cannot be transferred in a query string.
Are you sure that you must use HTTP GET? Maybe the error you are receiving "405 method not allowed" is caused by some bad configuration.
I would double check the SOAP endpoint URL is set correctly and check that there are no additional security requirements needed.
EDIT
In past, there was a practice to create ASP.NET Web Services which would accept GET as well. But they wouldn't expect XML messages. Instead, you would have to pass all parameters in a querystring. For example: https://foo.bar/service.asmx/Func?param1=X&param2=Y (where param1 and param2 are the expected parameters).
This way it is possible to call a WebService without a need for WSDL and using GET method. You can achieve it by using HttpClient for example.
The downside of this approach is that you will have to deal with plain data instead of objects.
I hope it might help.

Related

Why does a WCF web service not receive the client payload?

I have inherited a web service built to receive calls from a third party system, "System A". It was a POC that may not have any active functions calling it and I suspect it was only tested from SoapUI or the like and never from the application it was designed for.
When System A is configured to call it, the service is called but the payload, one complex-type parameter, is null.
I have two other web services written years ago that accept calls of the same type from the same function of System A. Pointing System A to either of these services results in the parameter being supplied. Contracts and WSDLs look very similar and the only variations I see (like differing namespaces) seem to vary between the two services that do work.
What would cause a web service to not receive the payload in the call?
Related, where should I look to find it? The parameter is getting dropped between System A calling and the web service code itself getting hit. I've checked the trace logs but see nothing that I recognize as useful.
namespace MyNamespace.StandardNoteReceiverService
{
public class StandardNoteReceiverService : IReceiveNoteService
{
public StandardNoteReceiverResponse ReceiveNote(ReceiveNoteData standardNoteReceiverRequest)
{
string x = standardNoteReceiverRequest == null ? "NULL" : "ok";
LoggingLib.Log($"Service called. Paramter status: {x}");
return NoteReceiverServiceLayer.ReceiveNote(standardNoteReceiverRequest);
}
}
}
which implements
namespace MyNamespace.StandardNoteReceiverService
{
[ServiceContract]
public interface IReceiveNoteService
{
[OperationContract]
StandardNoteReceiverResponse ReceiveNote(ReceiveNoteData standardNoteReceiverRequest);
}
}
It turned out to be the parameter naming. Once I changed the name of the parameter to be the same as the name used by the services that are working, it began receiving the data.
public class StandardNoteReceiverService : IReceiveNoteService
{
public StandardNoteReceiverResponse ReceiveNote(ReceiveNoteData NoteData)
{ ...
How did you build “System A”? Is it a WCF Web HTTP service or an ancient soap web service? How does the client call the service and send the parameter? I think it may be that the format of the parameters sent by the client is incorrect. In the Rest-style service created by WCF, using complex objects as parameters to pass data may not always receive the value of the parameter on the server because of the format of the parameter.
Get the object is null using JSON in WCF Service
While in the WCF SOAP web service, the invocation is completed with a client proxy, the parameters are strong-typed. If the server always gets null, it might be caused by other issues.
I suggest you create a minimal, producible example so that I can try to offer a workaround instead of offering speculation of this issue here.
Feel free to let me know if the problem still exists.

Implementing a SOAP web service

I have a WSDL definition for a SOAP service and I have successfully generated *.cs file from it using SvcUtil.
Implementing client is quite straightforward - I just need to call the necessary functions from the generated *.cs and that's it.
Implementing server seems more complicated. As I understand I need to implement an interface from the generated *.cs and then use some magic to turn it into the web server.
But I don't need a new web server, I already have a web server written in C# which already has many functionality unrelated to the SOAP service that I need to implement. I don't want to create another web server but I want my SOAP service to be just a part of my existing application (server), that is my server can answer e.g. requests http://example.com/request1, http://example.com/request2 etc. and I want this SOAP service to be just http://example.com/request3.
Since HTTP is already handled by my server I don't need .NET to handle it for me, basically my server can accept client connections and call the necessary handler based on the URL. I have a handler for SOAP request which looks approximately like this:
MyResponse HandleSOAPRequest(MyRequest request)
{
// 1. parse soap message from request.body
// 2. process it
// 3. generate response, serialize it in SOAP format and return it
}
The question is - can I rely on WSDL definition and .NET libraries to do it?
Currently I'm parsing SOAP request using XDocument and manually extract fields from it and serialize using simple string concatenation. Using .NET built-in functions to serialize or parse XML doesn't work. That is if I try to serialize response from an object of the class defined in the generated *.cs file then produced XML is different from what is expected by the protocol, similarly, if I try to parse request as an object of the class defined in the generated *.cs file I get error because XML parser expects different format. This applies to both the SoapFormatter and XmlSerializer.
Since .NET can implement client this means that everything that is necessary to parse and serialize SOAP messages is already implemented, I just need to figure out a way how to use this functionality.
The documentation for ServiceModel wasn't very helpful.
The easiest way would be to start the service via the ServiceHost:
ServiceHost host = new ServiceHost(typeof(YourService));
host.Open();
(I assumed here the configuration will come from the app.config and will not be setup in code like in the linked example below.)
How to: Expose a Contract to SOAP and Web Clients
The only drawback of this is that the application has to run with admin rights or otherwise a weird cofiguration is necessary.

Can ServiceStack mimic a WCF response?

I'm trialling out ServiceStack and loving what I'm seeing so far. However I've run into a bit of a brick wall.
I have a system retrieving data from another system via web services - a service at both ends. These two systems are from different vendors - so I have no control over changing them - and are configured to talk to each other via WCF web services. Let's say "Lemon" calls "Orange" to get some information about a customer.
The way we implement these two systems is slightly different to what the vendors planned - we point their service configuration to our intermediary service - let's call it "Peach" - which goes off and does some other things before returning the information. For example, "Lemon" calls what it thinks is "Orange" but is actually our intermediary service "Peach" using the same method names. "Peach" calls "Orange" for the customer information and for example overrides the email address for the customer with something else before combining all the information appropriately and returning it to "Lemon" in the format it was expecting.
I would like to get "Peach" using ServiceStack. However it's responses needs to be identical to a WCF service returning via wsHttpBinding. Is this possible with ServiceStack? Would it involve overriding the Soap 1.2 type?
Thanks for your help!
If ServiceStack's built-in SOAP Support doesn't return the response you're after, you may need to return the exact SOAP response you're after as a raw string.
Raw Access to WCF SOAP Message
To access the WCF's Raw Request in your Service you can use the IRequiresSoapMessage interface to tell ServiceStack to skip de-serialization of the request and instead pass the raw WCF Message to the Service instead for manual processing, e.g:
public class RawWcfMessage : IRequiresSoapMessage {
public Message Message { get; set; }
}
public class MyServices : Service
{
public object Post(RawWcfMessage request) {
var requestMsg = request.Message... //Raw WCF SOAP Message
}
}
Creating custom WCF Response
Some level of customization is possible by creating a custom WCF Message response and returning the raw output as a string, e.g:
var wcfResponse = wcfServiceProxy.GetPeach(...);
var responseMsg = Message.CreateMessage(
MessageVersion.Soap12, "urn:GetPeach", wcfResponse);
return responseMsg.ToString();
Otherwise you may need to use a HTTP Client like Http Utils to POST raw SOAP to the WCF Service and return the raw string Response.
This question isn't specifically related to WCF. What WCF returns is not a construct of WCF, it is returning a standards based response as specified by the WS* standards. http://en.wikipedia.org/wiki/List_of_web_service_specifications lists many of the standards.
Your question isn't specifically making ServiceStack emulate WCF, it is for ServiceStack to return responses adhering to existing published standards. Standards that WCF has already built in with the WsHttpBinding configuration.

System.Web.Services.Protocols.SoapException: Server did not recognize the value of HTTP Header SOAPAction:

An exception flows when I was trying to call a method on web service:
System.Web.Services.Protocols.SoapException: Server did not recognize the value of HTTP Header SOAPAction: http://localhost:53460/3Development/MyWebService.asmx/GetBasePath.
at System.Web.Services.Protocols.Soap11ServerProtocolHelper.RouteRequest()
at System.Web.Services.Protocols.SoapServerProtocol.RouteRequest(SoapServerMessage message)
at System.Web.Services.Protocols.SoapServerProtocol.Initialize()
at System.Web.Services.Protocols.ServerProtocolFactory.Create(Type type, HttpContext context, HttpRequest request, HttpResponse response, Boolean& abortProcessing)
The web service's namespace:
[WebService(Namespace = "http://internaltest.temp.us/MyWebService.asmx")]
I did some research and found out that this exception flows because the web service's namespace referenced in the project was different from the server web service's namespace, but I've tried removing web reference and add it again in the project, but the result was still the same.
My situation was similar to the below article:
http://bluebones.net/2003/07/server-did-not-recognize-http-header-soapaction/
From Article:
So basically the web service was moved from http://foo.com/servicename
to http://bar.com/servicename but the “namespace” of the web service
stayed as http://foo.com/servicename because no one changed it.
The problem is:
How to change the namespace of the web reference?
In addition to removing and adding web-reference, you could try regenerating proxies using wsdl.exe as suggested here, with the namespace again. Hope it helps
I also got same exception when calling a webservice. In my client code, I was using wrong the Namespace to refer to the WebService. So, whenever I was refered to the WebService, I used fully qualified names like: Namespace.WebService, which solved the issue for me.
Sharing my experience, because this may help someone out there.
Example to explain the case:
Actual method:
[WebMethod]
public string Bar(){
}
You renamed it to Foo
[WebMethod]
public string Foo(){
}
Wrongly called method:
objectName.Bar();
Correct call:
objectName.Foo();
A name conflict (because of renaming of web method) between actual web method and the called method can cause the issue.
Another shameless way to get the error is that if you are dynamically changing the endpoint url and you put in an asmx address instead of a wcf one and vice versa.
This can happen when the value of the SOAPAction property of the WS is not set (null) or not correct in the request sent. I am using the apache library to connect to the services in my current project, and below you can find my solution/workaround.
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
call = (Call) service.createCall();
call = setUseSOAPAction(true);
Since there is not a setSoapAction method for my apache case, I used their setProperty method and assigned the SOAPAction name to that property manually.
call.setProperty("SOAPAction", "expected SOAPAction value");
call.setSOAPActionURI("expected SOAPAction value");
I could not invoke the service without using those both methods at the same time.
I hope this will help.

See the SOAP request from Proxy class method calls

I'm using .NET 2.0 web services. If I add a reference to a WSDL and make a proxy class method call, what's the easiest way in VS to see the SOAP being sent?
Example, I added the PayPal WSDL Web Service Reference and made a call as so:
PayPalAPIAASoapBinding _client = new PayPalAPIAASoapBinding();
...rest of code and then
SetExpressCheckoutResponseType checkoutResponse = new SetExpressCheckoutResponseType();
checkoutResponse = _client.SetExpressCheckout(request); // makes the call here
I tried setting a debug point on line 2 but not sure how to dive in to see the SOAP. Obviously I could use something like Fiddler but want to just use Intellisense during debugging to drill down to the object that has the request. I would assume client would have it, my instance above but could not find it. Client is an instance of the PayPal Service.
I do see when I drill down into the base class PayPalAPIAASoapBinding that there is a version property but I can't get the value for this:
System.Web.Services.Protocols.SoapProtocolVersion.Default
when I try to paste that into my watch window, the value just shows the word Default not the true value that's sent. So this is why I need to look at the SOAP and so far in that binding object I don't see a property holding it. But it's gotta be somewhere in any requests you make in a web service in .NET, just don't know where to look during debug?
My end goal here is to be able to read the SOAP envelop before it's being sent really using any WSDL reference in VS.
There's no very easy way. See the example in the SoapExtension documentation on MSDN for a way to log the information.
If you were using WCF, you could just turn on logging in the configuration.
The easiest way to see the SOAP messages (regardless of the programming language) is to use a tool like SoapUI or TCPmon which lets you intercept send and received messages.
This is very easy (if the SOAP is not encrypted). Although it is not in VS.
The easiest way is to use the Fiddler. You can let your VS make Soap calls and see the traffic in raw view on the Fiddler. If the Soap calls are made over SSL, there are some extra steps that needs to be taken for Fiddler to trace them.

Categories

Resources