Выражение <TDelegate>. Компилировать в среде Medium Trust - PullRequest
9 голосов
/ 07 июля 2010

При попытке скомпилировать Expression в веб-приложении со средним уровнем доверия я получаю исключение MethodAccessException.Кто-нибудь знает другой способ скомпилировать выражение со средним доверием или обходной путь, чтобы избежать этого исключения?

Код, который вызывает исключение:

Expression<Func<object>> efn = 
  Expression.Lambda<Func<object>>(Expression.Convert((plan,typeof(object)));

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

План переменных - это выражение, котороепредставляет следующий план выполнения:

{
  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 Ответ

15 голосов
/ 07 июля 2010

Основная проблема здесь в том, что тип, передаваемый в System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes), либо не является общедоступным, либо имеет конструктор, который не является общедоступным.

Теперь - учитывая простоту вашего примера кода и глубинутрассировка стека, я полагаю, проблема не в plan, а в выражении в plan (поскольку вы говорите в своем комментарии к ответу Марка, что это тоже выражение), которое ссылается на тип, который затем ограничивается.

Выражение, которое здесь является источником ошибки, это ConstantExpression, который должен иметь ограниченный тип.

Единственное, что сбивает с толку, это то, что аргумент типа, который AddGlobalпереходит к Activator.CreateInstance is StrongBox<T>, который является общедоступным и имеет открытый конструктор - что подразумевает, что эта ошибка должна быть невозможной.

Возможно, однако, есть что-то скрытое, связанное с StrongBox<T>, что мыне могу видеть через Reflector.

Итак, я бы посмотрел на все дерево выражений, представленное plan, и исследовал всетипы, указанные в ConstantExpression s, чтобы гарантировать, что они все доступны.Если после этого все типы показаны как доступные, эта ошибка по-прежнему возникает, то это может быть ошибка в платформе.

Однако - я бы подумал, что такая ошибка уже была бы найдена для чего-топросто как 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 (код не виден, но я думаю, что это разумное предположение!).

Этозапекается в выражении как ConstantExpression экземпляра Type.Не спрашивайте, как я сузил параметр - много работы по сканированию стека и отражателю;)

Как упоминалось в первой половине моего ответа, трудно понять, как код, используемый компилятором дерева выражений, можеткогда-либо создавать исключение MethodAccessException, так как оно всегда обращается к общедоступному ctor типа StrongBox<T>.

Однако это будет расстроено, если тип, переданный как универсальный, не является общедоступным.«Но подождите, - говорите вы, - Type общедоступно!».

Может быть, но экземпляр Type, возвращаемый во время выполнения из typeof() или GetType(), не является - этоэкземпляр RuntimeType - который является внутренним .

. Именно поэтому приведенный выше фрагмент кода также вызовет ту же ошибку.

Исправление

Измените код, который выдает аргумент Type для ChangeType(,), с

Expression.Constant([type])

(что я почти гарантирую, что это так на данный момент) на

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

Это работает, потому что вы явно указываете компилятору использовать общедоступную Type для константы вместо отраженного типа RuntimeType.

Вы можете проверить это исправление, применивэто к моему примеру кода в предыдущем блоке и повторного запуска.

...