如何在 .NET 4.0 中正确使用 async/await

Posted

技术标签:

【中文标题】如何在 .NET 4.0 中正确使用 async/await【英文标题】:How to properly use async/await in .NET 4.0 【发布时间】:2017-03-28 00:08:19 【问题描述】:

由于某些原因,我需要返回 .net 版本,所以我是 4.5,现在我是 4.0,并且我与我的异步方法发生冲突: 我有 wcf 服务,我想执行异步方法并等待它们,所以在 4.5 中我这样做了: wcf:

public async Task<DataTable> ProcessSomething(string Param1, int Param2)
        
            return await Task.Run(() =>
             
            return new DataTable("aaa");
            );
        

和 4.5 客户端:

private static async Task<bool> ProcessSomethingAsync(string Param1, int Param2)
        
            decimal payin = 0;
            Task<DataTable> result = Client.Instance.___Client.ProcessSomethingAsync(Param1, Param2);
            if (result == await Task.WhenAny(result, Task.Delay(1000)))
            
                //code here..
            
           

但是当我恢复到 4.0 时,无论是服务还是客户端,我都必须使用 nuget 库:

https://www.nuget.org/packages/Microsoft.Bcl.Async/

现在在 wcf 4.0 我有这个:

public async Task<DataTable> ProcessSomething(string Param1, int Param2)
        
            return await Task.Factory.StartNew(() => 
            
                return new DataTable("aaa");
            );
        

在客户端我试试这个:

DataTable ProcessSomethingResult = await Client.Instance.____Client.ProcessSomethingAsync(Param1, Param2);

但弹出错误说:不能等待无效... 如果我打电话:

DataTable ProcessSomethingResult = Client.Instance.____Client.ProcessSomething(Param1, Param2);

它返回数据表没问题...但是异步返回无效..为什么?以及如何解决这个问题... tnx 提前..

//在cmets中你问我process的定义,这里是:

public async Task<DataTable> ProcessTicket(string Barcode, int ClientID)
        
            return await Task.Factory.StartNew(() => 
            
                try
                
                    DataTable dt = new DataTable("ProcessTicket");
                    using (SqlConnection con = new SqlConnection(TempClass._DatabaseConnectionString))
                    
                        using (SqlCommand com = new SqlCommand("SELECT * FROM dbo.ProcessTicket(@Barcode, @ClientID)", con))
                        
                            con.Open();
                            com.CommandType = CommandType.Text;
                            com.Parameters.AddWithValue("@Barcode", Barcode);
                            com.Parameters.AddWithValue("@ClientID", ClientID);
                            dt.Load(com.ExecuteReader());
                            if (dt == null)
                                throw new FaultException("DataTable from database is null.");
                            return dt;
                        
                    
                
                catch (Exception ex)
                
                    Logs.Instance.AppendLogs(ex.Message, MethodBase.GetCurrentMethod().Name);
                    throw new FaultException(ex.Message);
                
            );
        

【问题讨论】:

好像在 Client.Instance.____Client 中看不到最相关的代码,这是来自生成的客户端界面吗? 这是与 wcf 服务交互的客户端对象的单例模式。 Client.Instance.ClientObjectName.SomeMethod(); 不过,这就是问题所在。 你为什么这么认为? 你能告诉我们Client.Instance.___Client.ProcessSomethingAsync()的定义吗? 【参考方案1】:

在旧版本的 WCF 中,异步函数与 Begin/End 语句相关联。使用基于任务的异步代理可能会导致您遇到的问题。

重新生成您的客户端代理,以便您拥有 Begin/End 组合并使用 TaskFactory.FromAsync 将其转换为可以等待使用 Microsoft.Bcl.Async 的任务。

//put this in a seperate file, client proxies are usually marked "partial" so you can 
// add functions on like this and not have them erased when you regenerate.
partial class YourClientProxy

    public Task<DataTable> ProcessSomethingAsync(string Param1, int Param2)
    
        return Task<DataTable>.Factory.FromAsync(this.BeginProcessSomething, this.EndProcessSomething, Param1, Param2, null);
    

【讨论】:

谢谢先生,任务完成:) @Srgjan-LDTeam 您应该通过单击我的答案旁边的复选标记将答案标记为完成。

以上是关于如何在 .NET 4.0 中正确使用 async/await的主要内容,如果未能解决你的问题,请参考以下文章

如何在.net4.0中使用.net4.5的async/await实现异步

如何正确理解.NET 4.5和C#5.0中的async/await异步编程模式

Async和Await异步编程的原理

.NET4.5新特性之异步编程(Async和Await)的使用

gulp#4.0 Did you forget to signal async completion?

详解.NET 异步编程,如何透过现象,看async/await本质