本文可帮助你解决System.Security.SecurityException
基于 Microsoft .NET Framework 3.5 SP1 从 Windows 窗体 应用程序中使用该System.Net.HttpWebRequest
类时引发的此类。
原始产品版本: Microsoft .NET Framework 3.5 Service Pack 1
原始 KB 数: 2512713
症状
以同步方式使用System.Net.HttpWebRequest
Windows 窗体应用程序中的类,该类基于 Microsoft .NET Framework 3.5 Service Pack 1。 具体而言,此代码在主线程或 UI 线程上运行。 Windows 窗体应用程序引发类型间歇性异常,System.Security.SecurityException
其消息类似于以下内容:
请求 “System.Security.Permissions.UIPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089” 的权限失败。
异常将显示类似于以下内容的故障调用堆栈:
0:000> !clrstack
ESP EIP
<<ESP>> <<EIP>> System.Threading.WaitHandle.WaitOneNative(Microsoft.Win32.SafeHandles.SafeWaitHandle, UInt32, Boolean, Boolean)
<<ESP>> <<EIP>> System.Threading.WaitHandle.WaitOne(Int64, Boolean)
<<ESP>> <<EIP>> System.Threading.WaitHandle.WaitOne(Int32, Boolean)
<<ESP>> <<EIP>> System.Net.NetworkAddressChangePolled.CheckAndReset()
<<ESP>> <<EIP>> System.Net.NclUtilities.get_LocalAddresses()
<<ESP>> <<EIP>> System.Net.WebProxyScriptHelper.myIpAddress()
.........
.........
<<ESP>> <<EIP>> System.Net.WebProxyScriptHelper+MyMethodInfo.Invoke(System.Object, System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo)
<<ESP>> <<EIP>> Microsoft.JScript.LateBinding.CallOneOfTheMembers(System.Reflection.MemberInfo[], System.Object[], Boolean, System.Object, System.Reflection.Binder, System.Globalization.CultureInfo, System.String[], Microsoft.JScript.Vsa.VsaEngine, Boolean ByRef)
<<ESP>> <<EIP>> Microsoft.JScript.LateBinding.Call(System.Reflection.Binder, System.Object[], System.Reflection.ParameterModifier[], System.Globalization.CultureInfo, System.String[], Boolean, Boolean, Microsoft.JScript.Vsa.VsaEngine)
<<ESP>> <<EIP>> Microsoft.JScript.LateBinding.Call(System.Object[], Boolean, Boolean, Microsoft.JScript.Vsa.VsaEngine).........
.........
<<ESP>> <<EIP>> Microsoft.JScript.JSMethodInfo.Invoke(System.Object, System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo)
<<ESP>> <<EIP>> Microsoft.JScript.FunctionObject.Call(System.Object[], System.Object, Microsoft.JScript.ScriptObject, Microsoft.JScript.Closure, System.Reflection.Binder, System.Globalization.CultureInfo)
<<ESP>> <<EIP>> Microsoft.JScript.Closure.Call(System.Object[], System.Object, System.Reflection.Binder, System.Globalization.CultureInfo)
<<ESP>> <<EIP>> Microsoft.JScript.LateBinding.CallValue(System.Object, System.Object[], Boolean, Boolean, Microsoft.JScript.Vsa.VsaEngine, System.Object, System.Reflection.Binder, System.Globalization.CultureInfo, System.String[])
<<ESP>> <<EIP>> Microsoft.JScript.LateBinding.CallValue(System.Object, System.Object, System.Object[], Boolean, Boolean, Microsoft.JScript.Vsa.VsaEngine)
.........
.........
<<ESP>> <<EIP>> System.Reflection.MethodBase.Invoke(System.Object, System.Object[])
<<ESP>> <<EIP>> System.Net.VsaWebProxyScript.CallMethod(System.Object, System.String, System.Object[])
<<ESP>> <<EIP>> System.Net.VsaWebProxyScript.Run(System.String, System.String)
.........
.........
<<ESP>> <<EIP>> System.Net.IWebProxyScript.Run(System.String, System.String)
<<ESP>> <<EIP>> System.Net.AutoWebProxyScriptEngine.GetProxies(System.Uri, Boolean, System.Net.AutoWebProxyState ByRef, Int32 ByRef)
<<ESP>> <<EIP>> System.Net.WebProxy.GetProxiesAuto(System.Uri, System.Net.AutoWebProxyState ByRef, Int32 ByRef)
<<ESP>> <<EIP>> System.Net.ProxyScriptChain.GetNextProxy(System.Uri ByRef)
<<ESP>> <<EIP>> System.Net.ProxyChain+ProxyEnumerator.MoveNext()
<<ESP>> <<EIP>> System.Net.ServicePointManager.FindServicePoint(System.Uri, System.Net.IWebProxy, System.Net.ProxyChain ByRef, System.Net.HttpAbortDelegate ByRef, Int32 ByRef)
<<ESP>> <<EIP>> System.Net.HttpWebRequest.FindServicePoint(Boolean)
<<ESP>> <<EIP>> System.Net.HttpWebRequest.GetRequestStream(System.Net.TransportContext ByRef)
<<ESP>> <<EIP>> System.Net.HttpWebRequest.GetRequestStream().........
.........
<<ESP>> <<EIP>> YourApplicationFunction.....
.........
.........
原因
System.Net.HttpWebRequest
当类从主线程(也是用户界面(UI)线程运行时,可能需要运行 WPAD(Web 代理自动检测)协议来检测是否需要代理才能到达目标 URL。 在此过程中, System.Net
在内存中下载并编译 PAC(代理自动配置)脚本,并尝试根据 PAC 规范执行 FindProxyForURL
该函数。
执行此操作时, System.Net
在应用程序内创建一个内部应用程序域,该域运行的权限最少,最重要的是,它不会向此新应用程序域授予 UI 权限。 代理和运行 FindProxyForURL
JavaScript 函数的计算发生在此新应用程序域的上下文中,在此过程中System.Net
,可能需要根据 PAC 规范(例如isInNet
)dnsResolve
myIpAddress
运行多个帮助程序函数来计算代理。
例如,运行 myIpAddress
函数 System.Net
时将尝试评估当前计算机的当前 IP 地址,有时可能需要使用 System.Threading.WaitHandle.WaitOne()
函数调用。 从主线程或 UI 线程调用此 System.Threading.WaitHandle.WaitOne()
函数时,此调用将在等待时继续处理窗口消息。
如果在调用期间 WaitOne()
处理窗口消息,.NET Framework 公共语言运行时 (CLR) 将进行完整堆栈检查并要求 UI 权限。 如果它在权限中发现任何不匹配,则会引发 a System.Security.SecurityException
。
决议
此行为是设计造成的。
若要解决此问题,可以异步切换到使用 System.Net.HttpWebRequest
类,或者仍然可以使用同步方法,但从后台线程或非 UI 线程运行它。 这样一来,窗口进程将拥有 UI 线程的自由统治,而无需中断其他应用程序域中的等待调用。
可以使用的另一种方法是保留与之前相同的代码,但不能 System.Net
在主线程上运行自动代理检测,而是可以创建新线程并尝试 System.Net.WebProxy.GetProxy
在此后台线程上运行函数,让后台线程执行自动代理检测。 后台线程检索代理服务器的地址后,可以设置 Proxy
对象的属性 HttpWebRequest
,并将其设置为固定代理。 这将阻止主线程上的自动代理检测,并且不会引发异常。
如果环境配置了固定代理,可以通过在应用程序配置文件中添加以下配置设置来完全关闭自动代理检测:
<system.net>
<defaultProxy>
<proxy autoDetect="False" usesystemdefault="False" proxyaddress="http://yourProxy:yourProxyPort"/>
</defaultProxy>
</system.net>
注释
尽管在大多数情况下,使用 System.Net.HttpWebRequest
类运行的同步 HTTP 请求应该正常工作,但我们不建议运行同步网络操作,例如从主线程或 UI 线程发送 HTTP 请求,因为网络操作(如 IP 地址或 DNS 解析、代理检测等)可能会遇到可能延迟。 最好从后台线程运行此类同步请求或异步运行请求。