为什么我必须使用Task <t>来实现同步调用?

时间:2017-03-07 23:42:56

标签: c# multithreading thread-safety dynamics-crm

我正在开发一个与Dynamics 365和Dynamics SDK集成的网站。我们在日志中看到了错误,例如“无法访问已处置的对象”。经过进一步调查,我们发现SDK方法不是线程安全的,因此需要重构代码以将其考虑在内。

我们有一个如下的方法,可以创建或更新Contact实体,具体取决于它是否已经存在:

public Guid? SetProfile(IProfile profile)
    {

        using (var xrm = new XrmServiceContext(_organizationService))
        {
            //check whether account already exists
            var crmProfile = GetContact(xrm, profile.UserId);

            if (crmProfile == null)
            {
                //create new account if required
                {
                    crmProfile = new Contact
                    {
                        EMailAddress1 = profile.Username,
                        //lots of properties hidden to make for easier code example
                    };
                }
                xrm.AddObject(crmProfile);
            }
            else
            {
                //update existing account
                crmProfile.new_Title = profile.Title.HasValue ? new OptionSetValue(profile.Title.Value) : null;
                //lots of properties hidden to make for easier code example

                xrm.UpdateObject(crmProfile);
            }
            var response = xrm.SaveChanges();

            return crmProfile.Id;
        }
    }

当此方法由2个或更多用户同时执行时,错误&#34;无法访问已处置的对象&#34;将抛出,引用XrmServiceContext对象。

因此我知道我需要使这个方法是线程安全的,但它也需要是同步的,因为我们的UI依赖于具有方法的返回值。我玩了不同的线程方法:

  • Task.Factory.StartNew(()=&gt; delegate
  • new Thread()

然而,使用这两种方法我都无法让方法同步执行,所以我最终得到了:

        public Guid? SetProfile(IProfile profile)
    {
        var task = new Task<Guid?>(() =>
        {
            using (var xrm = new XrmServiceContext(_organizationService))
            {
                //check whether account already exists
                var crmProfile = GetContact(xrm, profile.UserId);

                if (crmProfile == null)
                {
                    //create new account if required
                    {
                        crmProfile = new Contact
                        {
                            EMailAddress1 = profile.Username,
                            //lots of properties hidden to make for easier code example
                        };
                    }
                    xrm.AddObject(crmProfile);
                }
                else
                {
                    //update existing account
                    crmProfile.new_Title = profile.Title.HasValue ? new OptionSetValue(profile.Title.Value) : null;
                    //lots of properties hidden to make for easier code example

                    xrm.UpdateObject(crmProfile);
                }
                var response = xrm.SaveChanges();

                return crmProfile.Id;
            }

        });
        task.RunSynchronously();

        return task.Result;
    }

我在网上看到的所有东西都建议我应该使用StartNew方法,但这是针对我不能允许的异步调用,而且它似乎也不能保证一个新的线程 - 从我读过的内容我知道它很聪明,知道何时需要创建一个新线程 - 但在我的实例中,我必须确定一个新线程用于调用Dynamics。

问题:

  • 我为Web应用程序采用的方法有什么问题吗?
  • 如果我不能使用异步调用,那么使用StartNew方法有什么优势吗?

非常感谢您提前的时间

亲切的问候

dotdev

0 个答案:

没有答案