Send XML document over soap - c#

Following is my code:
Method(SendXmlDocument) will take in as parameter an XML document, URL, and the SOAP action and make a request to a web service. I have to use HttpClient class to make the request to the web service.
using System;
using System.Net;
using System.Threading.Tasks;
using System.Xml;
using System.IO;
namespace HttpClientStatus
{
class WebServiceClient
{
public void SendXmlDocument(XmlDocument fi , string URL , string action)
{
XmlDocument soapEnvelopeXml = fi;
HttpWebRequest webRequest = CreateWebRequest(URL, action);
InsertSoapEnvelopeIntoWebRequest(soapEnvelopeXml, webRequest);
IAsyncResult asyncResult = webRequest.BeginGetResponse(null, null);
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();
}
Console.Write(soapResult);
}
}
private static HttpWebRequest CreateWebRequest(string url, string action)
{
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
webRequest.Headers.Add("SOAPAction", action);
webRequest.ContentType = "text/xml;charset=\"utf-8\"";
webRequest.Accept = "text/xml";
webRequest.Method = "POST";
return webRequest;
}
private static void InsertSoapEnvelopeIntoWebRequest(XmlDocument soapEnvelopeXml, HttpWebRequest webRequest)
{
using (Stream stream = webRequest.GetRequestStream())
{
soapEnvelopeXml.Save(stream);
}
}
}
class Program
{
static void Main(string[] args)
{
var _u = "http://xxxxxxxxx/Service1.asmx";
var _a = "http://xxxxxxxxx/Service1.asmx/action";
XmlDocument d = new XmlDocument();
d.Load("C://Users//gmzmdz//Desktop//course.xml");
WebServiceClient ob = new WebServiceClient();
ob.SendXmlDocument(d, _u, _a);
}
}
}
My Question is that following pure xml document will be sent or not. That this method make a request to web service or not. How do I will know about it that request has been made successful? Then, I have to print the response on the console that comes back from the web service.

Related

Client to send SOAP request to web service

I am trying to send SOAP request to my web service and from this question - Client to send SOAP request and received response
I got this piece of code:
using System.Xml;
using System.Net;
using System.IO;
public static void CallWebService()
{
var _url = "http://xxxxxxxxx/Service1.asmx";
var _action = "http://xxxxxxxx/Service1.asmx?op=HelloWorld";
XmlDocument soapEnvelopeXml = CreateSoapEnvelope();
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();
}
Console.Write(soapResult);
}
}
private static HttpWebRequest CreateWebRequest(string url, string action)
{
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
webRequest.Headers.Add("SOAPAction", action);
webRequest.ContentType = "text/xml;charset=\"utf-8\"";
webRequest.Accept = "text/xml";
webRequest.Method = "POST";
return webRequest;
}
private static XmlDocument CreateSoapEnvelope()
{
XmlDocument soapEnvelopeDocument = new XmlDocument();
soapEnvelopeDocument.LoadXml(#"<SOAP-ENV:Envelope xmlns:SOAP-ENV=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:xsi=""http://www.w3.org/1999/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/1999/XMLSchema""><SOAP-ENV:Body><HelloWorld xmlns=""http://tempuri.org/"" SOAP-ENV:encodingStyle=""http://schemas.xmlsoap.org/soap/encoding/""><int1 xsi:type=""xsd:integer"">12</int1><int2 xsi:type=""xsd:integer"">32</int2></HelloWorld></SOAP-ENV:Body></SOAP-ENV:Envelope>");
return soapEnvelopeDocument;
}
private static void InsertSoapEnvelopeIntoWebRequest(XmlDocument soapEnvelopeXml, HttpWebRequest webRequest)
{
using (Stream stream = webRequest.GetRequestStream())
{
soapEnvelopeXml.Save(stream);
}
}
But it doesn't work for me, it says there is no definition for GetRequestStream() and Headers where you add the SOAPAction under HttpWebRequest, can anyone help me solve the problem?
Edit:
The Errors occur on the line
using (Stream stream = webRequest.GetRequestStream())
And it gives the error
Error CS1061 'HttpWebRequest' does not contain a definition for 'GetRequestStream' and no extension method 'GetRequestStream' accepting a first argument of type 'HttpWebRequest' could be found (are you missing a using directive or an assembly reference?)
And another error on the line
webRequest.Headers.Add("SOAPAction", action);
And it gives the error
Error CS1929 'WebHeaderCollection' does not contain a definition for 'Add' and the best extension method overload 'SettersExtensions.Add(IList, BindableProperty, object)' requires a receiver of type 'IList'
Use for adding headers:
webRequest.Headers["HeaderToken"] = "HeaderValue";
And for GetRequestStream use:
using (var stream = await Task.Factory.FromAsync<Stream>(webRequest.BeginGetRequestStream, webRequest.EndGetRequestStream, null))
{
reqBody.Save(stream);
}

Getting the response of Asynchronous http web request using POST method in asp.net core

I am using asp.net core. I am able to get the response from the http webrequest using GET method. To get the response via http webrequest using POST am facing 405 error.(Remote server not found)
Here is my code using GET Method.
public static void Main(string[] args)
{
var task = MakeAsyncRequest("http://localhost:8080/nifi-api/flow/status", "text/html");
Console.ReadLine();
}
public static Task<string> MakeAsyncRequest(string url, string contentType)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.ContentType = contentType;
request.Method = "GET";
request.Proxy = null;
Task<WebResponse> task = Task.Factory.FromAsync(
request.BeginGetResponse,
asyncResult => request.EndGetResponse(asyncResult),
(object)null);
return task.ContinueWith(t => ReadStreamFromResponse(t.Result));
}
private static string ReadStreamFromResponse(WebResponse response)
{
using (Stream responseStream = response.GetResponseStream())
using (StreamReader reader = new StreamReader(responseStream))
{
string results = reader.ReadToEnd();
if (!string.IsNullOrEmpty(results))
{
Data data = new Data();
data = JsonConvert.DeserializeObject<Data>(results);
}
return results;
}
}
Please let me know how to get the response using async POST method in asp.net core. Thanks in advance.
Maybe this way?
HttpClient httpClient = new HttpClient();
var response = await httpClient.PostAsync("http://localhost:8080/nifi-api/flow/status", new StringContent("Json string", Encoding.UTF8, "application/json"));

