1

我正在尝试编写一个 MS Dynamics CRM 2011 插件以在沙盒模式下运行,但使用来自 GAC 程序集的类。我遇到了一个问题,即从 GAC 程序集创建类型列表会产生错误,我不明白为什么。生成的异常属于类型System.MethodAccessException并具有以下消息:

Attempt by method 'IsolatedModeExceptionsTestingPlugin.Plugin.Execute(System.IServiceProvider)' to access method 'System.Collections.Generic.List`1<System.__Canon>..ctor()' failed.

有人可以解释为什么这会失败,以便我可以修改我的代码/环境来解决失败吗?

我在下面的一组简单的类中重新创建了场景。

我在运行 Dynamics 2011 Rollup 7 的 Win2008 R2 服务器上运行了测试,然后在 Rollup 11 上再次运行了测试。我的两个程序集都是针对 .Net 4.0 构建的,并且 Dynamics IIS AppPool 是为 .Net 4 配置的。两个程序集都已签名(使用相同的密钥对)。

请注意,如果我将插件的隔离模式从“沙盒”更改为“无”,插件可以正常工作——只有在沙盒模式下才会发生这种情况,这意味着在生成 List<> 时会出现某种安全违规。另请注意,创建一个 List(或其他 .Net 类型)可以正常工作,就像在我自己​​的程序集中创建一个 List<> 类一样。它似乎特定于 GAC 的程序集。

我在 GAC 中放置的程序集名为“ClassLibrary1”,仅包含一个类:

namespace ClassLibrary1
{    
    public class MyCustomAssemblyClass
    {
        public string GetAString()
        {
            return "The current time is " + System.DateTime.Now.ToString();
        }
    }
} 

我通过在服务器(安装了 Windows SDK v7.1)上运行以下命令将它放在 GAC 中:"c:\program files\Windows SDKs\Windows\v7.1\bin\NETFX 4.0 Tools\gacutil.exe" -i classlibrary1.dll

我的插件代码如下所示:

using System.Collections.Generic;
using System.Text;
using System;
using ClassLibrary1;
using Microsoft.Xrm.Sdk;

namespace IsolatedModeExceptionsTestingPlugin
{
    public class Plugin : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {            
            var pluginExecutionContext = (IPluginExecutionContext) serviceProvider.GetService(typeof (IPluginExecutionContext));
            var tracingService = (ITracingService) serviceProvider.GetService(typeof (ITracingService));

            try
            {
                tracingService.Trace("Entered Plugin.Execute()");
                tracingService.Trace(string.Format("Isolation Mode: {0}, Mode: {1}\n\n",
                                                   pluginExecutionContext.IsolationMode,
                                                   pluginExecutionContext.Mode));

                try
                {                    
                    tracingService.Trace(string.Format("*** Creating List<{0}>", typeof (MyCustomAssemblyClass)));
                    var list = new List<MyCustomAssemblyClass>(); //XXX Exception thrown here!!
                    tracingService.Trace("    Success");
                }
                catch (Exception ex)
                {                    
                    tracingService.Trace(GetExpectionTraceMessage(ex));
                    throw new Exception("An error occurred in one of the tests", ex);
                }
                finally
                {
                    tracingService.Trace("*** Finished TestListOfGACClassCxtr\n\n");
                }

                //This will force a failure to allow viewing of the trace file
                //    throw new Exception("TEST SUCCESSFULL");                

            }           
            finally
            {
                tracingService.Trace("Exiting Plugin.Execute()");
            }
        }


        private string GetExpectionTraceMessage(Exception ex)
        {
            var message = new StringBuilder();
            message.AppendFormat("EXCEPTION: {0}\n", ex.GetType());
            message.AppendFormat("\tMessage: {0}\n", ex.Message);
            message.AppendFormat("\tStack: {0}\n", ex.StackTrace);

            if (ex.InnerException != null)
            {
                message.AppendLine("---- INNER EXCEPTION ----");
                message.AppendLine(GetExpectionTraceMessage(ex.InnerException));
            }

            return message.ToString();
        }

    }
}

