[英]SOAPAction over HTTP in .NET Core vs .NET Framework
我在較舊的應用程序中有以下代碼:
// send request
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
req.ContentType = "text/xml;charset=UTF-8";
req.Method = "POST";
req.Accept = "text/xml";
req.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip,deflate");
req.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
var test = req.Headers.ToString();
if (string.IsNullOrWhiteSpace(SOAPaction))
req.Headers.Add("SOAPAction", "\"\"");
else
req.Headers.Add("SOAPAction", "\"" + SOAPaction + "\"");
using (var writer = new StreamWriter(req.GetRequestStream(), Encoding.UTF8))
{
xdoc.Save(writer, SaveOptions.DisableFormatting);
}
WebResponse response;
try
{
response = req.GetResponse();
System.Diagnostics.Debug.WriteLine(response.ToString());
}
catch (WebException we)
{
if (we.Response.ContentType.StartsWith("text/xml", StringComparison.InvariantCultureIgnoreCase))
{
using (var stream = we.Response.GetResponseStream())
{
var xml = XDocument.Load(stream);
var fault = xml.Descendants().FirstOrDefault(e => e.Name.LocalName == "faultstring").Value;
throw new Exception("Error received when invoking the method: " + fault);
}
}
else
throw we;
}
我正在嘗試將其移植到新的 .NET Core 應用程序,但在更改必要的標頭后,我總是收到錯誤消息:“遠程服務器返回錯誤:(500) 內部服務器錯誤”,這並不是很有幫助。 我知道 HttpWebRequest 在 .NET Framework 和 .NET Core 中的工作方式不同,但是在 .NET Core 中設置標頭后,它應該只是進行相同的調用,我想?
我不確定服務器為什么拒絕它,因為您的請求代碼對我來說似乎很好。 (500) Internal Server Error
是服務器端錯誤。 大多數情況下,它來自請求正文或標頭或 url 本身,服務器拒絕了它。 所以你需要從url開始調試。 我發現有時必須在 url 末尾指定?WSDL
,如果未指定,它將返回500 internal server error
。 所以,先檢查一下。 如果問題仍然存在,請檢查正文並在SoapUI
或Postman
等測試工具上對其進行測試,確保它與您在請求中使用的內容和標頭相同。
另外,我建議改為使用HttpClient
(因為它已移至 ,如果可能的話。因為HttpWebRequest
是一個死區HttpClient
建立在它之上,它會比舊的HttpWebRequest
更好且易於維護(加上它是用async
開箱即用的方式構建的)。
如果你堅持使用HttpWebRequest
,那么你可以實現你自己的類,這將使事情更容易維護。 我已經專門為 Soap API 及其為我以前的項目提供的信封構建了一個小型的基本類。 因為我不想在每個類似的項目上重寫相同的東西。 我希望它會很有用:
肥皂 API 類
public class SoapAPI : IDisposable
{
// Requirements for Soap API
private const string SoapAction = "SOAPAction";
private const string SoapContentType = "text/xml;charset=\"utf-8\"";
private const string SoapAccept = "text/xml";
private const string SoapMethod = "POST";
private HttpWebRequest _request;
private SoapEnvelope _soapEnvelope;
public class SoapAPIResponse
{
private readonly SoapAPI _instance;
public SoapAPIResponse(SoapAPI instance)
{
_instance = instance;
}
public HttpWebResponse AsWebResponse()
{
try
{
_instance.SendRequest(_instance._soapEnvelope.GetEnvelope());
return (HttpWebResponse)_instance._request.GetResponse();
}
catch (WebException ex)
{
throw ex;
}
}
public StreamReader AsStreamReader()
{
return new StreamReader(AsHttpWebResponse().GetResponseStream());
}
public string AsString()
{
return AsStreamReader().ReadToEnd();
}
}
public SoapAPI(string url, SoapEnvelope envelope)
{
if (string.IsNullOrEmpty(url)) { throw new ArgumentNullException(nameof(url)); }
if (envelope == null) { throw new ArgumentNullException(nameof(envelope)); }
// some Soap Services requires to target the xml schema ?wsdl at the end of the url, just uncomment if needed.
// url = url.LastIndexOf("?WSDL", StringComparison.InvariantCultureIgnoreCase) > 0 ? url : $"{url}?WSDL";
_request = (HttpWebRequest)WebRequest.Create(new Uri(url));
_request.Headers.Clear();
_request.Headers.Add(SoapAction, envelope.SoapActionName);
_request.ContentType = SoapContentType;
_request.Accept = SoapAccept;
_request.Method = SoapMethod;
// optimizations
_request.ServicePoint.ConnectionLimit = 8;
_request.Proxy = null;
_request.KeepAlive = true;
_request.ReadWriteTimeout = 300000;
// envelope
_soapEnvelope = envelope;
}
public SoapAPI AddHeader(string name, string value)
{
_request.Headers.Add(name, value);
return this;
}
public SoapAPI AddHeader(HttpRequestHeader header, string value)
{
_request.Headers.Add(header, value);
return this;
}
public SoapAPI AddCompressionMethod(DecompressionMethods methods)
{
_request.AutomaticDecompression = methods;
return this;
}
private void SendRequest(object obj)
{
using StreamWriter sw = new StreamWriter(_request.GetRequestStream(), Encoding.UTF8);
sw.Write(obj);
}
public SoapAPIResponse GetResponse()
{
return new SoapAPIResponse(this);
}
#region IDisposable
private bool _disposed = false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
_request = null;
_soapEnvelope = null;
}
_disposed = true;
}
}
~SoapAPI()
{
Dispose(false);
}
#endregion
}
SoapEnvelope 類
public class SoapEnvelope : IDisposable
{
private XDocument _envelope;
public XNamespace SoapNamespace = "http://schemas.xmlsoap.org/soap/envelope/";
public XNamespace SoapActionNamespace { get; }
public string SoapActionName { get; }
public SoapEnvelope(XNamespace actionNamespace, string actionName)
{
if (actionNamespace == null) { throw new ArgumentNullException(nameof(actionNamespace)); }
if (string.IsNullOrEmpty(actionName)) { throw new ArgumentNullException(nameof(actionName)); }
SoapActionNamespace = actionNamespace;
SoapActionName = actionName;
CreateEnvelope();
}
private void CreateEnvelope()
{
_envelope = new XDocument(
new XElement(SoapNamespace + "Envelope",
new XAttribute(XNamespace.Xmlns + "soapenv", SoapNamespace),
new XAttribute(XNamespace.Xmlns + SoapActionName, SoapActionNamespace),
new XElement(SoapNamespace + "Header"),
new XElement(SoapNamespace + "Body")
)
);
}
public SoapEnvelope AddHeaderElement(XElement elements)
{
_envelope.Root.Element(SoapNamespace + "Header").Add(elements);
return this;
}
public SoapEnvelope AddBodyElement(XElement elements)
{
_envelope.Root.Element(SoapNamespace + "Body").Add(elements);
return this;
}
public XDocument GetEnvelope()
{
return _envelope;
}
public bool IsValidXml(string xml)
{
try
{
XmlConvert.VerifyXmlChars(xml);
return true;
}
catch (Exception)
{
return false;
}
}
#region IDisposable
private bool _disposed = false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
_envelope = null;
SoapNamespace = null;
}
_disposed = true;
}
}
~SoapEnvelope()
{
Dispose(false);
}
#endregion
}
這是基本用法:
WebResponse response; // will hold the response.
XNamespace actionNamespace = "http://xxxx"; // the namespace
var SoapAction = ""; //the action value
var envelope =
new SoapEnvelope(actionNamespace, SoapAction)
.AddBodyElement(new XElement(...));
using (var request = new SoapAPI(url, envelope))
{
response = request
.AddCompressionMethod(DecompressionMethods.GZip | DecompressionMethods.Deflate)
.AddHeader(HttpRequestHeader.AcceptEncoding, "gzip,deflate")
.GetResponse()
.AsWebResponse(); // you can get the respnse as StreamReader, WebResponse, and String
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.