我有一些IO代码在try..catch中读取流。它捕获IOException并调用System.Runtime.InteropServices.Marshal.GetHRForException() 在捕获中,试图根据HResult采取不同的行动。像这样:
try
{
stream.Read(...);
}
catch (IOException ioexc1)
{
uint hr = (uint) Marshal.GetHRForException(ioexc1);
if (hr == ...)
do_one_thing();
else
do_another();
}
程序集已签名并标有AllowPartiallyTrustedCallersAttribute。
但是使用trust =“medium”在ASP.NET中运行此代码,我得到了这个例外:
Request for the permission of type 'System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed.
几个问题:
catch (IOException ioexc1)
{
if (!OkToCallUnmanaged())
throw ioexc1;
uint hr = (uint) Marshal.GetHRForException(ioexc1);
if (hr == ...)
do_one_thing();
else
do_another();
}
我认为有一种运行时机制可用于测试权限是否可用,但无法找到它。
编辑:this blog article是答案吗?微软的ShawnFa表示你不能对受LinkDemand保护的方法进行try ... catch(SecurityException)。如果MethodA()调用MethodB(),并且MethodB()用LinkDemand标记为完全信任,则检查LinkDemand,方法A是Jit'ed。因此,为了避免SecurityException,我需要将Marshal.GetHRForException提取到一个单独的方法中。那是对的吗?
应用于我的代码,MethodA()可能是调用Read的代码,然后在catch中尝试调用GetHRForException()。 GetHRForException是MethodB()。当MethodA()是JIT时,将评估LinkDemand。 (此LinkDemand在我的中等信任ASP.NET方案中失败)。如果我将GetHRForException移动到一个新方法,MethodC(),并且只有在命令权限.Demand()成功之后才有条件地调用MethodC(),理论上我应该能够在JIT时避免SecurityException,因为MethodC()将是只有在permission.Demain()成功之后才进行JIT。
答案 0 :(得分:3)
所需方法为SecurityPermission.IsUnrestricted()。它返回true或false,指示是否允许该权限。它不像<{3}}那样要求权限。我使用IsUnresticted和SecurityPermissionFlag.UnmanagedCode来查看是否允许程序集调用非托管代码,然后仅在允许时调用非托管代码。
还有一个额外的转折点。 JIT编译器在编译方法时,会在任何称为我要编译的方法的方法上检查CodeAccessPermission LinkDemands。 Marshal.GetHRForException()标有LinkDemand。因此,调用Marshal.GetHRForException()的方法将在JIT编译时抛出无法捕获的SecurityException,此时在受限制的环境中运行,例如具有中等信任的ASP.NET。因此,在这种情况下,我们必须永远不要JIT调用Marshal.GetHRForException()的方法,这意味着我需要将Marshal.GetHRForException()分解为我的代码中的一个单独的方法,该方法只有在UnmanagedCode被调用时才被调用(因此被JITted)不受限制。
以下是一些示例代码:
internal void DoTheThing()
{
try
{
DoSomethingThatMayCauseAnException();
}
catch (System.IO.IOException ioexc1)
{
// Check if we can call GetHRForException,
// which makes unmanaged code calls.
var p = new SecurityPermission(SecurityPermissionFlag.UnmanagedCode);
if (p.IsUnrestricted())
{
uint hresult = _HRForException(ioexc1);
if (hresult == 0x80070021) // ERROR_LOCK_VIOLATION
TakeActionOnLockViolation(); // maybe notify the user
else
throw new Exception("Cannot handle", ioexc1);
}
else
{
// The permission is restricted. Therefore, we cannot call
// GetHRForException, and cannot do the subtle handling of
// ERROR_LOCK_VIOLATION. Just bail.
throw new Exception("Cannot handle", ioexc1);
}
}
}
// This method must remain separate, and must not be marked with a LinkDemand for
// UnmanagedCode.
//
// Marshal.GetHRForException() is needed to do special exception handling for
// the read. But, that method requires UnmanagedCode permissions, and is marked
// with LinkDemand for UnmanagedCode. In an ASP.NET medium trust environment,
// where UnmanagedCode is restricted, will generate a SecurityException at the
// time of JIT of the method that calls a method that is marked with LinkDemand
// for UnmanagedCode. The SecurityException, if it is restricted, will occur
// when this method is JITed.
//
// The Marshal.GetHRForException() is factored out of DoTheThing in order to
// avoid the SecurityException at JIT compile time. Because _HRForException is
// called only when the UnmanagedCode is allowed, .NET never
// JIT-compiles this method when UnmanagedCode is disallowed, and thus never
// generates the JIT-compile time exception.
//
private static uint _HRForException(System.Exception ex1)
{
return unchecked((uint)System.Runtime.InteropServices.Marshal.GetHRForException(ex1));
}
答案 1 :(得分:1)
制作CAS需求的代码如下所示
SecurityPermission permission = new SecurityPermission(SecurityPermissionFlag.UnmanagedCode);
try
{
permission.Demand();
// Got it, away we go
}
catch (SecurityException)
{
// Could not get permission to make unmanaged code calls
// React accordingly.
}
答案 2 :(得分:0)
通过检查异常类型,System.Runtime.InteropServices.Marshal.GetHRForException()能为您提供任何无法获得的信息吗?看起来它使用静态映射。