问题
I have an existing web service using .NET C#. Our in house application call the service and the service connects to UPS using XML to handle the request. It stopped working a few weeks ago. I connect to UPS and they said to update the URLs which I have done. They also mentioned they were seeing lots of TLS failure for but our IIS 8 and Windows Server 2012 are both up to date. I also have run security checks and both SSL3 and TLS have been disabled.
On my development system I am attempting to test the changes. First I wrote a small console application which connect to the UPS servers, this worked as expected. I move the code to the web service and ran the same test and it fails. I have verified the web service and the console code are running the same version of .NET.
I have compared the data sent so I am sure both are valid. The error occurs at shipRequest.GetRequestStream(). Any idea why it is failing on the web service but not the console app?
I just added the ServerCertificateValidationCallback part, it does not work if removed with the same error.
Rate_Tool_SampleRequest.xml was downloaded from the UPS development site.
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:\Projects\UPS-Tracking\samples\Rate_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_Code\UPS\UPSHelper.cs:line 99
at UPSHelper.GetRates(UPS_RateEstimate request) in \App_Code\UPS\UPSHelper.cs:line 34
回答1:
I think namely you are missing this line:
Here is a full code example:
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);
NOTE: I am serializing a UPSRate object whereas you are reading the properties from a file it looks like.
来源:https://stackoverflow.com/questions/48329844/ups-rate-request-using-net-web-service