Consume web service dynamically using HttpWebRequest without service reference - c#

The application I work will have to send data to external system. The system system will have a web service (c# or java or php) and I need to consume it. Since there will be as many external system as clients, I need to get the WSDL file, method name and parameters as user input and send the data to the external system.
So, I am trying to invoke a web service dynamically using code available here
I tested few free web services available here
I find the SOAP location, method name and parameters from the the WSDL file and give the same as input.
The following service works as expected
http://soaptest.parasoft.com/calculator.wsdl
Location - http://ws1.parasoft.com/glue/calculator
Method Name - add
Parameter - x,y
But when I tried the same for the another free service by providing the SOAP location, and method name it throws 500 Internal server error.
http://www.predic8.com:8080/crm/CustomerService?wsdl
Location - http://www.predic8.com:8080/crm/CustomerService
Method Name - getAll
I confirmed these inputs are correct by testing the above wsdl in soapUI. The same location is used in soapUI request window.
I am not sure why it throws error. Please help me understand it.
Also please let me know if it is fine to get the service location from WSDL file and use the HttpWebRequest to get the response. I am afraid whether this method of invoking the web service will work irrespective the technology used to implement the web service.
EDIT:
The problem seems to with the SOAP envelope.
For http://soaptest.parasoft.com/calculator.wsdl even if we ignore xmlns:cal="http://www.parasoft.com/wsdl/calculator/, it gets executed successfully.
But for http://www.predic8.com:8080/crm/CustomerService?wsdl , if I ignore xmlns:ns="http://predic8.com/wsdl/crm/CRMService/1/, it throws internal server error.
Please share how I can be generic here

The problem appears to be with request data that you are using. The request is failing validation, so is the error.
If you import the provided wsdl, and validate create request, it is clear what the problem is.
There is an element id under Person and Customer and data must follow certain patter which is defined under the schema ../common/1
Here is the schema reference, which has simpleType restriction:
<xsd:simpleType name="IdentifierType">
<xsd:annotation>
<xsd:documentation>Identifier for business objects.</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:string">
<xsd:pattern value="[A-Z]{2}-\d{5}"/>
</xsd:restriction>
</xsd:simpleType>
So, id value should Something like AA-12345 i.e., two Capital letter, hyphen(-), and followed by 5 digits.
Change your request as per above pattern, and you should be good.
Hope this is helpful.

Related

Supplant a BizTalk WCF service

I have a WCF service based on BizTalk, I'm not sure how it was deployed or generated but as far as I know it was made using the BizTalk wizard for publishing WCF services. The problem is the BizTalk server installation was removed and now the service still here but it doesn't work, when i invoke the URL the service responses an exception: The BizTalk receive location may be disabled. I need to generate a WCF service in order to replace that service. I have one example request and response and the folder with the service, with a lot of stuff, XML, definitions, etc but there are no DLLs. The SVC markup has a reference to a BizTalk logic.
<%# ServiceHost Language="c#" Factory="Microsoft.BizTalk.Adapter.Wcf.Runtime.WSHttpWebServiceHostFactory, Microsoft.BizTalk.Adapter.Wcf.Runtime, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>
So here goes my question, does anybody know how to generate a service based on request or response to supplant the service.
If you only have the request and response xml then it's a bit tricky. Even if you manage to recreate the service there is no guarantee that existing service consumers will be able to continue to call the service without any change. However, if you want to have a go, this rough guide will help:
Extract the operation signature from the soap request and response
This should be simple. Just look at the part of the request xml which defines the SOAP body. As an example:
<soap:Body xmlns:m="http://www.bookshop.com/prices">
<m:GetBookPrice>
<param1 xsi:type="xs:string">Metro 2033</param1>
</m:GetBookPrice>
</soap:Body>
This shows that the operation name was called GetBookPrice, and that it takes a string as an argument. Now look at the soap body for the response, for example:
<soap:Body xmlns:m="http://www.bookshop.com/prices">
<m:GetBookPriceResponse>
<return xsi:type="xs:decimal">5.99</return>
</m:GetBookPriceResponse>
</soap:Body>
This tells us that the return type of the operation was decimal:
public decimal GetBookPrice(string bookName);
So now you can recreate the service operation in a vanilla WCF service.
It's possible that the service definition included complex types rather than primitives, in which case you need to infer the types from the request/response xml. If the types are too large, you can try to automatically infer them by:
Infer XSD from XML - you'll need to extract just the request and response types from the request/response files, then run them through xsd.exe, which will try to generate the XSD schemas for your request/response types.
Infer CS from XSD - once you have the XSD files, again use xsd.exe to infer the classes for these files. You can then annotate these classes with the DataContract and DataMember attributes and then you can use them in your service definition.
In conclusion, it's not a task I envy you for - even if you manage to faithfully reconstruct the service and type definitions, you may still find that existing clients cannot call the service based on having missed some optional data which was not present in the request/response files you have.
If you create a client for the service in a blank project using Visual Studio (References > "Add Service Reference") you will get the interface that you need to implement (as well as POCOs for all the parameters).
Then create a new WCF project and use that interface and those classes as your contract.
This way you will honour the existing schema without having to manually interpret it.
Look for WcfServiceDescription.xml file in your service folder, its under \App_Data\Temp folder of your service physical folder (you can check IIS virtual directory where its pointing to find the physical path).
Use this file to publish the service again. Based on the definition in it, make sure, you deploy required assemblies to GAC (e.g. schema or orchestration assemblies) before publishing the service again.
Then you can use BtsWcfServicePublishing.exe tool which you can download from http://www.microsoft.com/en-us/download/details.aspx?id=21973 from command prompt. On this exe pass the WcfServiceDescription.xml file along with its full path
In the end, I used an ashx handler for procesing the request (cambined with the other responses were very helpfull) xml-> generate xsd -> parse and read request. The only problem is the .ashx termination.

Server returned an invalid soap fault when calling operation from class library

I am using Visual Studio 2012. I have a ASP.NET MVC 4 web app that references a class library. This class library has a service reference. The service reference I added by inserting the URL to the .wsdl file.
I have set up everything correctly. When I do a call to one of the operations then I get an error:
Server returned an invalid SOAP Fault. Please see InnerException for more details.
Then when I view the inner exception:
The data at the root level is invalid. Line 16, position 17.
I am doing everything right, I just don't know why I get this error when I do a call to one of the operations. Where do I see what is returned? I have no control over this service, I am just consuming it.
Run fiddler while making the request. http://fiddler2.com/
This will allow you to see what is actually being sent and what is actually being returned

Web API to insert records

I am working on Taleo web API. I have an XML file with several records that I will have to insert into the Taleo system using its web API.
I have got the Taleo API guide from http://tbe.taleo.net/products/TBE_API_Guide.pdf.
For the first time, I am working on web API so I don't know where to start. Although the guide shows some examples using SOAP, I don't know how to make this request and retrieve the response using C# or VB.NET. I googled it but didn't get much information about it. If you share your ideas, I would really appreciate it.
From the PDF, it appears the WSDL for the service is at: http://tbe.taleo.net/wsdl/WebAPI.wsdl. In your C#/VB project, use the "Add Service Reference" option on the context menu and supply that URI to the WSDL. That will generate a proxy and many ancillary classes on which you can call whatever methods you need - the SOAP details are under the covers. You'll instantiate an instance of WebAPIClient and should see all the relevant methods there.
For example, in C# after creating a new Service Reference with (uninspired) namespace name of ServiceReference2, I can code the following (though I have no idea what it does!):
var x = new ServiceReference2.WebAPIClient(); // I suspect there's an overload expecting credentials
ServiceReference2.AccountBean y = x.getAccountById("bar", 0);
Exception handling is left to the reader :)

