I have some IO code that reads a stream within a try..catch. It catches IOException and calls System.Runtime.InteropServices.Marshal.GetHRForException() within the catch, in an attempt to take different actions based on the HResult. Something like this:
try
{
stream.Read(...);
}
catch (IOException ioexc1)
{
uint hr = (uint) Marshal.GetHRForException(ioexc1);
if (hr == ...)
do_one_thing();
else
do_another();
}
The assembly is signed and marked with AllowPartiallyTrustedCallersAttribute.
But running this code within ASP.NET with trust="medium", I get this exception:
Request for the permission of type 'System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed.
A couple questions:
- I think the exception is occurring because GetHRForException calls into unmanaged code, which is not permitted in medium trust. Correct?
- This exception is being thrown, not at the time of execution of GetHRForException, but at the time the method is being JIT'ed - Correct? (The stacktrace shows my method, but I am 99% certain that an IO exception has not occurred)
- If so, is there a way for me to vary the behavior in a partial trust environment, so that I don't call the GetHRForException (unmanaged code) where it is not permitted? In other words, how can I allow the JIT to succeed at compile time, while also evaluating at runtime whether the code should call GetHRForException()? Something like this:
catch (IOException ioexc1)
{
if (!OkToCallUnmanaged())
throw ioexc1;
uint hr = (uint) Marshal.GetHRForException(ioexc1);
if (hr == ...)
do_one_thing();
else
do_another();
}
I think there is a runtime mechanism for testing if permissions are available, but haven't been able to find it.
EDIT: Is this blog article the answer? ShawnFa of Microsoft says that you cannot do a try ... catch(SecurityException) around a method protected by a LinkDemand. If MethodA() calls MethodB(), and MethodB() is marked with LinkDemand for full trust, then the LinkDemand is checked with MethodA is Jit'ed. Therefore to avoid the SecurityException, I need to extract Marshal.GetHRForException into a separate method. Is that correct?
Applied to my code, MethodA() might be the code that calls Read, and then in the catch tries to call GetHRForException(). GetHRForException is MethodB(). The LinkDemand is evaluated when MethodA() is JIT'd. (This LinkDemand fails in my medium-trust ASP.NET scenario). If I move the GetHRForException into a new method, MethodC(), and conditionally call MethodC() only after an imperative permission.Demand() succeeds, theoretically I should be able to avoid the SecurityException at JIT time, because MethodC() will be JIT'd only after the permission.Demain() succeeds.