2010-07-07 10 views
9

Lorsque j'essaie de compiler une expression dans une application Web de confiance moyenne, j'obtiens une exception MethodAccessException. Est-ce que quelqu'un sait d'une autre façon de compiler une expression sous confiance moyenne ou une solution de contournement pour éviter cette exception?Expression <TDelegate> .Compiler dans un environnement de confiance moyenne

Le code qui lève l'exception:

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

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

Le plan variable est une expression qui représente le plan d'exécution suivant:

{ 
    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 [] {} 
) 
} 

La pleine trace de la pile:

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

Vous n'avez pas 'ReflectionPermission (ReflectionPermissionFlag.MemberAccess)' pour accéder aux membres non publics. –

+0

@Jaroslav - Je sais que c'est la cause de l'erreur que je suis en train d'essayer de savoir sur ce qui nécessite cette autorisation et comment la contourner, si c'est possible. –

+1

@Adam: si vous utilisez des membres non publics (propriétés, champs, méthodes, constructeurs), essayez-les sans eux (si vous le pouvez). Même les paramètres externes peuvent provoquer un tel comportement. Essayez de "refléter" autour des classes utilisées ... –

Répondre

15

Le problème sous-jacent ici est que le type étant passé à System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes) n'est pas public ou a un constructeur qui n'est pas public.

maintenant - étant donné la simplicité de votre exemple de code par rapport à la profondeur de la stacktrace Je crois que le problème ne réside pas dans plan, mais dans une expression au sein plan (puisque vous dites dans votre commentaire sur la réponse de Marc qu'il est aussi une expression) qui fait référence au type qui est alors restreint.

L'expression qui est la source de l'erreur est ConstantExpression qui doit être de type restreint.

La seule chose confusion à ce sujet, cependant, est que l'argument de type qui passe à AddGlobalActivator.CreateInstance est StrongBox<T>, qui est public et a un constructeur public - ce qui impliquerait que cette erreur devrait être impossible.

Peut-être, cependant, il y a quelque chose de caché associé à StrongBox<T> que nous ne pouvons pas voir à travers Reflector. Donc, je regarderais tout l'arbre d'expression représenté par plan et j'examinerais tous les types référencés dans ConstantExpression s pour m'assurer qu'ils sont tous accessibles. Si après cela tous les types sont montrés être accessibles, cette erreur survient alors alors il pourrait être un bug dans le framework.

Cependant - j'aurais pensé qu'un tel bug aurait déjà été trouvé pour quelque chose d'aussi simple qu'un ConstantExpression!

EDIT (Remplacement Edition précédente) AVEC LA RÉPONSE

Je l'ai, et il est un problème très subtil. Vous pouvez reproduire avec ce petit bout de code dans une page ASPX qui est configuré pour fonctionner en confiance moyenne:

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()); 

Ainsi, dans le code que vous avez fourni, il est l'expression qui représente le deuxième argument à ChangeType (pris moi un moment pour réaliser que c'est une méthode Sub Sonic), qui semble être un Type (ne peut pas voir le code mais je pense que c'est une supposition raisonnable!).

Il est cuit dans l'expression en tant que ConstantExpression d'une instance Type.Ne demandez pas comment j'ai réduit le paramètre - beaucoup d'exploration de pile et travail de réflecteur;)

Comme mentionné dans la première moitié de ma réponse, il est difficile de voir comment le code utilisé par le compilateur Expression Tree peut jamais créer une exception MethodAccessException, puisqu'elle accède toujours au ctor public du type StrongBox<T>. Cependant, il se fâcherait si le type était transmis car le générique n'est pas public. "Mais attendez", vous dites, "Type est public!".

Cela pourrait être, mais l'instance Type retourné lors de l'exécution de typeof() ou GetType() n'est pas - c'est une instance de RuntimeType - qui est interne.

C'est également la raison pour laquelle l'extrait de code ci-dessus déclenchera la même erreur.

Le correctif

Modifier le code qui produit l'argument Type pour ChangeType(,) de

Expression.Constant([type]) 

(que je vais presque garantir qu'il est à l'heure actuelle) à

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

Cela fonctionne, parce que vous dites explicitement au compilateur d'utiliser le public Type pour la constante, au lieu du type reflété de RuntimeType.

Vous pouvez tester ce correctif en l'appliquant à mon exemple de code dans le bloc précédent et en le réexécutant.

+0

Merci, c'est vraiment utile, avez-vous une suggestion sur un moyen rapide de traquer les types non accessibles? Je suis assez confiant que ce n'est pas un bug d'infrastructure, mais je trouve que le fait de déterminer la cause exacte représente un défi important. –

+0

Hmmm ... Eh bien, j'ai réfléchi à la façon dont vous pourriez faire cela. Peut-être pouvez-vous utiliser un visiteur d'expression qui recherche "ConstantExpression" dont le type n'est pas public ou qui a au moins un constructeur non-public qui devrait le réduire. MSDN a un lien vers un exemple de visiteur d'expression. Je vais jeter un coup d'oeil et le poster sur la réponse. –

+0

@Adam - J'ai mis à jour ma réponse avec du code qui pourrait vous aider à diagnostiquer, à côté de ce lien du MSDN dont vous aurez besoin pour un visiteur de l'arbre d'expression. Ce n'est pas parfait - mais il devrait vous mettre sur votre chemin assez bien j'espère :) –

Questions connexes