Problem regarding consuming php web service in c# Desktop application

I am developing a c# desktop application and using a webservies which is developed in a php application when i try to consume that application. I just add web REference of that web service and try to access throught the following code
WebReference.TestWSDL pdl = new testingApp.WebReference.TestWSDL();
string copy = pdl.verify("testing");
it throws the error when i try to call the method verify. the error is
Possible SOAP version mismatch: Envelope namespace http://schemas.xmlsoap.org/wsdl/ was unexpected. Expecting http://schemas.xmlsoap.org/soap/envelope/.
and the web service link was like
http://171.139.101.12/code/index.php/webservice/wsdl
The error you are encountering is informing you that when you invoke the webservice, you are being given the WSDL (Web Service Definition Language) for the service - this is the metadata that describes the service functions, but cannot actually be used to invoke the service. Usually, you access the WSDL by appending either "?wsdl" or "wsdl" to the service URI.
There are two elements to the webservice you are attempting to consume.
The actual service exists at:
http://171.139.101.12/code/index.php/webservice
The metadata describing it, which Visual Studio via wsdl.exe used to generate a proxy, resides here:
http://171.139.101.12/code/index.php/webservice/wsdl
You need to edit the properties of the Web Reference and update the address appropriately. Alternatively, you can alter the properties of the pdl variable, and change the endpoint in code.

