Reputation: 5021
In my service layer I wanted to fire multiple methods asynchronously and await for their results.
I tried with one at a time and it is erroring out.
In my service class I called the method like
var _validChapterCodesTask = gd.validateChapterCodeDetails(_input1);
await Task.WhenAll(_validChapterCodesTask);
var _chapterCodeResult = await _validChapterCodesTask;
And in DAL class the method definition looks like
public async Task<IEnumerable<ChapterCodeValidationOutput>> validateChapterCodeDetails(GroupMembershipValidationInput gmvi)
{
Repository rep = new Repository();
if (!gmvi._chapterCodes.All(x => x.Equals("")))
{
var _validChapterCodes = await rep.ExecuteStoredProcedureAsync<Entities.Upload.ChapterCodeValidationOutput>(SQL.Upload.UploadValidation.getChapterCodeValidationSQL(gmvi._chapterCodes),null);
return _validChapterCodes;
}
else
return new List<ChapterCodeValidationOutput>();
}
Error message
Error 208 The
await
operator can only be used within anasync
method. Consider marking this method with theasync
modifier and changing its return type toTask<ARC.Donor.Business.Upload.GroupMembershipValidationOutput>
.C:\Users\m1034699\Desktop\Stuart_Upgrade_2.1_New Approach\Stuart_Export_Upload_v2.1\Stuart Web Service\ARC.Donor.Service\Upload\UploadValidationServices.cs 34 13 ARC.Donor.Service
in lines
await Task.WhenAll(_validChapterCodesTask);
var _chapterCodeResult = await _validChapterCodesTask;
What am I doing wrong ?
Upvotes: 0
Views: 263
Reputation: 24525
The error message is very explicit. It is telling you that you're Service class method is incorrectly attempting to use the async
keyword. In order to fix this, you should be using "Async all the way" as defined in Stephen Cleary's post on MSDN as a best practice.
For example, if you're service class has a method body that is working with Task
or Task<T>
, or attempting to use the await
keyword the method signature for this corresponding method body must be async
(as the async
keyword enables a method to use the await
keyword). Additionally this method itself should also be Task
or Task<T>
returning, with very few exceptions to that rule.
Personally, I would alter your DAL class to simply return the operation that represents the asynchronous work without actually awaiting it. If you think about it, the body of the validateChapterCodeDetails
method does not actually need to do anything with the results, it just needs to return them (instead of materializing them there). Consider the following:
public Task<IEnumerable<ChapterCodeValidationOutput>>
validateChapterCodeDetails(GroupMembershipValidationInput gmvi)
{
var rep = new Repository();
return gmvi._chapterCodes.All(x => x.Equals(""))
? new List<ChapterCodeValidationOutput>()
: rep.ExecuteStoredProcedureAsync
<Entities.Upload.ChapterCodeValidationOutput>
(SQL.Upload.UploadValidation
.getChapterCodeValidationSQL(gmvi._chapterCodes),null)
}
Since your Task<IEnumerable<ChapterCodeValidationOutput>>
variable has already been awaited, you can access the .Result
property to get what you're looking for.
Then in your Service class your method would look like this:
public async Task ConsumeAsync()
{
var _validChapterCodesTask = gd.validateChapterCodeDetails(_input1);
await Task.WhenAll(_validChapterCodesTask);
var _chapterCodeResult = _validChapterCodesTask.Result;
// Do something with it...
}
Here is a .NET fiddle that should help to exemplify this for you better.
NOTE
I would also caution using IEnumerable
as it pertains to your repo, you should ensure that the results from the Database are not occurring via deferred execution, otherwise you risk the potential for connection issues, i.e.; unintentionally leaving a connection open, or not properly closing one.
Upvotes: 1
Reputation: 3968
In the Service
class where you call
var _validChapterCodesTask = gd.validateChapterCodeDetails(_input1);
await Task.WhenAll(_validChapterCodesTask);
var _chapterCodeResult = await _validChapterCodesTask;
add a async
to the method signature where await Task.WhenAll(_validChapterCodesTask);
is called. And when this method also has a return type you have to wrap this type in a Task
like the exception shows:
Task<ARC.Donor.Business.Upload.GroupMembershipValidationOutput>
E.g. if you have the following method:
public GroupMemberShipValidationOutput validate(..) {
...
await Task.WhenAll(_validChapterCodesTask);
...
}
You have to change the method signature to:
public async Task<GroupMemberShipValidationOutput> validate(..) {
...
await Task.WhenAll(_validChapterCodesTask);
...
}
Upvotes: 0