请求.GetRequestStream() 抛出"值不能为空"异常



我有一个函数可以对接受jsons的api服务器执行http请求:

private static string DoRequest(object objToSend, string Url)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url);
request.Method = "POST";
request.ContentType = "application/json";
request.Accept = "application/json";
var jsonString= Obj2Json(objToSend);
if (string.IsNullOrEmpty(jsonString))
throw new ArgumentNullException("objToSend", "Objcet was converted to json string and produces an empty string");
var buffer = Encoding.UTF8.GetBytes(jsonString);
request.ContentLength = buffer.Length;
using (var stream = request.GetRequestStream())
{
stream.Write(buffer, 0, buffer.Length);
}
var response = (HttpWebResponse)request.GetResponse();
var sResponse = new System.IO.StreamReader(response.GetResponseStream()).ReadToEnd();
return sResponse;
}

当我运行该行时:

using (var stream = request.GetRequestStream())

我有一个例外: mscorlib 中的"System.ArgumentNullException".dll("Value 不能为 null"。 System.ArgumentNullException.

在StackTrace中,有一行说:

"System.Enum.TryParseEnum(Type enumType, String value, Boolean ignoreCase, EnumResult&parseResult)">

异常正在消失,单击 F10 键。

有没有人知道,为什么会抛出异常?

我想强调的是,它在 GetRequestStream() 上抛出了异常,即在使用该流之前。写()

在浪费了大量时间之后,我发现标题是从ServicePointManager中抛出的.cs这是系统.dll的一部分。 这是导致异常的函数:

private static void LoadDisableStrongCryptoConfiguration()
{
try
{
bool disableStrongCryptoInternal = false;
int schUseStrongCryptoKeyValue = 0;
if (LocalAppContextSwitches.DontEnableSchUseStrongCrypto)
{
//.Net 4.5.2 and below will default to false unless the registry key is specifically set to 1.
schUseStrongCryptoKeyValue =
RegistryConfiguration.GlobalConfigReadInt(strongCryptoValueName, 0);
disableStrongCryptoInternal = schUseStrongCryptoKeyValue != 1;
}
else
{
// .Net 4.6 and above will default to true unless the registry key is specifically set to 0.
schUseStrongCryptoKeyValue =
RegistryConfiguration.GlobalConfigReadInt(strongCryptoValueName, 1);
disableStrongCryptoInternal = schUseStrongCryptoKeyValue == 0;
}
if (disableStrongCryptoInternal)
{
// Revert the SecurityProtocol selection to the legacy combination.
s_SecurityProtocolType = SecurityProtocolType.Tls | SecurityProtocolType.Ssl3;
}
else
{
s_SecurityProtocolType =
SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
string appSetting = RegistryConfiguration.AppConfigReadString(secureProtocolAppSetting, null);
SecurityProtocolType value;
try
{
value = (SecurityProtocolType)Enum.Parse(typeof(SecurityProtocolType), appSetting);
ValidateSecurityProtocol(value);
s_SecurityProtocolType = value;
}
// Ignore all potential exceptions caused by Enum.Parse.
catch (ArgumentNullException) { }
catch (ArgumentException) { }
catch (NotSupportedException) { }
catch (OverflowException) { }
}
disableStrongCrypto = disableStrongCryptoInternal;
}
catch (Exception e)
{
if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException)
{
throw;
}
}
}

这是完整的调用堆栈

姆科利布.dll!System.Enum.TryParseEnum(System.Type enumType, string value, bool ignoreCase, ref System.Enum.EnumResult parseResult) 姆科利布.dll!System.Enum.Parse(System.Type enumType, string value, 布尔忽略案例)系统.dll!System.Net.ServicePointManager.LoadDisableStrongCryptoConfiguration()System.dll!System.Net.ServicePointManager.EnsureConfigurationLoaded() 系统.dll!System.Net.ServicePointManager.SecurityProtocol.get() 系统.dll!System.Net.TlsStream.ProcessAuthentication(System.Net.LazyAsyncResult 结果)系统.dll!System.Net.TlsStream.Write(byte[] buffer, int 偏移量,整数大小)系统.dll!System.Net.PooledStream.Write(byte[] 缓冲区,整数偏移量,整数大小) 系统.dll!System.Net.ConnectStream.WriteHeaders(bool async) 系统.dll!System.Net.HttpWebRequest.EndSubmitRequest() 系统.dll!System.Net.HttpWebRequest.SetRequestSubmitDone(System.Net.ConnectStream 提交流)系统.dll!System.Net.Connection.CompleteConnection(bool async, System.Net.HttpWebRequest request) 系统.dll!System.Net.Connection.CompleteStartConnection(bool async, System.Net.HttpWebRequest httpWebRequest) 系统.dll!System.Net.Connection.CompleteStartRequest(bool onSubmitThread, System.Net.HttpWebRequest request, System.Net.TriState 需要重新连接) 系统.dll!System.Net.Connection.SubmitRequest(System.Net.HttpWebRequest 请求,布尔强制提交) 系统.dll!System.Net.ServicePoint.SubmitRequest(System.Net.HttpWebRequest 请求,字符串连接名称) 系统.dll!System.Net.HttpWebRequest.SubmitRequest(System.Net.ServicePoint 服务点) 系统.dll!System.Net.HttpWebRequest.GetRequestStream(out System.Net.TransportContext context) 系统.dll!System.Net.HttpWebRequest.GetRequestStream() 里维希特.dll!RivhitApi.RivhitService.DoRequest(object objToSend, 字符串 Url) 第 59 行

根据文档,当缓冲区为 null 时,Write方法将引发ArgumentNullException。在您的情况下,这意味着bJsonReq为空。

在调用Write之前,请确保它不为 null

根据这个微软文档,添加这行代码解决了这个问题。

private const string DisableCachingName = @"TestSwitch.LocalAppContext.DisableCaching";
private const string DontEnableSchUseStrongCryptoName = @"Switch.System.Net.DontEnableSchUseStrongCrypto";
AppContext.SetSwitch(DisableCachingName, true);
AppContext.SetSwitch(DontEnableSchUseStrongCryptoName, true);

该文档中还有更多选项来设置此定义。

但缺点可能是安全性的降低。 我正在寻找一个更智能的解决方案,也许通过以某种方式设置ServicePointManager,以一种SecurityProtocolType不会为null的方式。目前我找不到这样的。

最新更新