1

不在 OrganizationServiceProxy 对象上调用 .Dispose() 的后果是什么?

有时,在测试过程中,代码在对象被释放之前就崩溃了;这是否意味着服务渠道永远开放?

我对 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
    }

这是 Windows 服务

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()...
}
4

2 回答 2

2

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

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

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

将代码包装在 using 语句中是语法糖,因为它编译为代理被包装在 try/finally 中,而 dispose 在 finally 中被调用。

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

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

于 2013-10-31T00:36:19.373 回答
0

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

于 2013-10-30T11:55:01.190 回答