【问题标题】:Async callback is called but not executed sometimes异步回调被调用但有时不执行
【发布时间】:2016-07-14 19:57:18
【问题描述】:

Silverlight 项目。

在我后面的 View 代码中,我调用 View Model 中的一个方法来获取值。

 public MyViewModel ViewModel
    {
        get
        {
            if (this.viewModel == null)
                this.viewModel = new MyViewModel();
            return this.viewModel;
        }
        set
        {
            if (this.viewModel != value)
            {
                this.viewModel = value;
            }
        }
    }

但是没有调用异步回调。有时它被延迟调用。因此,我得到的值是1900-01-01 00:00:00.000,而不是正确的日期时间。

DateTime value;
public void GetDateTime()
    {
        var proxy = new WcfClient();
        proxy.GetCurrentDateTimeCompleted -= ProxyGetCurrentDateTimeCompleted;
        proxy.GetCurrentDateTimeCompleted += ProxyGetCurrentDateTimeCompleted;
        proxy.GetCurrentDateTimeAsync();
    }

    private void ProxyGetCurrentDateTimeCompleted(object sender, GetCurrentDateTimeCompletedEventArgs args)
    {
        try
        {
            value = args.Result;

在后面的代码中调用它。

this.viewModel.GetDateTime();

更新 1

根据评论,我添加了一些解释。视图有一个复选框。如果我单击它或取消单击它,将弹出一个带有是/否按钮的消息框。无论您选择是或否,我都会在MessageBoxYesNoSelection_Closed 事件中记录日期和时间。事件方法还在后面的代码中。

复选框部分代码为:

if (clickedCheckBox != null)
{
    var msgBoxControl = new MessageBoxControl();
    msgBoxControl.Closed -= MessageBoxYesNoSelection_Closed;
    msgBoxControl.Closed += MessageBoxYesNoSelection_Closed;

    if (clickedCheckBox.IsChecked == true)
    {
        var curDateTime = this.ViewModel.value;// 1900-01-01 00:00:00.000

MessageBoxYesNoSelection_Closed 中,我们得到了值。

this.ViewModel.GetDateTime();// WCF async call
this.ViewModel.UpdateValue(value); // another WCF async call, need value from GetDateTime() method's return result.
this.ViewModel.UpdateAnotherValue(value, user); // third WCF async call

我发现有时虽然调用了异步回调,但它们并没有执行。

【问题讨论】:

  • 您需要提供更多关于在异步功能完成后如何获取值value的信息,您需要提供Minimal Complete Verifiable Example,现在您遗漏了太多信息我们可以有效地帮助您。
  • @ScottChamberlain,感谢您的评论。我添加了一些代码。
  • 在您的服务类中设置断点并观察那里发生的情况。服务器是否收到请求?超时时间是否太短?对我来说很多猜测......
  • @lok​​usking,服务器确实收到了请求。问题是有时我能得到正确的值,有时不能。
  • Sometimes 表示在某些情况下存在超时问题。您的服务器方法是否被 lock 包围?

标签: c# wcf asynchronous


【解决方案1】:

我猜您遇到了race condition,因为您没有等待this.ViewModel.GetDateTime() 调用,因此在大多数情况下,设置值的回调 (ProxyGetCurrentDateTimeCompleted) 在您使用该值之前没有被调用在下一条语句中 (this.ViewModel.UpdateValue(value))。

最简单的解决方案是使用asyncawait,如herehere 所述。

如果你不能这样做,另一种解决方案是将依赖于值的代码移动到回调方法中。

更新 1

可以将 asyncawait 与 Silverlight 4 和 .NET Framework 4.0 一起使用。请参阅Microsoft.Bcl.Async 了解更多信息。但是,此方法至少需要 Visual Studio 2012,因此如果您无法切换到较新的 Visual Studio 版本,这将不适合您。

在这种情况下,想法是将依赖于值的代码移动到回调方法中。所以一开始你只会打电话给GetDateTime()

this.ViewModel.GetDateTime(); // WCF async call

然后你会在回调方法中调用其他方法:

private void ProxyGetCurrentDateTimeCompleted(object sender, GetCurrentDateTimeCompletedEventArgs args)
{
    value = args.Result;
    UpdateValue(value); // another WCF async call, need value from GetDateTime()
    UpdateAnotherValue(value, user); // third WCF async call
}

更新 2

根据您的最后一条评论,我建议您重组您的应用程序,以便您可以使用第一次更新中所示的方法。在后面的代码和视图模型中存储数据似乎有点奇怪。但是,如果您想要一个快速的解决方案,您也可以等待回调手动设置值。请参阅以下代码作为示例以帮助您入门:

DateTime value;
bool wcfCallInProgress;
public void GetDateTime()
{
    var proxy = new WcfClient();
    proxy.GetCurrentDateTimeCompleted -= ProxyGetCurrentDateTimeCompleted;
    proxy.GetCurrentDateTimeCompleted += ProxyGetCurrentDateTimeCompleted;
    wcfCallInProgress = true;
    proxy.GetCurrentDateTimeAsync();
}

private void ProxyGetCurrentDateTimeCompleted(object sender, GetCurrentDateTimeCompletedEventArgs args)
{
    value = args.Result;
    wcfCallInProgress = false;
}

现在您可以添加一个循环,等待该值被设置:

this.ViewModel.GetDateTime();// WCF async call

while (this.ViewModel.wcfCallInProgress)
{
    Thread.Sleep(10);
}

this.ViewModel.UpdateValue(value); // another WCF async call, need value from GetDateTime() method's return result.
this.ViewModel.UpdateAnotherValue(value, user); // third WCF async call

如果您使用这种方法,则必须确保超时和异常不会成为问题。否则你可能会陷入无限循环。

【讨论】:

  • 我使用 Visual Studio 2010,.NET 4。async & await 是 .NET 4.5。
  • 那么我猜你必须更改代码以确保在调用ProxyGetCurrentDateTimeCompleted 回调之后调用UpdateValue(value)UpdateAnotherValue(value, user) 方法。确保这一点的最简单方法是在设置值后在回调方法中调用这些方法。
  • 我同意你的想法。现在的问题是如何确保以正确的顺序调用这些方法。我什至在 finally 块中放置了一种方法,但仍然无法正常工作。
  • 我添加了一个示例。如果第三个 WCF 异步调用需要来自第二个 WCF 调用的值,则必须将其从第二个调用移到回调处理程序中(依此类推)。
  • 正如我所说,if (clickedCheckBox != null) 在代码后面。在 ViewModel 中,我调用 WCF。所以他们在不同的地方。因此,我还必须将复选框和消息框信息传递给它,并且我还有其他参数(例如用户等)要传入 WCF 调用。
猜你喜欢
  • 2021-11-23
  • 1970-01-01
  • 2015-07-30
  • 2016-05-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多