lundi 10 avril 2017

Dynamics CRM Reflection

I wish to use Reflection inside a Dynamics CRM Online plugin. I am aware that CRM Online uses a Medium-Trust environment, which does not allow Reflection. However, I also understand that Reflection within the same assembly is permitted - since it's within the same assembly, which can automatically trust itself.

Note that my CRM plugin solution contains several projects - therefore several DLLs outside CRM, but I'm using ILMerge to merge these together into 1 assembly for deployment to CRM. Therefore, this single assembly contains several different namespaces, however for the purposes of Reflection permissions this is just one assembly with different namespaces in it - nothing unusual about that, and should not cause reflection issue problems - AFAIK.

In my local testing environment, I have used http://ift.tt/2opFxID to setup a partial trust environment and to test my Reflection. In this testing environment, the assemblies are not merged with ILMerge but using the InternalsVisibleTo attribute I'm able to successfully do Reflection. The InternalsVisibleTo attribute stays there in the assembly which is the result of the ILMerge, but actually is not required since ILMerge creates just the one assembly.

This is the error that CRM is giving me:

Attempt by method 'Namespace1.QueryProvider.Evaluator+SubtreeEvaluator.GetValue(System.Linq.Expressions.MemberExpression)' to access field 'Namespace2.Entities.CreditTransaction+<>c__DisplayClass1_0.id' failed.: at System.Reflection.RtFieldInfo.PerformVisibilityCheckOnField(IntPtr field, Object target, RuntimeType declaringType, FieldAttributes attr, UInt32 invocationFlags)
at System.Reflection.RtFieldInfo.InternalGetValue(Object obj, StackCrawlMark& stackMark)
at System.Reflection.RtFieldInfo.GetValue(Object obj)
at Namespace1.QueryProvider.Evaluator.SubtreeEvaluator.GetValue(MemberExpression exp)

The method Namespace1.QueryProvider.Evaluator+SubtreeEvaluator.GetValue(System.Linq.Expressions.MemberExpression) does this:

private object GetValue(MemberExpression exp)
{
    if (exp.Expression is ConstantExpression)
    {
        return (((ConstantExpression)exp.Expression).Value).GetType().GetField(exp.Member.Name).GetValue(((ConstantExpression)exp.Expression).Value);
    }   
}

The field Namespace2.Entities.CreditTransaction+<>c__DisplayClass1_0.id is being passed in to the above method via the following expression and it refers to the id variable which from my reading is defined as internal by the compiler as part of the ClosureExpression:

Guid id = newTrans.Account.Id;
List<CreditTransaction> transactions = context.CreditTransactionSet.Where(ct => ct.Account.Id == id).OrderByDescending(ct => ct.CreatedOn).ToList();

Can anyone shed any light on this for me as to why it's not working (ie. a gap in my knowledge), or steer me towards a solution if my working theory is correct that reflection within the same assembly should be possible despite the trust environment?





Aucun commentaire:

Enregistrer un commentaire