我们最近遇到过几次这样的问题:在 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/动态拦截不是选项)这里)?
感谢您的帮助和指点。
最佳答案
简单而聪明的回答:如果你这样做会痛,那就不要那样做。 :)
您使用环境上下文模式的 self 强加要求与 CRM 的设计模式冲突。想一想 CRM 的工作原理 - 它向您传递一个 IServiceProvider
,其中包含您需要的一切,包括跟踪服务。它为您处理所有复杂的多线程和优化,只要求您不要试图用花哨的模式、静态变量或线程技巧来超越它。
我的建议是使用相同的模式 - 将 IServiceProvider
传递给任何需要它的类或方法。简单得多——再加上以后当你遇到一个奇怪的错误时,你不会怀疑你是否成功地智胜了微软的工程师。 :)
关于c# - CRM 2011 插件中的线程/环境上下文,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13886017/