Server did not recognize the value of HTTP Header SOAPAction

[SoapRpcMethod(Action = "http://cyberindigo/TempWebService/InsertXML",
RequestNamespace = "http://cyberindigo/TempWebService/Request",
RequestElementName = "InsertXMLRequest",
ResponseNamespace = "http://cyberindigo/TempWebService/Response",
ResponseElementName = "InsertXMLResponse",
Use = System.Web.Services.Description.SoapBindingUse.Literal)]
[WebMethod]
public string InsertXML(string Jobs)
{
return "Hi";
}
The Problem when I am accessing it using XMLHttpRequest it gives following error
Server did not recognize the value of HTTP Header SOAPAction: http://Cyberindigo/TempWebService/InsertXML
The source of the next part of this post is:
http://bluebones.net/2003/07/server-did-not-recognize-http-header-soapaction/
(since the OP didn't want to give attribution, and thanks to Peter)
Please note that bakert is the original author of the text, not the OP.
Seeing as nowhere on the internet can I find an explanation of this error I thought I’d share the fruits of my long search for this bug.
It means (at least in my case) that you are accessing a web service with SOAP and passing a SOAPAction parameter in the HTTP request that does not match what the service is expecting.
I got in a pickle because we moved a web service from one server to another and thus I changed the “namespace” (don’t get confused between web service namespaces and .net namespaces) in the calling C# file to match the new server. But the server doesn’t care about the actual web reality of http://yournamespace.com/blah it only cares that you send it what you have said you are expecting on the server. It doesn’t care if there’s actually anything there or not.
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.
And that only took about 4 hours to work out!
If you’re having a similar problem but can’t work what I’m saying here, feel free to mail me on bakert+web#gmail.com – I wouldn’t wish my four hours on anyone!
While calling the .asmx / wcf web service please take care of below points:
The namespace is case sensitive,the SOAP request MUST be sent with the same namespace with which the WebService is declared.
e.g. For the WebService declared as below
[WebService(Namespace = "http://MyDomain.com/TestService")]
public class FooClass : System.Web.Services.WebService
{
[WebMethod]
public bool Foo( string name)
{
......
}
}
The SOAP request must maintain the same case for namespace while calling.Sometime we overlook the case sensitivity.
<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>
<Foo xmlns="http://MyDomain.com/TestService">
<name>string</name>
</Foo>
</soap:Body>
</soap:Envelope>
The namespace need not be same as hosted url of the service.The namespace can be any string.
e.g. Above service may be hosted at http://84.23.9.65/MyTestService , but still while invoking the Web Service from client the namespace should be the same which the serice class is having i.e.http://MyDomain.com/TestService
I agree with Sam in that the SOAP definition does not match what is expected. Here is just ONE solution it could be, I had to manually figure this error for myself:
My problem was that I changed the name of the web method but did not change the "MessageName" in the metadata tag.
[WebMethod(MessageName = "foo")]
public string bar()
{
}
It should be
[WebMethod(MessageName = "foo")]
public string foo()
{
}
hope that helps someone
I've decided to post my own answer here because I've lost a few hours on this and I think that, although the accepted answer is very good and pointed me in the right direction (yes, it got a voteup), it was not detailed enough to explain what was wrong with my application, at least in my case.
I'm running a BPEL module in OpenESB 2.2 and the Test Case of my Composite Application was failing with the following error:
Caused by: System.Web.Services.Protocols.SoapException: Server did not recognize the value of HTTP Header SOAPAction: .
After doing some research I've noticed that the external WSDL has all the clues we need to fix this problem, e.g., I'm using the following web service to validate a credit card number through a orchestration of Web Services:
http://www.webservicex.net/CreditCard.asmx?WSDL
If you check the <wsdl:operation elements you will see that it clearly states the soapAction for that operation:
<wsdl:binding name="CCCheckerSoap" type="tns:CCCheckerSoap">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="ValidateCardNumber">
<soap:operation soapAction="http://www.webservicex.net/ValidateCardNumber" style="document"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
...
But, once you create the Composite Application and build the project with the BPEL that invokes this external WSDL service, for some reason (bug?), the XML of the Composite Application Service Assembly (CASA) binding is generated with an empty soapAction parameter:
<binding name="casaBinding1" type="ns:CCCheckerSoap">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="ValidateCardNumber">
<soap:operation soapAction="" style="document"/>
<input>
<soap:body use="literal"/>
</input>
Once you copy the proper soapAction (http://www.webservicex.net/ValidateCardNumber) into this parameter, the application's Test Case will correctly and return the expected Soap response.
<soap:operation soapAction="http://www.webservicex.net/ValidateCardNumber" style="document"/>
So, it's a more specific solution that I decided to document based on the information found in this blog post: http://bluebones.net/2003/07/server-did-not-recognize-http-header-soapaction/.
It means (at least in my case) that you are accessing a web service
with SOAP and passing a SOAPAction parameter in the HTTP request
that does not match what the service is expecting.
I had same problem, it fixed after some checking:
<< Target WebService Exists but called method's not eXXXists. >>
my local service contain methods but target server(connecting server)
does not contain specified called method.
Check your program scenario again...
Just to help someone on this problem, after an afternoon of debug, the problem was that the web service was developed with framework 4.5 and the call from android must be done with SoapEnvelope.VER12 and not with SoapEnvelope.VER11
I had similar issue. To debug the problem, I've run Wireshark and capture request generated by my code. Then I used XML Spy trial to create a SOAP request (assuming you have WSDL) and compared those two.
This should give you a hint what goes wrong.
My error fixed by answer Mr. John Saunders : http://forums.asp.net/post/2906487.aspx
in short: difference between Namespace of ws
.asmx.cs with ws
.wsdl files.
1) [WebService(Namespace = "http://tempuri.org/")]
later web service namespace changed to :
2) [WebService(Namespace = "http://newvalue.com/")]
so we referenced (1) in application and web service is (2) now.
make them equal to fix your problem.
I had this same problem, but the solution for me was that I was pointing to the wrong web service. I had updated the web reference correctly. But we store the URl for the service in an encrypted file, and I didn't update the file with the correct service encrypted.
But all these suggestions really helped me to realize where to go for debugging.
Thanks!
I had the same problem after changing the namespace from "tempuri" in my Web Service.
You have to update your Service Reference in the project that is consuming the above service, so it can get the latest SOAP definitions.
Or at least that worked for me. :)
We had renamed some of our webservice project namespaces and forgot to update the website httphandlers config section with the namespace of the renamed projects.
I had the same error, i was able to resolve it by removing the 'Web Reference' and adding a 'Service Reference' instead
I got this error when I tried to call a method which did not exist. It only existed in a newer version of our webservice.
I had to sort out capitalisation of my service reference, delete the references and re add them to fix this. I am not sure if any of these steps are superstitious, but the problem went away.
I had a similar problem with the same error message:
System.Web.Services.Protocols.SoapException: Server did not recognize the value of HTTP Header SOAPAction:
We utilize dynamic URL's in our web service calls. We have a central configuration server that manages the location of all web service calls so that our code can run in DEV, test or live without recompiling. The URL for a specific web service call for the test environment was incorrect in our configuration server. The web service call was being sent to the wrong server and the wrong web service.
So this error can simply be the result of the web service request not matching the web service being called.
It took running fiddler on the Web App server to see that the actual call was to the incorrect web service.
the problem is in the System.Web.Services.Protocols.SoapDocumentMethodAttribute
in the service. Please check it. it may changed.
I found out that my web reference was out of date and the code was calling a removed web service.

Categories