我有一个使用 .NET C# 的现有 Web 服务。 我们的内部应用程序调用服务,该服务使用 XML 连接到 UPS 来处理请求。 几周前它停止工作。 我连接到UPS,他们说要更新我所做的URL。 他们还提到他们看到很多TLS失败,但我们的IIS 8和Windows Server 2012都是最新的。 我还运行了安全检查,并且SSL3和TLS都被禁用了。
在我的开发系统上,我正在尝试测试更改。 首先,我编写了一个连接到UPS服务器的小型控制台应用程序,该应用程序按预期工作。 我将代码移动到 Web 服务并运行相同的测试,但它失败了。 我已经验证了 Web 服务和控制台代码是否正在运行相同版本的 .NET。
我已经比较了发送的数据,因此我确定两者都有效。 该错误发生在 shipRequest.GetRequestStream() 中。 知道为什么它在 Web 服务上失败而不是控制台应用程序失败吗?
我刚刚添加了服务器证书验证回调部分,如果删除并出现相同的错误,它将不起作用。
Rate_Tool_SampleRequest.xml是从 UPS 开发网站下载的。
internal string UPSAccessKey;
internal string UPSPassword;
internal string UPSUserID;
internal string UPSAccount;
internal string Server = "https://onlinetools.ups.com/ups.app/xml/Rate";
// test file, to be removed.
private static string RateFile = @"D:ProjectsUPS-TrackingsamplesRate_Tool_SampleRequest.xml";
internal string GetRates(UPS_RateEstimate request)
{
try
{
// var data = this.AccessRequest + request.Data;
// Read UPS test file and replace key filds
var data = File.ReadAllText(RateFile)
.Replace("Your_License", UPSAccessKey)
.Replace("Your_ID", UPSPassword)
.Replace("Your_Password", UPSUserID)
.Replace("Ship Number", UPSAccount);
var response = this.RequestData(data);
return response;
}
catch (Exception exc)
{
System.Diagnostics.Debug.WriteLine(exc);
return exc.ToString();
}
}
private string RequestData(string request)
{
HttpWebRequest shipRequest;
try
{
// convert request to bytes
ASCIIEncoding encoding = new ASCIIEncoding();
byte[] data = encoding.GetBytes(request); // Request
shipRequest = (HttpWebRequest)WebRequest.Create(Server);
shipRequest.Method = "POST";
shipRequest.ContentType = "application/x-www-form-urlencoded";
shipRequest.ContentLength = data.Length;
shipRequest.ServerCertificateValidationCallback += (sender, cert, chain, error) => { return true; };
using (var requestStream = shipRequest.GetRequestStream())
{
// Send the data
requestStream.Write(data, 0, data.Length);
requestStream.Close();
using (var response = shipRequest.GetResponse())
{
using (StreamReader sr = new StreamReader(response.GetResponseStream()))
{
var result = sr.ReadToEnd();
File.WriteAllText(RateTestResultFile, result);
return result;
}
}
}
}
finally
{
shipRequest = null;
}
}
System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a send.
---> System.IO.IOException: Authentication failed because the remote party has closed the transport stream.
at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.ForceAuthentication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult)
at System.Net.TlsStream.CallProcessAuthentication(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Net.TlsStream.ProcessAuthentication(LazyAsyncResult result)
at System.Net.TlsStream.Write(Byte[] buffer, Int32 offset, Int32 size)
at System.Net.PooledStream.Write(Byte[] buffer, Int32 offset, Int32 size)
at System.Net.ConnectStream.WriteHeaders(Boolean async)
--- End of inner exception stack trace ---
at System.Net.HttpWebRequest.GetRequestStream(TransportContext& context)
at System.Net.HttpWebRequest.GetRequestStream()
at UPSHelper.RequestData(String request) in App_CodeUPSUPSHelper.cs:line 99
at UPSHelper.GetRates(UPS_RateEstimate request) in App_CodeUPSUPSHelper.cs:line 34
我认为即您缺少这一行:
下面是一个完整的代码示例:
string Testing = "https://wwwcie.ups.com/rest/Rate";
string Production = "https://onlinetools.ups.com/rest/Rate";
string json = Newtonsoft.Json.JsonConvert.SerializeObject(upsRate);
System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12 | System.Net.SecurityProtocolType.Tls | System.Net.SecurityProtocolType.Tls11; //This line will ensure the latest security protocol for consuming the web service call.
WebRequest httpWebRequest = WebRequest.Create(Production);
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";
using (StreamWriter streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
streamWriter.Write(json);
streamWriter.Flush();
streamWriter.Close();
}
HttpWebResponse httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
string returnResult = "";
using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
returnResult = streamReader.ReadToEnd();
}
if (string.IsNullOrEmpty(returnResult))
{
return NotFound();
}
return Ok(returnResult);
注意:我正在序列化 UPSRate 对象,而您正在从它看起来像的文件中读取属性。