8

我们最近有几次提出这样的问题:在 Dynamics CRM 2011 中,是否Execute()保证一个插件执行(即方法的传递)保持在同一个线程上。

我想使用环境上下文模式来实现跟踪,以避免将跟踪服务传递给任何可能想要跟踪的类。问题是我们知道插件每个注册步骤只实例化一次,然后从同一个实例提供所有后续操作;这意味着我不能只拥有一些像Tracing.Current我分配当前ITracingService实例的静态属性,我很高兴。如果我这样做了,最后开始的操作将覆盖所有其他可能仍在运行的操作的实例(这种并发并不少见)。

现在,如果我可以确定Execute()方法下的所有内容都保留在同一个线程中,我仍然可以使用环境上下文,利用[ThreadStatic]静态字段的属性:

public static class Tracing
{
    [ThreadStatic]
    private static ITracingService _current;

    public static ITracingService Current
    {
        get
        {
            if (null == _current)
            {
                _current = new NullTracingService();
            }

            return _current;
        }

        set { _current = value; }
    }
}

我会在输入Execute()方法时设置它并在最后清除它,以便删除对跟踪服务实例的引用。

在 MSCRM 插件的上下文中,我唯一能找到的关于线程的事情是,显然各个线程来自 ThreadPool - 无论对我的问题可能产生什么后果。

有没有人更深入地了解如何使用 MSCRM 插件处理线程 - 或者关于如何在这种特殊情况下使用 SOLID 代码优雅地处理跟踪的横切关注点的任何其他想法(AOP/动态拦截在这里没有选项)?

感谢您的任何帮助和指点。

4

3 回答 3

3

简单而聪明的答案:如果你这样做会很痛,那就不要那样做。:)

您对使用环境上下文模式的自我要求与 CRM 的设计模式相冲突。想一想 CRM 是如何工作的——它为您传递了一个IServiceProvider您需要的一切,包括跟踪服务。它为您处理所有复杂的多线程和优化,并且只要求您不要试图用花哨的模式或静态变量或线程技巧来超越它。

我的建议是使用相同的模式 - 将 传递IServiceProvider给任何需要它的类或方法。简单得多 - 再加上以后遇到奇怪的错误时,您不会质疑您是否成功地超越了微软的工程师。:)

于 2012-12-15T20:00:07.470 回答
1

CRM 创建单个插件对象,然后根据需要使用线程来处理请求。因此,您唯一可以确定的是,您将同时为单个插件对象运行多个线程。

线程是通过 IIS 管理的,如果可能的话将被重用。所以如果你想确保每次Execute被调用,它都有一个新的ITracingService,你必须设置它。如果你只是想确保每次Execute被调用,它都有一个,你只需要做一个if语句来检查它。

由于您的后备变量是ThreadStatic,因此您无需担心线程问题,但由于 IIS 尝试重用线程,因此每次Execute调用它都不会为空。

于 2012-12-17T14:09:11.317 回答
0

恐怕我只能在这里猜测整个插件/线程/静态问题,但是您提出的建议确实有点复杂。因此,作为替代方案,您是否考虑过使用跟踪侦听器?

如果您Trace.Writeline在整个应用程序中使用,那么单个跟踪侦听器将捕获所有这些消息。这样您就不必传递跟踪对象。

例如:

Execute(...)
{
    if(System.Diagnostics.Trace.Listeners
        .Count(l => typeof(l) == MyCustomTraceListener) == 0)
    {
        System.Diagnostics.Trace.Listeners.Add(new MyCustomTraceListener());
    }

    DoWork();
}

DoWork()
{   
    System.Diagnostics.Trace.WriteLine("I'm doing work!");
}

相关链接:

跟踪侦听器演练:创建自定义跟踪侦听器

于 2012-12-16T11:31:39.450 回答