Posting soap xml to a web service directly in c#/ asp.net - c#

I am trying to post XML to a web service directly rather than using VS's "add a web reference..." functionality. There is a good reason for this. To get proper test XML I logged what was generated using the standard web reference. I used what I found in this question Capturing SOAP requests to an ASP.NET ASMX web service
The web service was just what is generated when you create a new web service in visual studio, nothing fancy.
To try and pass the XML itself, I borrowed the code from this question Client to send SOAP request and received response
Unfortunately, when I call it, I get "The remote server returned an error: (500) Internal Server Error." 100% if I call the same web method like this
WebService1 ws = new WebService1();
String output = ws.HelloWorld();
then everything works great so I know the service is working well as deployed. I would appreciate so greatly some advice as to what I am doing wrong =)
Here is my code:
var _url = "http://localhost/simulator/webservice1.asmx";
var _action = "http://localhost/simulator/webservice1.asmx?op=HelloWorld";
String soapMessage = soapMessage = #"<?xml version='1.0' encoding='utf-8'?><soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema'><soap:Body><HelloWorld xmlns='http://tempuri.org/' /></soap:Body></soap:Envelope>";
XmlDocument soapEnvelop = new XmlDocument();
soapEnvelop.LoadXml(soapMessage);
XmlDocument soapEnvelopeXml = soapEnvelop;
HttpWebRequest webRequest = CreateWebRequest(_url, _action);
InsertSoapEnvelopeIntoWebRequest(soapEnvelopeXml, webRequest);
// begin async call to web request.
IAsyncResult asyncResult = webRequest.BeginGetResponse(null, null);
// suspend this thread until call is complete. You might want to
// do something usefull here like update your UI.
asyncResult.AsyncWaitHandle.WaitOne();
// get the response from the completed web request.
string soapResult;
using (WebResponse webResponse = webRequest.EndGetResponse(asyncResult))
using (StreamReader rd = new StreamReader(webResponse.GetResponseStream()))
{
soapResult = rd.ReadToEnd();
}

Related

Using Azure Hybrid Connection to connect to internal Web API

Very new to Azure, and I have an internal web API on an internal address http://internal-server:182/api/policies. I have set up a Hybrid Connection internal-service.servicebus.windows.net. This is connected and working.
My struggle is getting the C# code working to connect and retrieve the data. After a number of days, I have reviewed various articles, videos etc and all seem more advanced than what I am trying to do, which is just call the Web API and read the JSON. I have tried to simplify the code but receive the error:
401 MalformedToken: Invalid authorization header: The request is missing WRAP authorization credentials.
At present I have the followed code:
using (var client = new HttpClient())
{
var url = "http://internal-service.servicebus.windows.net";
var tp = TokenProvider.CreateSharedAccessSignatureTokenProvider("RootManageSharedAccessKey", "<key goes here>");
var token = tp.GetWebTokenAsync(url, string.Empty, true, TimeSpan.FromHours(1))
.GetAwaiter()
.GetResult();
client.BaseAddress = new Uri(url);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("ServiceBusAuthorization", token);
var response = client.GetAsync("/api/policies").Result;
string res = "";
using (HttpContent content = response.Content)
{
// ... Read the string.
Task<string> result = content.ReadAsStringAsync();
res = result.Result;
Label1.Text = res;
}
}
Any help or direction would be much appreciated? Once this code is working the Web App will be published as an Azure Web App.
Seems that your are not sending the right header.
First suggestion: intercept the call with a proxy like fiddler, to do that add a proxy config to your call to localhost port 8888, after this you can try some request and see the raw http you are sending to the server, you can also modify it until it works, once you have this modify your code until it send the same raw http.
You can find more info about this here:
Microsoft Azure CreateQueue using Simple REST Client
https://github.com/ytechie/event-hubs-sas-generator

Getting data from MailChimp using SilverLight

I have created my own silverlight API to get/set data from/to MailChimp.
It was working fine, but today I am getting an error. Example code is :
string MailChimpURL = "https://us2.api.mailchimp.com/1.3/?method=lists&apikey=my_api_key-us2";
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(new Uri(MailChimpURL));
request.BeginGetResponse(new AsyncCallback(ReadCallback), request);
private void ReadCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
using (StreamReader streamReader1 = new StreamReader(response.GetResponseStream()))
{
string resultString = streamReader1.ReadToEnd();
}
}
This works fine with http but gives error when using https.
The error which https is for yesterday. Months back it was working fine for both http and https. Now its only working for http.
Is this a problem in my code or this from MailChimp.
I don't think you are showing us the true exception. The exception you are seeing when inspecting the AsyncWaitHandle property you will always get when debugging because Siverlight does not support that property.
You really need to place some error handling in your ReadCallBack so you can report back to the UI in a friendly way anything that may have gone wrong.

How can I make a SOAP call in C# with an old WSDL+XSD and current Web Service location?