How to properly make a http web GET request

i am still new on c# and i'm trying to create an application for this page that will tell me when i get a notification (answered, commented, etc..). But for now i'm just trying to make a simple call to the api which will get the user's data.
i'm using Visual studio express 2012 to build the C# application, where (for now) you enter your user id, so the application will make the request with the user id and show the stats of this user id.
here is the code where i'm trying to make the request:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//Request library
using System.Net;
using System.IO;
namespace TestApplication
{
class Connect
{
public string id;
public string type;
protected string api = "https://api.stackexchange.com/2.2/";
protected string options = "?order=desc&sort=name&site=stackoverflow";
public string request()
{
string totalUrl = this.join(id);
return this.HttpGet(totalUrl);
}
protected string join(string s)
{
return api + type + "/" + s + options;
}
protected string get(string url)
{
try
{
string rt;
WebRequest request = WebRequest.Create(url);
WebResponse response = request.GetResponse();
Stream dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
rt = reader.ReadToEnd();
Console.WriteLine(rt);
reader.Close();
response.Close();
return rt;
}
catch(Exception ex)
{
return "Error: " + ex.Message;
}
}
public string HttpGet(string URI)
{
WebClient client = new WebClient();
// Add a user agent header in case the
// requested URI contains a query.
client.Headers.Add("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)");
Stream data = client.OpenRead(URI);
StreamReader reader = new StreamReader(data);
string s = reader.ReadToEnd();
data.Close();
reader.Close();
return s;
}
}
}
the class is an object and its being accessed from the form by just parsing it the user id and make the request.
i have tried many of the examples i have looked on google, but not clue why i am getting on all ways this message "�".
i am new in this kind of algorithm, if anyone can share a book or tutorial that shows how to do this kind of stuff (explaining each step), i would appreciate it
If using .NET 6 or higher, please read the warning at the bottom of this answer.
Servers sometimes compress their responses to save on bandwidth, when this happens, you need to decompress the response before attempting to read it. Fortunately, the .NET framework can do this automatically, however, we have to turn the setting on.
Here's an example of how you could achieve that.
string html = string.Empty;
string url = #"https://api.stackexchange.com/2.2/answers?order=desc&sort=activity&site=stackoverflow";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.AutomaticDecompression = DecompressionMethods.GZip;
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
using (Stream stream = response.GetResponseStream())
using (StreamReader reader = new StreamReader(stream))
{
html = reader.ReadToEnd();
}
Console.WriteLine(html);
GET
public string Get(string uri)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
using(HttpWebResponse response = (HttpWebResponse)request.GetResponse())
using(Stream stream = response.GetResponseStream())
using(StreamReader reader = new StreamReader(stream))
{
return reader.ReadToEnd();
}
}
GET async
public async Task<string> GetAsync(string uri)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
using(HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync())
using(Stream stream = response.GetResponseStream())
using(StreamReader reader = new StreamReader(stream))
{
return await reader.ReadToEndAsync();
}
}
POST
Contains the parameter method in the event you wish to use other HTTP methods such as PUT, DELETE, ETC
public string Post(string uri, string data, string contentType, string method = "POST")
{
byte[] dataBytes = Encoding.UTF8.GetBytes(data);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
request.ContentLength = dataBytes.Length;
request.ContentType = contentType;
request.Method = method;
using(Stream requestBody = request.GetRequestStream())
{
requestBody.Write(dataBytes, 0, dataBytes.Length);
}
using(HttpWebResponse response = (HttpWebResponse)request.GetResponse())
using(Stream stream = response.GetResponseStream())
using(StreamReader reader = new StreamReader(stream))
{
return reader.ReadToEnd();
}
}
POST async
Contains the parameter method in the event you wish to use other HTTP methods such as PUT, DELETE, ETC
public async Task<string> PostAsync(string uri, string data, string contentType, string method = "POST")
{
byte[] dataBytes = Encoding.UTF8.GetBytes(data);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
request.ContentLength = dataBytes.Length;
request.ContentType = contentType;
request.Method = method;
using(Stream requestBody = request.GetRequestStream())
{
await requestBody.WriteAsync(dataBytes, 0, dataBytes.Length);
}
using(HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync())
using(Stream stream = response.GetResponseStream())
using(StreamReader reader = new StreamReader(stream))
{
return await reader.ReadToEndAsync();
}
}
Warning notice: The methods of making a HTTP request outlined within this answer uses the HttpWebRequest class which is deprecated starting from .NET 6 and onwards. It's recommended to use HttpClient instead which this answer by DIG covers for environments that depends on .NET 6+.
Ref: https://learn.microsoft.com/en-us/dotnet/core/compatibility/networking/6.0/webrequest-deprecated
Another way is using 'HttpClient' like this:
using System;
using System.Net;
using System.Net.Http;
namespace Test
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Making API Call...");
using (var client = new HttpClient(new HttpClientHandler { AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate }))
{
client.BaseAddress = new Uri("https://api.stackexchange.com/2.2/");
HttpResponseMessage response = client.GetAsync("answers?order=desc&sort=activity&site=stackoverflow").Result;
response.EnsureSuccessStatusCode();
string result = response.Content.ReadAsStringAsync().Result;
Console.WriteLine("Result: " + result);
}
Console.ReadLine();
}
}
}
Check HttpClient vs HttpWebRequest from stackoverflow and this from other.
Update June 22, 2020:
It's not recommended to use httpclient in a 'using' block as it might cause port exhaustion.
private static HttpClient client = null;
ContructorMethod()
{
if(client == null)
{
HttpClientHandler handler = new HttpClientHandler()
{
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
};
client = new HttpClient(handler);
}
client.BaseAddress = new Uri("https://api.stackexchange.com/2.2/");
HttpResponseMessage response = client.GetAsync("answers?order=desc&sort=activity&site=stackoverflow").Result;
response.EnsureSuccessStatusCode();
string result = response.Content.ReadAsStringAsync().Result;
Console.WriteLine("Result: " + result);
}
If using .Net Core 2.1+, consider using IHttpClientFactory and injecting like this in your startup code.
var timeout = Policy.TimeoutAsync<HttpResponseMessage>(
TimeSpan.FromSeconds(60));
services.AddHttpClient<XApiClient>().ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
{
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
}).AddPolicyHandler(request => timeout);
Simpliest way for my opinion
var web = new WebClient();
var url = $"{hostname}/LoadDataSync?systemID={systemId}";
var responseString = web.DownloadString(url);
OR
var bytes = web.DownloadData(url);
var request = (HttpWebRequest)WebRequest.Create("sendrequesturl");
var response = (HttpWebResponse)request.GetResponse();
string responseString;
using (var stream = response.GetResponseStream())
{
using (var reader = new StreamReader(stream))
{
responseString = reader.ReadToEnd();
}
}
Adding to the responses already given, this is a complete example hitting JSON PlaceHolder site.
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace Publish
{
class Program
{
static async Task Main(string[] args)
{
// Get Reqeust
HttpClient req = new HttpClient();
var content = await req.GetAsync("https://jsonplaceholder.typicode.com/users");
Console.WriteLine(await content.Content.ReadAsStringAsync());
// Post Request
Post p = new Post("Some title", "Some body", "1");
HttpContent payload = new StringContent(JsonConvert.SerializeObject(p));
content = await req.PostAsync("https://jsonplaceholder.typicode.com/posts", payload);
Console.WriteLine("--------------------------");
Console.WriteLine(content.StatusCode);
Console.WriteLine(await content.Content.ReadAsStringAsync());
}
}
public struct Post {
public string Title {get; set;}
public string Body {get;set;}
public string UserID {get; set;}
public Post(string Title, string Body, string UserID){
this.Title = Title;
this.Body = Body;
this.UserID = UserID;
}
}
}