当实体更新时,我将插件注册为在数据库中以沙盒模式运行。执行插件后,我通过“业务流程错误”对话框的“下载日志文件”获得以下输出:

Unhandled Exception: System.ServiceModel.FaultException`1[[Microsoft.Xrm.Sdk.OrganizationServiceFault, Microsoft.Xrm.Sdk, Version=5.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]: Unexpected exception from plug-in (Execute): IsolatedModeExceptionsTestingPlugin.Plugin: System.Exception: An error occurred in one of the testsDetail: 
<OrganizationServiceFault xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/xrm/2011/Contracts">
  <ErrorCode>-2147220956</ErrorCode>
  <ErrorDetails xmlns:d2p1="http://schemas.datacontract.org/2004/07/System.Collections.Generic" />
  <Message>Unexpected exception from plug-in (Execute): IsolatedModeExceptionsTestingPlugin.Plugin: System.Exception: An error occurred in one of the tests</Message>
  <Timestamp>2012-11-29T18:09:26.5671559Z</Timestamp>
  <InnerFault i:nil="true" />
  <TraceText>

[IsolatedModeExceptionsTestingPlugin: IsolatedModeExceptionsTestingPlugin.Plugin]
[6d245108-b638-e211-bae5-000c29d5e4ba: IsolatedModeExceptionsTestingPlugin.Plugin: Update of new_insurancequote]

Entered Plugin.Execute()
Isolation Mode: 2, Mode: 0


*** Creating List&lt;ClassLibrary1.MyCustomAssemblyClass&gt;
EXCEPTION: System.MethodAccessException
    Message: Attempt by method 'IsolatedModeExceptionsTestingPlugin.Plugin.Execute(System.IServiceProvider)' to access method 'System.Collections.Generic.List`1&lt;System.__Canon&gt;..ctor()' failed.
    Stack:    at IsolatedModeExceptionsTestingPlugin.Plugin.Execute(IServiceProvider serviceProvider)

*** Finished TestListOfGACClassCxtr


Exiting Plugin.Execute()


</TraceText>
</OrganizationServiceFault>

作为参考,.Net 框架似乎使用 System.__Canon 类型在 JIT 中为所有泛型创建可重用代码。见: http: //www.marklio.com/marklio/PermaLink,guid,1fa8a82b-a6d6-4fbb-8cca-5e352ff3c9e9.aspx

4

2 回答 2

1

隔离模式模仿 CRM Online。在 CRM Online 中,如果不检查低级别原因,您就无法从根本上添加到 GAC,我相信这就是您的代码失败的原因。

(因此我猜这List<>是一个红鲱鱼,即使实例化 GACed 类型的单个实例也会失败)

编辑

GAC 默认授予程序集完全信任。在沙盒/隔离模式下运行的插件在部分信任下运行 - 这就是为什么我不相信你MyCustomAssemblyClass在沙盒模式下运行时能够实例化(这就是我认为List<>无关紧要的原因)。

从下面我自己的评论中 - 我认为这种总结:

我认为这个问题从根本上是一个提升问题——即是否应该信任一个部分受信任的程序集(即插件,它的功能受到限制)来运行一个完全受信任的插件(它可以做任何事情)。如果允许部分信任的代码运行完全信任的代码,这似乎是合乎逻辑的,它将有效地提升部分信任的程序集的权限,从而产生漏洞。

于 2012-11-29T23:23:34.063 回答
0

查看此链接并尝试将允许部分受信任的调用者属性添加到您的 GAC。

最终,CRM 使用 .NET 4 中的 AppDomain 类(AppDomain 上的链接)并使用 AppDomain 运行沙盒插件。

我面临的挑战是,我找不到任何 Microsoft 文档清楚地说明 CRM 沙盒服务将哪些规则应用于它为执行插件而创建的 AppDomain。这使得在 GAC 中配置一个类以使其可由沙盒代码调用基本上是反复试验。

于 2012-11-30T18:28:53.447 回答