将WCF调用转换为异步WCF调用的最佳实践

时间:2009-03-10 20:26:15

标签: wcf asynchronous

尝试将所有正常的WCF调用转换为异步WCF调用时遇到问题。我发现我有一个重构代码很多,并且不确定如何做到这一点。我已经使用了我发现here的方法,但遇到了需要按顺序发生事情的问题。

private void btnSave_Click(object sender, RoutedEventArgs e)
{

  List<Item> itemList = GetList();
  foreach(Item i in itemList)
  {
    DoSomeWork(i);

    if(i.SomeID == 0)
    {      
       DoSomeMoreWork(i);  
    }

    UpdateRecord(i)  // this can't execute until the above code is complete

  }
}

private void DoSomeWork(Item i)
{
  // call async method
}

private void DoSomeMoreWork(i)
{
  // call async method
}

private void UpdateRecord(item i)
{
  // call async method
}

重构代码以异步方式工作的最佳方法是什么,还是我需要完全重新考虑我的逻辑?我是否真的必须在任何地方插入计数器和开关以确保在执行其他操作之前完成某些事情?

编辑:我这样做的原因是在接下来的几个月里,我们将这个WPF应用程序转换为需要异步调用的Silverlight。所以我正在尝试将我们的常规WCF调用转换为异步准备。我发现它需要一种不同的思维方式。

6 个答案:

答案 0 :(得分:3)

对于你正在做的事情,我会说处理事情的真正地方是每个项目只打一次电话,而不是3。

最好,如果项目列表不是很大,请使用整个列表对服务进行一次调用...

private void btnSave_Click(object sender, RoutedEventArgs e)
{  
    List<Item> itemList = GetList();  
    foreach(Item i in itemList)  
    {    
        DoAllTheWorkAndUpdate(i);    
    }
}

...或

private void btnSave_Click(object sender, RoutedEventArgs e)
{  
    List<Item> itemList = GetList();  
    foreach(Item i in itemList)  
    {    
        if(i.Id == 0)
        {
            DoLotsOfWorkAndUpdate(i);
        }
        else
        {
            DoSomeWorkAndUpdate(i);
        }

    }
}

...或

private void btnSave_Click(object sender, RoutedEventArgs e)
{  
    List<Item> itemList = GetList();  
    DoTheWorkOnTheWholeList(itemList);
}

换句话说,感觉你的一些责任可能是错位的 - 我通常更愿意提供服务,我只能打电话给他们。然后,异步性质是无关紧要的,因为您没有执行一系列事件。

答案 1 :(得分:2)

查看Juval Lowy(Programming WCF Serviceswebsite的作者,了解如何在WCF中实现异步编程的示例。下载是免费的;你只需要提供你的电子邮件地址。

答案 2 :(得分:1)

当你需要在循环内部同步时,我可能有点疑惑为什么你需要使用异步WCF操作。

如果您只是使用异步方法来帮助阻止UI挂起,那么您可以使用支持进度更新的BackgroundWorker来使UI保持最新,而不是使用异步WCF调用。

您还应该能够从Async方法的Completed事件中调用各种函数。

只需将事件处理程序连接到已完成的事件,然后在启动异步WCF调用时将Item对象作为userState参数传递。这样,当每个Completed事件触发时,您将把它作为参数。这样,您只会在上一次异步调用完成时执行下一步处理。

我不知道这是否真的回答了你的问题。

答案 3 :(得分:1)

答案 4 :(得分:0)

如果您没有使用Silverlight,则可以使用一种方法阻塞线程,直到其他方法完成,例如使用ManualResetEvent。但是这在Silverlight中不起作用,因为所有WCF调用都发生在主UI线程上,所以如果你阻止该线程,所有块。更好的方法是使用回调来做这样的事情:

    public delegate void OperationCallback();

    private void btnSave_Click(object sender, RoutedEventArgs e)
    {

        List<Item> itemList = GetList();
        foreach (Item i in itemList)
        {
            DoSomeWork(i, () =>
            {
                if (i.SomeID == 0)
                {
                    DoSomeMoreWork(i, () =>
                    {
                        UpdateRecord(i);
                    });
                }
                else
                {
                    UpdateRecord(i);
                }
            });

        }
    }

    private void DoSomeWork(Item i, OperationCallback callback)
    {
        // call async method then callback when it completes.
        callback();
    }

    private void DoSomeMoreWork(Item i, OperationCallback callback)
    {
        // call async method, then callback when it completes.
        callback();
    }

    private void UpdateRecord(Item i)
    {
        // call async method
    }

它肯定不如同步版本那么清晰,但如果你尽可能多地使用lambda表达式,那么仍然可以保持控制流的可读性。

答案 5 :(得分:-1)

将名为SomeWorkDone和SomeMoreWorkDone的2个属性添加为布尔值。创建处理DoSomeWorkCompleted和DoSomeMoreWorkCompleted的方法。在这些方法中,将相应的布尔属性设置为true并调用UpdateRecord。在UpdateRecord中,确保两个Done属性都为true,然后完成调用。

您可能会遇到一些争用问题,但这可以帮助您实现目标。