Calling Soap web service over HTTP giving exception "Connection close"

I am calling third party Web service over HTTP but it is failing to connect in WPF application/Console Application. Exception is connection close. Wondering why it is closed though same SOAP message works in SOAP UI. Can I give Action with URN as I copyed from SOAP UI. Please suggest what is wrong. Since it is not using browser so cros domain problem should not be.
My C# code is as follows.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Xml;
namespace CTWpfApp
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
CallWebService();
}
public static void CallWebService()
{
var _url = "https://myService.com/webservices/ct/services/4.1";
var _action = "urn:provider/interface/ctservices/getCPNInstances";
XmlDocument soapEnvelopeXml = CreateSoapEnvelope();
HttpWebRequest webRequest = CreateWebRequest(_url, _action);
InsertSoapEnvelopeIntoWebRequest(soapEnvelopeXml, webRequest);
// Start the asynchronous operation to get the response
webRequest.BeginGetResponse(new AsyncCallback(GetResponseCallback), webRequest);
}
private static void GetResponseCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
// End the operation /* I'm getting the exception Connection Close."*/
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
Stream streamResponse = response.GetResponseStream();
StreamReader streamRead = new StreamReader(streamResponse);
string responseString = streamRead.ReadToEnd();
Console.WriteLine(responseString);
// Close the stream object
streamResponse.Close();
streamRead.Close();
// Release the HttpWebResponse
response.Close();
}
private static HttpWebRequest CreateWebRequest(string url, string action)
{
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
webRequest.Headers.Add("SOAPAction", action);
webRequest.ContentType = "text/xml;charset=\"utf-8\"";
webRequest.Accept = "text/xml";
webRequest.Method = "POST";
webRequest.KeepAlive = false;
webRequest.Timeout = 300000;
return webRequest;
}
private static XmlDocument CreateSoapEnvelope()
{
XmlDocument soapEnvelop = new XmlDocument();
soapEnvelop.LoadXml(#"<SOAP-ENV:Envelope xmlns:SOAP-ENV=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:ns1=""urn:dictionary:com.ct.webservices""><SOAP-ENV:Header xmlns:wsse=""http://docs.myses.org/wss/2004/01/200401-wss-wssecurity-secext-1.0.xsd""><wsse:Security SOAP-ENV:mustUnderstand=""1""><wsse:UsernameToken><wsse:Username>fiwjiueji</wsse:Username><wsse:Password Type=""http://docs.myses.org/wss/2004/01/200401-wss-username-token-profile-1.0#PasswordText"">tjrrfrsi</wsse:Password></wsse:UsernameToken></wsse:Security></SOAP-ENV:Header><SOAP-ENV:Body><ns1:getCPNInstances></ns1:getCPNInstances></SOAP-ENV:Body></SOAP-ENV:Envelope>");
return soapEnvelop;
}
private static void InsertSoapEnvelopeIntoWebRequest(XmlDocument soapEnvelopeXml, HttpWebRequest webRequest)
{
using (Stream stream = webRequest.GetRequestStream())
{
soapEnvelopeXml.Save(stream);
}
}
}
}
Take out the webRequest.KeepAlive = false in the CreateWebRequest method.
When using HTTP/1.1, Keep-Alive is on by default. Setting KeepAlive to false may result in sending a Connection: Close header to the server. -From http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.keepalive.aspx

