2010-07-07 11 views
9

Podczas próby skompilowania wyrażenia w aplikacji sieciowej średniego zaufania uzyskuję wyjątek MethodAccessException. Czy ktoś wie o innym sposobie kompilacji wyrażenia w ramach średniego zaufania lub obejścia, aby uniknąć tego wyjątku?Wyrażenie .Kompilowanie w środowisku średniego zaufania

kod, który zgłasza wyjątek:

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

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

Zmienna planie jest wyrażenie, które reprezentuje następujący plan wykonania:

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

Pełne śledzenia stosu:

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

Nie masz "ReflectionPermission (ReflectionPermissionFlag.MemberAccess)", aby uzyskać dostęp do członków niepublicznych. –

+0

@Jaroslav - Wiem, że to jest przyczyna błędu. Próbuję ustalić, co to jest, że wymaga tego pozwolenia i jak je obejść, jeśli to możliwe. –

+1

@Adam: jeśli używasz żadnych niepublicznych członków (właściwości, pola, metody, konstruktorzy), spróbuj bez nich (jeśli możesz). Nawet zewnętrzne parametry mogą powodować takie zachowanie. Staraj się "rozmyślać" wokół używanych klas ... –

Odpowiedz

15

Podstawowy problem polega na tym, że typ jest przekazywany do System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes) nie jest publiczne lub ma konstruktor, który nie jest publiczny.

Teraz - biorąc pod uwagę prostotę swojej przykład kodu w funkcji głębokości stacktrace Wierzę, że problem nie leży w plan, ale w wyrażeniu w plan (ponieważ mówisz w swoim komentarzu na odpowiedź Marca, że ​​jest również wyrazem), który odwołuje się do typu, który jest następnie ograniczony.

Wyrażenie, które jest źródłem tego błędu, to ConstantExpression, które musi być typu ograniczonego.

Jedynym mylące rzeczą jest jednak to, że argument typu, który AddGlobal przechodzi do Activator.CreateInstance jest StrongBox<T>, który jest publiczny i ma konstruktora publicznego - co oznaczałoby, że błąd ten powinien być niemożliwe.

Być może jednak coś ukrytego jest powiązane z StrongBox<T>, którego nie możemy zobaczyć przez Reflektor.

Tak więc powinienem przejrzeć całe drzewo wyrażeń reprezentowane przez plan i sprawdzić wszystkie typy wymienione w ConstantExpression s, aby upewnić się, że są one dostępne. Jeśli po wykonaniu tego wszystkie typy będą widoczne, błąd ten nadal występuje, może to być błąd w strukturze.

Jednak - pomyślałem, że taki błąd zostałby znaleziony już na coś tak prostego jak ConstantExpression!

EDIT (Wymiana Poprzedni Edit) z odpowiedzią

Mam go i to bardzo subtelny problem. można odtworzyć z tego małego kawałka kodu w stronę aspx, który jest skonfigurowany do pracy w średnim zaufania:

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

Więc w kodzie już dostarczonych, to wyrażenie reprezentujące Drugi argument ChangeType (wziął mi chwilę, aby zdać sobie sprawę, że jest to metoda Sub Sonic), która wydaje się być Type (nie widzę kodu, ale myślę, że to rozsądne zgadnięcie!).

Został wypalony w wyrażeniu jako ConstantExpression instancji Type.Nie pytaj, w jaki sposób zawęziłem parametr - wiele wątków pełzających i reflektorów działa;)

Jak wspomniano w pierwszej połowie mojej odpowiedzi, trudno jest zobaczyć, w jaki sposób kod, który kompilator Expression Tree może kiedykolwiek stworzyć Wyjątek MethodAccessException, ponieważ zawsze uzyskuje dostęp do publicznego ctorka typu StrongBox<T>.

Jednak byłoby zdenerwować, jeśli typ przekazany jako rodzajowy nie jest publiczny. "Ale czekaj", mówisz, "Type jest publiczne!".

To może być, ale instancja Type zwrócony przy starcie z typeof() lub GetType() nie jest - to wystąpienie RuntimeType - co jest wewnętrzny.

Z tego powodu powyższy fragment kodu wywoła również ten sam błąd.

Rozwiązaniem

Zmień kod, który produkuje Type argument ChangeType(,) z

Expression.Constant([type]) 

(który ja niemal gwarancja, że ​​jest w tej chwili) do

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

To działa, ponieważ wyraźnie mówisz kompilatorowi, aby używał publicznego Type dla stałej, zamiast odbitego typu RuntimeType.

Możesz przetestować tę poprawkę, stosując ją do mojego kodu przykładowego w poprzednim bloku i ponownie uruchomić.

+0

Dzięki temu, że to naprawdę pomocne, czy masz jakieś sugestie na temat szybkiego znalezienia dostępnych typów? Jestem przekonany, że to nie jest błąd związany ze strukturą, ale znajduję dokładną przyczynę znaczącego wyzwania. –

+0

Hmmm ... cóż, zastanawiałem się, jak możesz to zrobić. Być może możesz użyć gościa, który wyszukuje wyrażenie "ConstantExpression", którego typ nie jest publiczny lub ma co najmniej jeden niepubliczny konstruktor, który powinien go zawęzić. MSDN ma link do przykładowego użytkownika wyrażenia. Przyjrzę się i opublikuję odpowiedź. –

+0

@Adam - Zaktualizowałem swoją odpowiedź za pomocą kodu, który może pomóc w diagnozowaniu, wraz z linkiem z MSDN, który będzie potrzebny dla użytkownika drzewa wyrażeń. To nie jest perfekcyjne - ale powinno Cię po drodze dobrze mieć Mam nadzieję :) –

Powiązane problemy