【问题标题】:WCF - Call Web Service Completed event is do after awaitWCF - 调用 Web 服务完成事件在等待之后执行
【发布时间】:2018-02-04 01:18:48
【问题描述】:

我调用了 WCF,方法的 Completed 事件在等待方法之后调用。

   public void my_method()
    {
        Task task = Task.Run(async () => await DoWorkAsync());       
        task.Wait();            
    }

    public async Task DoWorkAsync()
    {
        await Task.Run(() =>
         {
             wcf1.ServiceAnnonces s = new wcf1.ServiceAnnonces();
             s.DoWorkCompleted += S_DoWorkCompleted;
             s.DoWorkAsync();
         });
    }

    private string retour;
    public string Retour { get => retour; set => retour = value; }

    private void S_DoWorkCompleted(object sender, wcf1.DoWorkCompletedEventArgs e)
    { 
            Retour = e.Result;   
    }

我用这段代码调用方法:

    Droid.Resources.ISvAnnoncesSoap s = new Droid.Resources.ISvAnnoncesSoap();
        s.ma_methode();

        LbResulat.Text = s.Retour;

我的服务:

 [ServiceContract]
    public interface IServiceAnnonces
    {
        [OperationContract]
        string DoWork();
    }

  public class ServiceAnnonces : IServiceAnnonces
    {

        public string DoWork()
        {
            return "coucou";
        }
    }
}

但是 le Completed 事件是在 LbResulat.Text = s.Retour; 之后抛出的;

感谢您的帮助。

编辑:

我删除了一些行代码。我现在的代码:

  public void ma_methode()
    {
        wcf1.ServiceAnnonces s = new wcf1.ServiceAnnonces();
        s.DoWorkCompleted += S_DoWorkCompleted;
        s.DoWorkAsync();         
    }

    private string retour;
    public string Retour { get => retour; set => retour = value; }

    private void S_DoWorkCompleted(object sender, wcf1.DoWorkCompletedEventArgs e)
    { 
            Retour = e.Result;   
    }

直接调用:

 Droid.Resources.ISvAnnoncesSoap s = new Droid.Resources.ISvAnnoncesSoap();
            s.ma_methode();

        LbResulat.Text = s.Retour;

但是一样,但是 Completed 事件是在 LbResulat.Text = s.Retour 之后抛出的;所以我的 Retour 是空的。

【问题讨论】:

  • 猜测,s.DoWorkAsync() 也是异步的,应该等待。我很确定你不需要所有这些 Task.Run's 虽然 - async doesn't need Threads 你能提供代码或 ServiceAnnonces.DoWorkAsync(); 的方法签名
  • 感谢我编辑我的帖子

标签: wcf asynchronous async-await


【解决方案1】:

假设 DoWorkAsync()DoWorkCompleted 是为您的 WCF 服务合同生成的客户端代理,那么“问题”是您没有阻止/等待 DoWorkCompleted 回调的完成 - 您正在调用 @ 987654327@ 然后你的代码继续。稍后,WCF 调用完成并调用回调(这就是 WCF 中的异步客户端方法代理对的工作方式——它们早于 .Net 4.5 的await)。

您可以“重新同步”代码,例如使用TaskCompletionSource 让您的代码等待回调完成并发出任务已完成的信号:

public async Task DoWorkAsync()
{
     var tcsWorkDone = new TaskCompletionSource<bool>();
     wcf1.ServiceAnnonces s = new wcf1.ServiceAnnonces();
     s.DoWorkCompleted += (sender, e) =>
     {
        S_DoWorkCompleted(sender, e);
        tcsWorkDone.SetResult(true);
     };
     s.DoWorkAsync();
     await tcsWorkDone.Task;
 }

(同样,如果在回调之后没有任何工作完成,您也可以放弃异步,并从方法中返回任务让调用者等待)

可以指出,这完全是愚蠢的 - 我们正在重新同步异步 WCF 客户端代理。

相反,您可以回退到同步客户端 WCF 代理(它将生成一个同步方法 DoWork(),您可以将其绑定到您的 LbResulat.Text(WPF / WinForms / Web 窗体标签?)。

更好的是,您可以在回调中异步进行绑定

private void S_DoWorkCompleted(object sender, wcf1.DoWorkCompletedEventArgs e)
{ 
   Retour = e.Result;
   // TODO - Use this to trigger code to set LbResulat.Text = s.Retour;
}

但是请注意,回调可以在不同的线程上,因此您可能需要适当的(重新)调用代码以确保任何 UI 工件(如标签/文本框)在 UI 线程上更新。

回复:不要使用 Task.Run

最好使用 Task.Run 来

public async Task my_method()
{
    return await DoWorkAsync();
}

或者如果没有其他工作,只需将任务返回给调用者等待:

public Task my_method()
{
    return DoWorkAsync();
}

但是如果你真的不能让 my_method 异步,那么你可以用Task.Run 启动第二个线程然后阻塞第一个线程,然后你可以synchronize with

public void my_method()
{
    DoWorkAsync()
        .GetAwaiter()
        .GetResult();
}

【讨论】:

  • 哇!非常感谢您的解释,我试着理解并告诉您是否可以。
  • 我已经很久没有使用 WCF,但现在您似乎可以生成一个 net 4.5 async / await Task based asyncronous proxy - 这可能是处理您的代码的正确异步方式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-05-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-19
  • 1970-01-01
相关资源
最近更新 更多