Client to send SOAP request and receive response

Trying to create a C# client (will be developed as a Windows service) that sends SOAP requests to a web service (and gets the results).
From this question I saw this code:
protected virtual WebRequest CreateRequest(ISoapMessage soapMessage)
{
var wr = WebRequest.Create(soapMessage.Uri);
wr.ContentType = "text/xml;charset=utf-8";
wr.ContentLength = soapMessage.ContentXml.Length;
wr.Headers.Add("SOAPAction", soapMessage.SoapAction);
wr.Credentials = soapMessage.Credentials;
wr.Method = "POST";
wr.GetRequestStream().Write(Encoding.UTF8.GetBytes(soapMessage.ContentXml), 0, soapMessage.ContentXml.Length);
return wr;
}
public interface ISoapMessage
{
string Uri { get; }
string ContentXml { get; }
string SoapAction { get; }
ICredentials Credentials { get; }
}
Looks nice, anyone knows how to use it and if it is the best practice?
I normally use another way to do the same
using System.Xml;
using System.Net;
using System.IO;
public static void CallWebService()
{
var _url = "http://xxxxxxxxx/Service1.asmx";
var _action = "http://xxxxxxxx/Service1.asmx?op=HelloWorld";
XmlDocument soapEnvelopeXml = CreateSoapEnvelope();
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();
}
Console.Write(soapResult);
}
}
private static HttpWebRequest CreateWebRequest(string url, string action)
{
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
webRequest.Headers.Add("SOAPAction", action);
webRequest.ContentType = "text/xml;charset=\"utf-8\"";
webRequest.Accept = "text/xml";
webRequest.Method = "POST";
return webRequest;
}
private static XmlDocument CreateSoapEnvelope()
{
XmlDocument soapEnvelopeDocument = new XmlDocument();
soapEnvelopeDocument.LoadXml(
#"<SOAP-ENV:Envelope xmlns:SOAP-ENV=""http://schemas.xmlsoap.org/soap/envelope/""
xmlns:xsi=""http://www.w3.org/1999/XMLSchema-instance""
xmlns:xsd=""http://www.w3.org/1999/XMLSchema"">
<SOAP-ENV:Body>
<HelloWorld xmlns=""http://tempuri.org/""
SOAP-ENV:encodingStyle=""http://schemas.xmlsoap.org/soap/encoding/"">
<int1 xsi:type=""xsd:integer"">12</int1>
<int2 xsi:type=""xsd:integer"">32</int2>
</HelloWorld>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>");
return soapEnvelopeDocument;
}
private static void InsertSoapEnvelopeIntoWebRequest(XmlDocument soapEnvelopeXml, HttpWebRequest webRequest)
{
using (Stream stream = webRequest.GetRequestStream())
{
soapEnvelopeXml.Save(stream);
}
}
I got this simple solution here:
Sending SOAP request and receiving response in .NET 4.0 C# without using the WSDL or proxy classes:
class Program
{
/// <summary>
/// Execute a Soap WebService call
/// </summary>
public static void Execute()
{
HttpWebRequest request = CreateWebRequest();
XmlDocument soapEnvelopeXml = new XmlDocument();
soapEnvelopeXml.LoadXml(#"<?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://schemas.xmlsoap.org/soap/envelope/"">
<soap:Body>
<HelloWorld xmlns=""http://tempuri.org/"" />
</soap:Body>
</soap:Envelope>");
using (Stream stream = request.GetRequestStream())
{
soapEnvelopeXml.Save(stream);
}
using (WebResponse response = request.GetResponse())
{
using (StreamReader rd = new StreamReader(response.GetResponseStream()))
{
string soapResult = rd.ReadToEnd();
Console.WriteLine(soapResult);
}
}
}
/// <summary>
/// Create a soap webrequest to [Url]
/// </summary>
/// <returns></returns>
public static HttpWebRequest CreateWebRequest()
{
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(#"http://localhost:56405/WebService1.asmx?op=HelloWorld");
webRequest.Headers.Add(#"SOAP:Action");
webRequest.ContentType = "text/xml;charset=\"utf-8\"";
webRequest.Accept = "text/xml";
webRequest.Method = "POST";
return webRequest;
}
static void Main(string[] args)
{
Execute();
}
}
I think there is a simpler way:
public async Task<string> CreateSoapEnvelope()
{
string soapString = #"<?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://schemas.xmlsoap.org/soap/envelope/"">
<soap:Body>
<HelloWorld xmlns=""http://tempuri.org/"" />
</soap:Body>
</soap:Envelope>";
HttpResponseMessage response = await PostXmlRequest("your_url_here", soapString);
string content = await response.Content.ReadAsStringAsync();
return content;
}
public static async Task<HttpResponseMessage> PostXmlRequest(string baseUrl, string xmlString)
{
using (var httpClient = new HttpClient())
{
var httpContent = new StringContent(xmlString, Encoding.UTF8, "text/xml");
httpContent.Headers.Add("SOAPAction", "http://tempuri.org/HelloWorld");
return await httpClient.PostAsync(baseUrl, httpContent);
}
}
The best practice is to reference the WSDL and use it like a web service reference.
It's easier and works better, but if you don't have the WSDL, the XSD definitions are a good piece of code.
I wrote a more general helper class which accepts a string-based dictionary of custom parameters, so that they can be set by the caller without having to hard-code them. It goes without saying that you should only use such method when you want (or need) to manually issue a SOAP-based web service: in most common scenarios the recommended approach would be using the Web Service WSDL together with the Add Service Reference Visual Studio feature instead.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Xml;
namespace Ryadel.Web.SOAP
{
/// <summary>
/// Helper class to send custom SOAP requests.
/// </summary>
public static class SOAPHelper
{
/// <summary>
/// Sends a custom sync SOAP request to given URL and receive a request
/// </summary>
/// <param name="url">The WebService endpoint URL</param>
/// <param name="action">The WebService action name</param>
/// <param name="parameters">A dictionary containing the parameters in a key-value fashion</param>
/// <param name="soapAction">The SOAPAction value, as specified in the Web Service's WSDL (or NULL to use the url parameter)</param>
/// <param name="useSOAP12">Set this to TRUE to use the SOAP v1.2 protocol, FALSE to use the SOAP v1.1 (default)</param>
/// <returns>A string containing the raw Web Service response</returns>
public static string SendSOAPRequest(string url, string action, Dictionary<string, string> parameters, string soapAction = null, bool useSOAP12 = false)
{
// Create the SOAP envelope
XmlDocument soapEnvelopeXml = new XmlDocument();
var xmlStr = (useSOAP12)
? #"<?xml version=""1.0"" encoding=""utf-8""?>
<soap12:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""
xmlns:xsd=""http://www.w3.org/2001/XMLSchema""
xmlns:soap12=""http://www.w3.org/2003/05/soap-envelope"">
<soap12:Body>
<{0} xmlns=""{1}"">{2}</{0}>
</soap12:Body>
</soap12:Envelope>"
: #"<?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>
<{0} xmlns=""{1}"">{2}</{0}>
</soap:Body>
</soap:Envelope>";
string parms = string.Join(string.Empty, parameters.Select(kv => String.Format("<{0}>{1}</{0}>", kv.Key, kv.Value)).ToArray());
var s = String.Format(xmlStr, action, new Uri(url).GetLeftPart(UriPartial.Authority) + "/", parms);
soapEnvelopeXml.LoadXml(s);
// Create the web request
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
webRequest.Headers.Add("SOAPAction", soapAction ?? url);
webRequest.ContentType = (useSOAP12) ? "application/soap+xml;charset=\"utf-8\"" : "text/xml;charset=\"utf-8\"";
webRequest.Accept = (useSOAP12) ? "application/soap+xml" : "text/xml";
webRequest.Method = "POST";
// Insert SOAP envelope
using (Stream stream = webRequest.GetRequestStream())
{
soapEnvelopeXml.Save(stream);
}
// Send request and retrieve result
string result;
using (WebResponse response = webRequest.GetResponse())
{
using (StreamReader rd = new StreamReader(response.GetResponseStream()))
{
result = rd.ReadToEnd();
}
}
return result;
}
}
}
For additional info & details regarding this class you can also read this post on my blog.
So this is my final code after googling for 2 days on how to add a namespace and make soap request along with the SOAP envelope without adding proxy/Service Reference
class Request
{
public static void Execute(string XML)
{
try
{
HttpWebRequest request = CreateWebRequest();
XmlDocument soapEnvelopeXml = new XmlDocument();
soapEnvelopeXml.LoadXml(AppendEnvelope(AddNamespace(XML)));
using (Stream stream = request.GetRequestStream())
{
soapEnvelopeXml.Save(stream);
}
using (WebResponse response = request.GetResponse())
{
using (StreamReader rd = new StreamReader(response.GetResponseStream()))
{
string soapResult = rd.ReadToEnd();
Console.WriteLine(soapResult);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
private static HttpWebRequest CreateWebRequest()
{
string ICMURL = System.Configuration.ConfigurationManager.AppSettings.Get("ICMUrl");
HttpWebRequest webRequest = null;
try
{
webRequest = (HttpWebRequest)WebRequest.Create(ICMURL);
webRequest.Headers.Add(#"SOAP:Action");
webRequest.ContentType = "text/xml;charset=\"utf-8\"";
webRequest.Accept = "text/xml";
webRequest.Method = "POST";
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
return webRequest;
}
private static string AddNamespace(string XML)
{
string result = string.Empty;
try
{
XmlDocument xdoc = new XmlDocument();
xdoc.LoadXml(XML);
XmlElement temproot = xdoc.CreateElement("ws", "Request", "http://example.com/");
temproot.InnerXml = xdoc.DocumentElement.InnerXml;
result = temproot.OuterXml;
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
return result;
}
private static string AppendEnvelope(string data)
{
string head= #"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" ><soapenv:Header/><soapenv:Body>";
string end = #"</soapenv:Body></soapenv:Envelope>";
return head + data + end;
}
}
As an alternative, and pretty close to debiasej approach. Since a SOAP request is just a HTTP request, you can simply perform a GET or POST using with HTTP client, but it's not mandatory to build SOAP envelope.
Something like this:
using Microsoft.Extensions.Logging;
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
namespace HGF.Infraestructure.Communications
{
public class SOAPSample
{
private readonly IHttpClientFactory _clientFactory;
private readonly ILogger<DocumentProvider> _logger;
public SOAPSample(ILogger<DocumentProvider> logger,
IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
_logger = logger;
}
public async Task<string> UsingGet(int value1, int value2)
{
try
{
var client = _clientFactory.CreateClient();
var response = await client.GetAsync($"https://hostname.com/webservice.asmx/SampleMethod?value1={value1}&value2={value2}", HttpCompletionOption.ResponseHeadersRead);
//NULL check, HTTP Status Check....
return await response.Content.ReadAsStringAsync();
}
catch (Exception ex)
{
_logger.LogError(ex, "Oops! Something went wrong");
return ex.Message;
}
}
public async Task<string> UsingPost(int value1, int value2)
{
try
{
var content = new StringContent($"value1={value1}&value2={value2}", Encoding.UTF8, "application/x-www-form-urlencoded");
var client = _clientFactory.CreateClient();
var response = await client.PostAsync("https://hostname.com/webservice.asmx/SampleMethod", content);
//NULL check, HTTP Status Check....
return await response.Content.ReadAsStringAsync();
}
catch (Exception ex)
{
_logger.LogError(ex, "Oops! Something went wrong");
return ex.Message;
}
}
}
}
Of course, it depends on your scenario. If the payload is too complex, then this won't work
Call SOAP webservice in c#
using (var client = new UpdatedOutlookServiceReferenceAPI.OutlookServiceSoapClient("OutlookServiceSoap"))
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12;
var result = client.UploadAttachmentBase64(GUID, FinalFileName, fileURL);
if (result == true)
{
resultFlag = true;
}
else
{
resultFlag = false;
}
LogWriter.LogWrite1("resultFlag : " + resultFlag);
}

Categories