Expression<TDelegate>.在中等信任环境中编译

Posted

技术标签:

【中文标题】Expression<TDelegate>.在中等信任环境中编译【英文标题】:Expression<TDelegate>.Compile in Medium Trust environment 【发布时间】:2011-03-12 19:14:26 【问题描述】:

尝试在中等信任的 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)

【问题讨论】:

您没有ReflectionPermission(ReflectionPermissionFlag.MemberAccess) 访问非公共成员。 @Jaroslav - 我知道这是错误的原因,我正在尝试找出需要该权限的原因以及如何绕过它,如果可能的话。 @Adam:如果您使用任何非公共成员(属性、字段、方法、构造函数),请尝试不使用它们(如果可以)。即使是外部参数也可能导致这种行为。尝试围绕使用的类“反映”... @Jaroslav - 虽然在技术上是正确的 - 它实际上与直接使用任何不可见的方法无关;将 Type 实例烘焙为表达式是一个微妙的问题 - RuntimeType(用于运行时的所有反射类型实例)是内部的,它导致 StrongBox&lt;T&gt; 爆炸。 @Andras:听起来很可能。快速查看堆栈跟踪表明这是代码ChangeType(r0.GetValue(0), System.Int32)。也许使用像ChangeTypeTo&lt;T&gt; 这样的替代方法可以解决这个问题——不过这取决于 SubSonic 的实现。 【参考方案1】:

这里的根本问题是传递给System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes) 的类型不是公共的,或者有一个非公共的构造函数。

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

这里的错误源表达式是ConstantExpression,它必须是受限类型。

然而,唯一令人困惑的是AddGlobal 传递给Activator.CreateInstance 的类型参数是StrongBox&lt;T&gt;,它是公共的并且有一个公共构造函数——这意味着这个错误应该是不可能的。

不过,也许有一些与 StrongBox&lt;T&gt; 相关的隐藏内容,我们无法通过 Reflector 看到。

因此,我将查看plan 表示的整个表达式树,并检查ConstantExpressions 中引用的所有类型,以确保它们都可以访问。如果这样做之后所有类型都显示为可访问,但仍然出现此错误,则可能是框架中的错误。

但是 - 我原以为像 ConstantExpression 这样简单的东西已经发现了这样的错误!

编辑(替换以前的编辑)有答案

我明白了,这是一个非常微妙的问题。您可以在配置为以中等信任度运行的 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(可以'没有看到代码,但我认为这是一个合理的猜测!)。

它在表达式中被烘焙为 ConstantExpressionType 实例。不要问我是如何缩小参数范围的——大量的堆栈爬取和反射器工作;)

正如我在回答的前半部分中提到的,很难看出 Expression Tree 编译器使用的代码如何创建 MethodAccessException,因为它总是访问 StrongBox&lt;T&gt; 类型的公共 ctor。

但是,如果作为泛型传入的类型不是公共的,则会感到不安。 “但是等等,”你说,“Type 是公开的!”。

可能是这样,但在运行时从 typeof()GetType() 返回的 Type 实例不是 - 它是 RuntimeType 的实例 - 内部

这也是为什么上面的代码sn-p也会触发同样的错误。

修复

更改为ChangeType(,) 生成Type 参数的代码

Expression.Constant([type])

(我几乎可以保证现在是这样)到

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

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

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

【讨论】:

谢谢,这真的很有帮助,你有什么快速追踪不可访问类型的建议吗?我很确定这不是框架错误,但我发现查明确切原因是一项重大挑战。 嗯...好吧,我考虑过如何做到这一点。也许您可以使用表达式访问者来查找ConstantExpression,其类型要么不是公共的,要么具有至少一个非公共构造函数——这应该会缩小范围。 MSDN 有一个示例表达式访问者的链接。我会看一下并将其发布在答案上。 @Adam - 我已经用一些代码更新了我的答案,这些代码可能可以帮助您诊断,以及来自 MSDN 的链接,您需要表达式树访问者。它并不完美 - 但我希望它能让你走上正轨:) @Andras - 太棒了,谢谢,我会告诉你我的进展情况:) 很遗憾这是一个晦涩难懂的问题,因为这种质量的答案值得更多的投票。

以上是关于Expression<TDelegate>.在中等信任环境中编译的主要内容,如果未能解决你的问题,请参考以下文章

表达式目录树

Expression经验之二:LambdaExpression变换

为什么Expression.Call抛出参数错误

[Regex Expression] Find Sets of Characters

warning: left-hand operand of comma expression has no effect for语句中编译错误,求原因

vue template 里使用可选链操作符( ?. )报错:Errors compiling template:invalid expression: Unexpected token ‘.‘ i