I have to connect to a third party web service that provides no wsdl nor asmx. The url of the service is just http://server/service.soap
I have read this article ab
In my opinion, there is no excuse for a SOAP web service to not supply a WSDL. It need not be dynamically generated by the service; it need not be available over the Internet. But there must be a WSDL, even if they have to send it to you on a floppy disk thumb drive!
If you have any ability to complain to the providers of this service, then I urge you to do so. If you have the ability to push back, then do so. Ideally, switch service providers, and tell these people it's because they didn't provide a WSDL. At the very least, find out why they don't think it's important.
Hmm, tricky one here but not impossible but I'll do my best to explian it.
What you'll need to do is
I will try to add more as and when I think of it but that should be enough to get you started.
I have created the following helper method to call WebService manually without any reference:
public static HttpStatusCode CallWebService(string webWebServiceUrl,
string webServiceNamespace,
string methodName,
Dictionary<string, string> parameters,
out string responseText)
{
const string soapTemplate =
@"<?xml version=""1.0"" encoding=""utf-8""?>
<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""
xmlns:xsd=""http://www.w3.org/2001/XMLSchema""
xmlns:soap=""http://www.w3.org/2003/05/soap-envelope"">
<soap:Body>
<{0} xmlns=""{1}"">
{2} </{0}>
</soap:Body>
</soap:Envelope>";
var req = (HttpWebRequest)WebRequest.Create(webWebServiceUrl);
req.ContentType = "application/soap+xml;";
req.Method = "POST";
string parametersText;
if (parameters != null && parameters.Count > 0)
{
var sb = new StringBuilder();
foreach (var oneParameter in parameters)
sb.AppendFormat(" <{0}>{1}</{0}>\r\n", oneParameter.Key, oneParameter.Value);
parametersText = sb.ToString();
}
else
{
parametersText = "";
}
string soapText = string.Format(soapTemplate, methodName, webServiceNamespace, parametersText);
using (Stream stm = req.GetRequestStream())
{
using (var stmw = new StreamWriter(stm))
{
stmw.Write(soapText);
}
}
var responseHttpStatusCode = HttpStatusCode.Unused;
responseText = null;
using (var response = (HttpWebResponse)req.GetResponse())
{
responseHttpStatusCode = response.StatusCode;
if (responseHttpStatusCode == HttpStatusCode.OK)
{
int contentLength = (int)response.ContentLength;
if (contentLength > 0)
{
int readBytes = 0;
int bytesToRead = contentLength;
byte[] resultBytes = new byte[contentLength];
using (var responseStream = response.GetResponseStream())
{
while (bytesToRead > 0)
{
// Read may return anything from 0 to 10.
int actualBytesRead = responseStream.Read(resultBytes, readBytes, bytesToRead);
// The end of the file is reached.
if (actualBytesRead == 0)
break;
readBytes += actualBytesRead;
bytesToRead -= actualBytesRead;
}
responseText = Encoding.UTF8.GetString(resultBytes);
//responseText = Encoding.ASCII.GetString(resultBytes);
}
}
}
}
// standard responseText:
//<?xml version="1.0" encoding="utf-8"?>
//<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
// <soap:Body>
// <SayHelloResponse xmlns="http://tempuri.org/">
// <SayHelloResult>Hello</SayHelloResult>
// </SayHellorResponse>
// </soap:Body>
//</soap:Envelope>
if (!string.IsNullOrEmpty(responseText))
{
string responseElement = methodName + "Result>";
int pos1 = responseText.IndexOf(responseElement);
if (pos1 >= 0)
{
pos1 += responseElement.Length;
int pos2 = responseText.IndexOf("</", pos1);
if (pos2 > pos1)
responseText = responseText.Substring(pos1, pos2 - pos1);
}
else
{
responseText = ""; // No result
}
}
return responseHttpStatusCode;
}
You can then simply call any web service method with the following code:
var parameters = new Dictionary<string, string>();
parameters.Add("name", "My Name Here");
string responseText;
var responseStatusCode = CallWebService("http://localhost/TestWebService.asmx",
"http://tempuri.org/",
"SayHello",
parameters,
out responseText);
If you're lucky you could still get the wsdl. Some web service frameworks allow you to retrieve a dynamically generated WSDL.
Web Services written with Axis1.x allow you to retrieve a dynamically generated WSDL file by browsing to the URL.
Just browse to
http://server/service.soap/?wsdl
I don't know if this is possible with other frameworks though.
Well, I finally got this to work, so I'll write here the code I'm using. (Remember, .Net 2.0, and no wsdl to get from web service).
First, we create an HttpWebRequest:
public static HttpWebRequest CreateWebRequest(string url)
{
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
webRequest.Headers.Add("SOAP:Action");
webRequest.ContentType = "text/xml;charset=\"utf-8\"";
webRequest.Accept = "text/xml";
webRequest.Method = "POST";
return webRequest;
}
Next, we make a call to the webservice, passing along all values needed. As I'm reading the soap envelope from a xml document, I'll handle the data as a StringDictionary. Should be a better way to do this, but I'll think about this later:
public static XmlDocument ServiceCall(string url, int service, StringDictionary data)
{
HttpWebRequest request = CreateWebRequest(url);
XmlDocument soapEnvelopeXml = GetSoapXml(service, data);
using (Stream stream = request.GetRequestStream())
{
soapEnvelopeXml.Save(stream);
}
IAsyncResult asyncResult = request.BeginGetResponse(null, null);
asyncResult.AsyncWaitHandle.WaitOne();
string soapResult;
using (WebResponse webResponse = request.EndGetResponse(asyncResult))
using (StreamReader rd = new StreamReader(webResponse.GetResponseStream()))
{
soapResult = rd.ReadToEnd();
}
File.WriteAllText(HttpContext.Current.Server.MapPath("/servicios/" + DateTime.Now.Ticks.ToString() + "assor_r" + service.ToString() + ".xml"), soapResult);
XmlDocument resp = new XmlDocument();
resp.LoadXml(soapResult);
return resp;
}
So, that's all. If anybody thinks that GetSoapXml must be added to the answer, I'll write it down.