在受限制的中间信任环境中编译Expression<TDelegate>。

9
尝试在中等信任的Web应用程序中编译表达式时,我遇到了MethodAccessException。是否有其他方法可以在中等信任下编译表达式或解决此异常的解决方法?
抛出异常的代码:
Expression<Func<object>> efn = 
  Expression.Lambda<Func<object>>(Expression.Convert((plan,typeof(object)));

Func<object> fn = efn.Compile(); // Exception thrown here

变量plan是一个表达式,代表以下执行计划:
{
  Convert(Query(MyProjectNamespace.MyDatabaseTableObject).Provider).Execute
  (
    new QueryCommand(
    "SELECT [t0].[LinkId], [t0].[Url] FROM [dbo].[MyDatabaseTable] AS t0",
    value(System.String[]), 
    r0 => new MyDatabaseTableObject() 
    {
      Id = IIF(r0.IsDBNull(0), 0, 
        Convert(ChangeType(r0.GetValue(0), System.Int32))), 
      Url = IIF(r0.IsDBNull(1), null, 
        Convert(ChangeType(r0.GetValue(1), System.String)))
    }, 
    value(System.Collections.Generic.List[System.String])), 
    new [] {}
  )
}

完整的堆栈跟踪:
at System.Reflection.MethodBase.PerformSecurityCheck(Object obj, RuntimeMethodHandle method, IntPtr parent, UInt32 invocationFlags)
at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
at System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
at System.Linq.Expressions.ExpressionCompiler.AddGlobal(Type type, Object value)
at System.Linq.Expressions.ExpressionCompiler.GenerateConstant(ILGenerator gen, Type type, Object value, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.GenerateConstant(ILGenerator gen, ConstantExpression c, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.Generate(ILGenerator gen, Expression node, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.GenerateArgs(ILGenerator gen, ParameterInfo[] pis, ReadOnlyCollection`1 args)
at System.Linq.Expressions.ExpressionCompiler.GenerateMethodCall(ILGenerator gen, MethodInfo mi, ReadOnlyCollection`1 args, Type objectType)
at System.Linq.Expressions.ExpressionCompiler.GenerateMethodCall(ILGenerator gen, MethodCallExpression mc, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.Generate(ILGenerator gen, Expression node, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.GenerateConvert(ILGenerator gen, UnaryExpression u)
at System.Linq.Expressions.ExpressionCompiler.Generate(ILGenerator gen, Expression node, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.GenerateConditional(ILGenerator gen, ConditionalExpression b)
at System.Linq.Expressions.ExpressionCompiler.Generate(ILGenerator gen, Expression node, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.GenerateMemberAssignment(ILGenerator gen, MemberAssignment binding, Type objectType)
at System.Linq.Expressions.ExpressionCompiler.GenerateBinding(ILGenerator gen, MemberBinding binding, Type objectType)
at System.Linq.Expressions.ExpressionCompiler.GenerateMemberInit(ILGenerator gen, ReadOnlyCollection`1 bindings, Boolean keepOnStack, Type objectType)
at System.Linq.Expressions.ExpressionCompiler.GenerateMemberInit(ILGenerator gen, MemberInitExpression init)
at System.Linq.Expressions.ExpressionCompiler.Generate(ILGenerator gen, Expression node, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.GenerateLambda(LambdaExpression lambda)
at System.Linq.Expressions.ExpressionCompiler.GenerateCreateDelegate(ILGenerator gen, LambdaExpression lambda)
at System.Linq.Expressions.ExpressionCompiler.Generate(ILGenerator gen, Expression node, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.GenerateArgs(ILGenerator gen, ParameterInfo[] pis, ReadOnlyCollection`1 args)
at System.Linq.Expressions.ExpressionCompiler.GenerateNew(ILGenerator gen, NewExpression nex, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.Generate(ILGenerator gen, Expression node, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.GenerateArgs(ILGenerator gen, ParameterInfo[] pis, ReadOnlyCollection`1 args)
at System.Linq.Expressions.ExpressionCompiler.GenerateMethodCall(ILGenerator gen, MethodInfo mi, ReadOnlyCollection`1 args, Type objectType)
at System.Linq.Expressions.ExpressionCompiler.GenerateMethodCall(ILGenerator gen, MethodCallExpression mc, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.Generate(ILGenerator gen, Expression node, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.GenerateConvert(ILGenerator gen, UnaryExpression u)
at System.Linq.Expressions.ExpressionCompiler.Generate(ILGenerator gen, Expression node, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.GenerateLambda(LambdaExpression lambda)
at System.Linq.Expressions.ExpressionCompiler.CompileDynamicLambda(LambdaExpression lambda)
at System.Linq.Expressions.Expression`1.Compile()
at SubSonic.Linq.Structure.DbQueryProvider.Execute(Expression expression)
at SubSonic.Linq.Structure.QueryProvider.System.Linq.IQueryProvider.Execute(Expression expression)
at SubSonic.Linq.Structure.Query`1.GetEnumerator()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at WebApplication1._Default.Page_Load(Object sender, EventArgs e)
at System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e)
at System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e)
at System.Web.UI.Control.OnLoad(EventArgs e)
at System.Web.UI.Control.LoadRecursive()
at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

1
您没有 ReflectionPermission(ReflectionPermissionFlag.MemberAccess) 权限以访问非公共成员。 - Jaroslav Jandek
@Jaroslav - 我知道这是错误的原因,我正在努力找出需要该权限的原因以及如何绕过它,如果可能的话。 - Adam Cooper
1
@Adam:如果你使用了任何非公共成员(属性、字段、方法、构造函数),请尝试在没有它们的情况下运行代码(如果可能的话)。甚至外部参数也可能导致这种问题。试着“反射”使用的类…… - Jaroslav Jandek
1
@Jaroslav - 虽然技术上是正确的,但它实际上与任何非可见方法的直接使用无关;这是一个微妙的问题,涉及将 Type 实例嵌入表达式中——RuntimeType(用于运行时反射类型实例)是内部的,并且它导致 StrongBox<T> 失败。 - Andras Zoltan
2
@Andras:听起来很有可能。 快速查看堆栈跟踪表明,是这段代码 ChangeType(r0.GetValue(0), System.Int32) 的问题。也许使用替代方法,如 ChangeTypeTo<T> ,可以解决问题——这取决于SubSonic的实现方式。 - Jaroslav Jandek
@Jaroslav:使用泛型是个好主意。我在我的答案中找到了另一个解决方案,可以调用Expression.Constant([type instance], typeof(Type))而不是调用Expression.Constant([type instance]),这样代码生成函数就会反映出反射友好的Type而不是RuntimeType - Andras Zoltan
1个回答

15
这里的潜在问题是传递给 System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes) 的类型要么不是公开的,要么具有不公开的构造函数。

现在 - 鉴于你的代码示例的简单性与堆栈跟踪的深度,我认为问题不在于 plan,而是在于 plan 中的表达式(因为你在 Marc 的回答中的评论中说这也是一个表达式),该表达式引用了受限制的类型。

这里产生错误的表达式是一个 ConstantExpression,必须是受限制的类型。

然而唯一令人困惑的是,AddGlobal 传递给 Activator.CreateInstance 的类型参数是 StrongBox<T>,它是公开的并且有一个公开的构造函数-这意味着这个错误是不可能的。

也许,与 StrongBox<T> 相关联的某些隐藏信息我们无法通过 Reflector 看到。

因此,我会查看由 plan 表示的整个表达式树,并检查所有在 ConstantExpression 中引用的类型,以确保它们都是可访问的。如果在做完所有这些检查之后,仍然出现此错误,则可能是框架中的一个 bug。

但是 - 对于像 ConstantExpression 这样简单的东西,我认为这样的 bug 应该已经被发现了!

编辑(替换前面的编辑)附答案

我明白了,这是一个非常微妙的问题。你可以在配置为在中等信任级别下运行的 aspx 页面中使用以下代码重现:

Type t = typeof([any type you fancy]);
Expression expr = Expression.Constant(t);
var lambda = Expression.Lambda<Func<Type>>(expr);
var del = lambda.Compile();
Response.Write(del().ToString());

因此,在您提供的代码中,它是表示传递给ChangeType的第二个参数的表达式(我花了一段时间才意识到那是一个Sub Sonic方法),它似乎是一个Type(看不到代码,但我认为这是一个合理的猜测!)。
它作为Type实例的ConstantExpression嵌入表达式中。请不要问我如何缩小参数范围——需要大量的堆栈爬取和反射工作 ;)
正如我答案的前半部分所提到的,很难看出表达式树编译器使用的代码如何会创建MethodAccessException,因为它总是访问StrongBox类型的公共ctor。
然而,如果传递给泛型的类型不是public,它就会感到不满。但是,你说:“Type是public的!"
可能是这样,但在运行时从typeof()或GetType()返回的Type实例不是public - 它是RuntimeType的实例 - 这是内部的。
这也是为什么上面的代码片段也会触发相同的错误。
解决方法
更改为生成ChangeType(,)的Type参数的代码
Expression.Constant([type])

我几乎可以保证它(指IT技术相关内容)目前正在进行中,以便于

Expression.Constant([type], typeof(Type))

这是有效的,因为您明确地告诉编译器使用公共Type常量,而不是RuntimeType的反射类型。

您可以通过将此修复应用于我在上一个区块中的示例代码并重新运行来测试此修复。


谢谢,这真的很有帮助。你有没有快速追踪无法访问类型的建议?我相当自信这不是框架的错误,但我发现精确定位确切原因是一个重大挑战。 - Adam Cooper
@Andras - 这太棒了,谢谢,我会告诉你我的进展的 :) - Adam Cooper
@Adam:哦,亲爱的,这有点奇怪……堆栈跟踪不会说谎,因此可能这是一些更大的问题。在中等信任级别下生成代码存在一些问题(第一个评论者在您的问题上提到的RestrictedMemberAccess权限),但Expression Trees的MSDN文档并未提到需要任何特殊的要求才能实际执行任何操作。您可以尝试请求RestrictedMemberAccess权限-我只是看不出您实际需要它的任何原因... - Andras Zoltan
@Adam - 没问题 - 这是一个有趣的 bug,很高兴能帮到你。祝你在 Subsonic 的工作顺利 :) - Andras Zoltan
3
这个问题很遗憾不为人知,因为这样高质量的回答应该获得更多的赞。 - Mark Rendle
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接