My question is similar to this one: need to call soap ws without wsdl except that my application does not use Spring so the answer was not helpful.
Here's what I have:
A web service that only accepts SOAP requests
A current endpoint URL for the web service
An outdated wsdl and xsd file
An outdated sample SOAP request file
What I need to do is:
Successfully make a SOAP request using some combination of the above.
I've tried to approach this from two different angles, with no luck so far. My background is familiarity with web services with POST and GETs, but not SOAP. After googling 'C# SOAP', I wrote the following code:
void soap(String xmlfile)
{
Stream outputStream = null;
StreamReader reader = null;
WebResponse response = null;
try
{
string text = System.IO.File.ReadAllText(xmlfile);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://misapi.ercot.com/2007-08/Nodal/eEDS/EWS");
request.PreAuthenticate = true;
X509Certificate ercotCert = X509Certificate.CreateFromCertFile("D:\\Amigo\\WebSite1\\Nodal_Test_Cert.cer");
request.ClientCertificates.Clear();
request.ClientCertificates.Add(ercotCert);
ServicePointManager.ServerCertificateValidationCallback +=
new System.Net.Security.RemoteCertificateValidationCallback(customValidation);
request.Credentials = CredentialCache.DefaultNetworkCredentials;
// I don't actually have a SOAPAction, but have tried adding a fake one just to see
//request.Headers.Add("SOAPAction", "http://www.ercot.com/Nodal/Payload");
request.Method = "POST";
request.ContentType = "text/xml;charset=\"utf-8\"";
request.ContentLength = text.Length;
StreamWriter writer = new StreamWriter(request.GetRequestStream(), System.Text.Encoding.ASCII);
writer.Write(text);
writer.Close();
response = request.GetResponse();
outputStream = response.GetResponseStream();
reader = new StreamReader(outputStream);
Response.Write(reader.ReadToEnd());
}
catch (WebException e)
{
// This is where it ends up, with Status="ProtocolError"
}
catch (System.Web.Services.Protocols.SoapException soapE)
{
// Never gets in here
}
catch (Exception e)
{
// Never gets in here
}
finally
{
if (outputStream != null)
outputStream.Close();
if(reader != null)
reader.Close();
if(response != null)
response.Close();
}
}
private static bool customValidation(object sender, X509Certificate cert, X509Chain chain, System.Net.Security.SslPolicyErrors error)
{
return true;
}
This yields a 500 Internal Server Error. It throws a WebException which contains no other message or inner exception, but the Status is 'ProtocolError'. I have tried other permutations including using XmlDocument and other content types, but none have worked.
The other thing I've tried is using "Add Web Reference" in Visual Studio. Putting in the endpoint URL doesn't work and gives a soap fault. If, instead, I point to the local copy of my outdated wsdl, then it will add the WebReference but won't let me use it due to numerous errors that I cannot correct. My guess is that these errors are due to the wsdl being outdated, things like the namespace not matching or being unable to find things at the URLs included. If I replace those URLs with the current web service endpoint URL, it still does not work.
If anyone could pinpoint a problem in my code, or direct me on how to get the "Add Web Reference" working, I would be greatly greatly appreciated!
Thanks in advance!
SOAP is just the format for the payload that you POST to the service, that's all. There's a defined specification for fields and namespaces and such, and there are different SOAP versions, but there's really not that much to it. (Other than it being remarkably verbose for it's usage, but that's a different topic.)
You need to start with a current WSDL. If you know you're working WSDL is outdated, that means that something the webservice is expecting (required) or could work with (optional) is different from your definition. And the WSDL is your contractual gateway into the webservice. You need to get a current WSDL.
As luck would have it, when I navigate to https://misapi.ercot.com/2007-08/Nodal/eEDS/EWS/?WSDL (which I derived by appending "?WSDL" to the end of the url), after skipping past the certificate error, bingo -- there's the WSDL used by the service. You can either (a) save it locally, or (b) reference it directly from Visual Studio in building a web service client. Because of the cert error, I would recommend saving it locally and building from there.
This should get you started.

How do I test connectivity to an unknown web service in C#?

