Srgjan-LDTeam Srgjan-LDTeam - 25 days ago 9
C# Question

How to properly use async/await in .NET 4.0

for some reasons i needed to go back version of .net, so i was 4.5 and now im 4.0, and im having conflict with my async methods:
i have wcf service, and i want to execute the async methods and await them, so in 4.5 i did this:
wcf:

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


and 4.5 client:

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..
}
}


but when i reverted to 4.0, both, the service and the client, i had to use nuget library:


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


now in wcf 4.0 i have this:

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


and in client i try this:

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


but error pops up saying: cannot await void...
if i call:

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


it returns datatable no problem ... but async is returning void .. why ? and how to solve this ... tnx in advance..

//in comments you asked me for the definition of process something, here it is:

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);
}
});
}

Answer

In the older versions of WCF the async functions where tied to Begin/End statements. Using the task based async proxes will likely cause problems like you are running in to.

Regenerate your client proxies so you have the Begin/End combos and use TaskFactory.FromAsync to convert it in to a task which can be awaited on using 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);
    }
}