客户端发送 SOAP 请求并接收响应

尝试创建一个 C # 客户端(将作为 Windows 服务开发) ,该客户端将 SOAP 请求发送到 Web 服务(并获得结果)。

从这个 有个问题我看到了这个代码:

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; }
}

看起来不错,有人知道如何使用它,如果它是最好的做法?

728980 次浏览

我通常用另一种方法来做同样的事情

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);
}
}

最佳实践是引用 WSDL 并像使用 Web 服务引用一样使用它。 它更容易并且工作得更好,但是如果您没有 WSDL,那么 XSD 定义是一段很好的代码。

我有一个简单的解决方案:

在.NET 4.0 C # 中发送 SOAP 请求和接收响应,而不使用 WSDL 或代理类:

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();
}
}

我认为有一个更简单的方法:

 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);
}
}

我编写了一个更通用的 helper 类,它接受一个基于字符串的自定义参数字典,这样调用者就可以设置它们,而无需对它们进行硬编码。不言而喻,只有当您想(或需要)手动发布基于 SOAP 的 Web 服务时,才应该使用这种方法: 在大多数常见场景中,推荐的方法是使用 Web Service WSDL 和 添加服务参考 Visual Studio 特性。

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;
}
}
}

关于这个课程的更多信息和细节,你也可以在我的博客 读读这篇文章

在 c # 中调用 SOAPwebservice

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);
}

因此,这是我在谷歌了两天关于如何添加名称空间和如何在不添加代理/服务引用的情况下使用 SOAP 信封发出肥皂请求之后的最后一段代码

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;
}
}

作为替代方案,非常接近 debiasej 方法。由于 SOAP 请求只是一个 HTTP 请求,您可以简单地使用 HTTP 客户端执行 GET 或 POST,但是并不一定要构建 SOAP 信封。

就像这样:

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;
}
}
}
}

当然,这取决于您的场景。如果有效载荷过于复杂,那么这将不起作用