I'm busy writing a class that monitors the status of RAS connections. I need to test to make sure that the connection is not only connected, but also that it can communicate with my web service. Since this class will be used in many future projects, I'd like a way to test the connection to the webservice without knowing anything about it.
I was thinking of passing the URL to the class so that it at least knows where to find it. Pinging the server is not a sufficient test. It is possible for the server to be available, but the service to be offline.
How can I effectively test that I'm able to get a response from the web service?
You could try the following which tests the web site's existence:
public static bool ServiceExists(
string url,
bool throwExceptions,
out string errorMessage)
{
try
{
errorMessage = string.Empty;
// try accessing the web service directly via it's URL
HttpWebRequest request =
WebRequest.Create(url) as HttpWebRequest;
request.Timeout = 30000;
using (HttpWebResponse response =
request.GetResponse() as HttpWebResponse)
{
if (response.StatusCode != HttpStatusCode.OK)
throw new Exception("Error locating web service");
}
// try getting the WSDL?
// asmx lets you put "?wsdl" to make sure the URL is a web service
// could parse and validate WSDL here
}
catch (WebException ex)
{
// decompose 400- codes here if you like
errorMessage =
string.Format("Error testing connection to web service at" +
" \"{0}\":\r\n{1}", url, ex);
Trace.TraceError(errorMessage);
if (throwExceptions)
throw new Exception(errorMessage, ex);
}
catch (Exception ex)
{
errorMessage =
string.Format("Error testing connection to web service at " +
"\"{0}\":\r\n{1}", url, ex);
Trace.TraceError(errorMessage);
if (throwExceptions)
throw new Exception(errorMessage, ex);
return false;
}
return true;
}
You are right that pinging the server isn't sufficient. The server can be up, but the web service unavailable due to a number of reasons.
To monitor our web service connections, I created a IMonitoredService interface that has a method CheckService(). The wrapper class for each web service implements this method to call an innocuous method on the web service and reports if the service is up or not. This allows any number of services to be monitored with out the code responsible for the monitoring knowing the details of the service.
If you know a bit about what the web service will return from accessing the URL directly, you could try just using the URL. For example, Microsoft's asmx file returns a summary of the web service. Other implementations may behave differently though.
The tip: create a interface/baseclass with method "InvokeWithSomeParameters". The meaning of "SomeParameters" should be a "parameters which 100% does not affect any important state".
I think, there are 2 cases:
Simple webservice, which does not affect any data on server. For example: GetCurrentTime(). This web service can be called without parameters.
Complex webservice, which can affect some daty on server. For example: Enlist pending tasks. You fill-up parameter with values which 100% throws a exception (resp. does not change affect pending tasks), if you got some exception like "ArgumentException", you know the service is alive.
I don't think, this is most clear solution, but it should works.
How about opening a TCP/IP connection to the port used by the webservice? If the connection works, the RAS connection, the rest of the network and the host are all working. The webservice is almost certainly running too.
If it is a Microsoft SOAP or WCF service and service discovery is allowed, you can request the web page serviceurl + "?disco" for discovery. If what is returned is a valid XML document , you know the service is alive and well. A non-Microsoft SOAP service that does not allow ?disco will probably return valid XML too.
Sample code:
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(URL + "?disco");
request.ClientCertificates.Add(
new X509Certificate2(#"c:\mycertpath\mycert.pfx", "<privatekeypassword>")); // If server requires client certificate
request.Timeout = 300000; // 5 minutes
using (WebResponse response = request.GetResponse())
using (Stream stream = response.GetResponseStream())
using (StreamReader sr = new StreamReader(stream, Encoding.UTF8))
{
XmlDocument xd = new XmlDocument();
xd.LoadXml(sr.ReadToEnd());
return xd.DocumentElement.ChildNodes.Count > 0;
}
If the web server is present, but the service does not exist, an exception will be raised quickly for the 404 error. The fairly long time-out in the example is to allow a slow WCF service to restart after a long period of inactivity or after iisreset. If the client needs to be responsive, you could poll with a shorter timeout until the service is available.

Query Web Service for list of Messages?

Is there a straightforward way to query a web service to see which messages it supports? The C# .NET application I'm working on needs to be able to handle an older version of the web service, which does not implement the message I'm trying to send. The web service does not expose a version number, so Plan B is to see if the message is defined.
I'm assuming I can just make an HTTP request for the WSDL and parse it, but before I go down that path, I want to make sure there's not a simpler approach.
Update:
I've decided to get the WSDL and get messages directly. Here's the rough draft for getting all the messages:
HttpWebRequest webRequest = (HttpWebRequest) WebRequest.Create( "http://your/web/service/here.asmx?WSDL" );
webRequest.PreAuthenticate = // details elided
webRequest.Credentials = // details elided
webRequest.Timeout = // details elided
HttpWebResponse webResponse = (HttpWebResponse) webRequest.GetResponse();
XPathDocument xpathDocument = new XPathDocument( webResponse.GetResponseStream() );
XPathNavigator xpathNavigator = xpathDocument.CreateNavigator();
XmlNamespaceManager xmlNamespaceManager = new XmlNamespaceManager( new NameTable() );
xmlNamespaceManager.AddNamespace( "wsdl", "http://schemas.xmlsoap.org/wsdl/" );
foreach( XPathNavigator node in xpathNavigator.Select( "//wsdl:message/#name", xmlNamespaceManager ) )
{
string messageName = node.Value;
}
Parsing the WSDL is probably the simplest way to do this. Using WCF, it's also possible to download the WSDL at runtime, essentially run svcutil on it through code, and end up with a dynamically generated proxy that you can check the structure of. See https://learn.microsoft.com/en-us/archive/blogs/vipulmodi/dynamic-programming-with-wcf for an example of a runtime-generated proxy.
I'm pretty sure WSDL is the way to do this.

Categories

Resources