为什么要调用 OrganizationServiceProxy.Dispose()

本文关键字:Dispose OrganizationServiceProxy 调用 为什么 | 更新日期: 2023-09-27 18:37:23

不调用 有什么后果。Dispose() on a OrganizationServiceProxy 对象?

有时,在测试期间,代码在释放对象之前崩溃;这是否意味着服务通道永远保持打开状态?

我对 OrganizationServiceContext 有同样的问题,直到今天读到这篇文章我才开始处理这个问题。

    /* Synchronizes with CRM * */
    public class CRMSync
    {
        [ThreadStatic] // ThreadStatic ensures that each thread gets a copy of these fields
        private static OrganizationServiceProxy service;
        [ThreadStatic]
        private static Context linq;
        /* Tries to connect to CRM and return false if failure - credentials arguments */
        private bool Connect(string username = @"username", string password = "password", string uri = @"orgUrl/XRMServices/2011/Organization.svc")
        {
            try
            {
                var cred = new ClientCredentials();
                cred.UserName.UserName = username;
                cred.UserName.Password = password;
                service = new OrganizationServiceProxy(new Uri(uri), null, cred, null);
                service.EnableProxyTypes(); // this has to happen to allow LINQ early bound queries
                linq = new Context(service);
                var who = new Microsoft.Crm.Sdk.Messages.WhoAmIRequest(); // used to test the connection
                var whoResponse = (Microsoft.Crm.Sdk.Messages.WhoAmIResponse)service.Execute(who); // this fails if not connected       
            }
            catch (Exception e)
            {
                Log(e.Message); // Write to Event Log
                return false;
            }
            return true;
        }
    }

有没有另一种方法可以在多种方法中使用相同的 OrganizationServiceContext 和 OrganizationServiceProxy?

我计划使用此析构函数来处置 OrganizationServiceProxy 和 OrganizationServiceContext:

    ~CRMSync()
    {
        if (service != null)
            service.Dispose();
        if(linq!=null)
            linq.Dispose();
    }

编辑

这是由服务 OnStart 调用的方法

    /* Called by CRMAUX.OnStart when it is time to start the service */
    public async void Start()
    {
        this.ProcessCSVFiles(); // Creates a ThreadPool thread that processes some CSV files
        this.ProcessCases(); // Imports cases into CRM from a db (on this thread)
        var freq = 0;
        ConfigurationManager.RefreshSection("appSettings");
        var parse = int.TryParse(ConfigurationManager.AppSettings["Frequency"], out freq);
        await System.Threading.Tasks.Task.Delay((parse) ? freq * 1000 * 60 : 15000 * 60); // 15 minutes default or user defined
        Start(); // Start again after the wait above
    }

这是视窗服务

public partial class CRMAUX : ServiceBase
{
    private CRMSync crmSync;
    public CRMAUX()
    {
        InitializeComponent();
    }
    protected override void OnStart(string[] args)
    {
        ConfigurationManager.RefreshSection("userSettings"); // Get the current config file so that the cached one is not useds
        if (TestConfigurationFile())
        {
            crmSync = new CRMSync();
            Thread main = new Thread(crmSync.Start);
            main.IsBackground = true;
            main.Start();
        }
        else //The configuration file is bad
        {
            Stop(); // inherited form ServiceBase
            return;
        }
    }
    protected override void OnStop()
    {            
    }
    /* Checks the configuration file for the necessary keys */
    private bool TestConfigurationFile()...
}

为什么要调用 OrganizationServiceProxy.Dispose()

OrganizationServiceProxy是利用非托管资源(套接字等)的 WCF 通道的包装器。

实现IDisposable的类(我们的代理)本质上是声明它将访问非托管资源,因此您应该在完成它时明确告诉它,而不仅仅是允许它超出范围。 这将允许它释放这些资源的句柄,并释放它们以供其他地方使用。 不幸的是,我们的代码并不是服务器上运行的唯一内容!

非托管资源是有限且昂贵的(SQL 连接是典型的示例)。 如果您的代码正确执行,但您没有显式调用 dispose 那么这些资源的清理将是不确定的,这是一种奇特的说法,垃圾回收器只会"最终"调用这些托管对象上的 dispose,这将依次清理它们所持有的非托管资源。 这将损害应用程序以及在可能与您争用这些资源的同一硬件上运行的任何其他服务的可伸缩性。 这是最好的情况,如果在获取这些资源之后在堆栈中的任何时间点发生异常,则不会释放它们,因此内存泄漏和可用于其他地方的资源更少。

将代码包装在 using 语句中是语法糖,因为这会编译为代理被包装在 try/finally 中,并在 finally 中调用释放。

在跨多种方法使用代理/上下文方面,您应该查看工作单元模式。 OrganizationServiceContext就是这样,您可以在请求过程中(可能跨多个方法调用)应用更改,然后在完成后提交到数据存储(CRM),在我们的例子中使用context.SaveChanges()

您在哪里使用此代码,因为我很想知道您希望使用 [ThreadStatic] 属性实现什么? 如果它在IIS托管应用程序中,我认为您不会看到任何好处,因为您不管理线程池,因此代理仍然只有与HttpRequest匹配的生存期。 如果是这种情况,有几种更好的方法来管理这些对象的生存期,依赖注入框架和HttpRequest生存期行为是显而易见的。

如果您的应用程序崩溃,操作系统将自动回收您的所有资源,即关闭所有网络端口、文件等。所以没有什么是永远开放的。当然,在服务器端,如果处理不当并且应用程序在请求过程中崩溃,则可能会发生意外情况。但这就是事务的用途,因此服务器数据的状态始终是一致的。