I am trying to master async method syntax in .NET 4.5. I thought I had understood the examples exactly however no matter what the type of the async method is (ie Task<T>), I always get the same type of error error on the conversion back to T - which I understood was pretty much automatic. The following code produces the error:
Cannot implicitly convert type 'System.Threading.Tasks.Task<System.Collections.Generic.List<int>>' to 'System.Collections.Generic.List<int>'
public List<int> TestGetMethod()
{
return GetIdList(); // compiler error on this line
}
async Task<List<int>> GetIdList()
{
using (HttpClient proxy = new HttpClient())
{
string response = await proxy.GetStringAsync("www.test.com");
List<int> idList = JsonConvert.DeserializeObject<List<int>>();
return idList;
}
}
It fails if I explicitly cast the result as well. This:
public List<int> TestGetMethod()
{
return (List<int>)GetIdList(); // compiler error on this line
}
somewhat predictably results in this error:
Cannot convert type 'System.Threading.Tasks.Task<System.Collections.Generic.List<int>>' to 'System.Collections.Generic.List<int>'
Any help greatly appreciated.
The main issue with your example that you can't implicitly convert Task<T> return types to the base T type. You need to use the Task.Result property. Note that Task.Result will block async code, and should be used carefully.
Try this instead:
public List<int> TestGetMethod()
{
return GetIdList().Result;
}
You need to make TestGetMethod async too and attach await in front of GetIdList(); will unwrap the task to List<int>, So if your helper function is returning Task make sure you have await as you are calling the function async too.
public Task<List<int>> TestGetMethod()
{
return GetIdList();
}
async Task<List<int>> GetIdList()
{
using (HttpClient proxy = new HttpClient())
{
string response = await proxy.GetStringAsync("www.test.com");
List<int> idList = JsonConvert.DeserializeObject<List<int>>();
return idList;
}
}
Another option
public async void TestGetMethod(List<int> results)
{
results = await GetIdList(); // await will unwrap the List<int>
}
Depending on what you're trying to do, you can either block with GetIdList().Result ( generally a bad idea, but it's hard to tell the context) or use a test framework that supports async test methods and have the test method do var results = await GetIdList();
I've just had this issue. I was trying to return a value, but it could not be implicitly cast to a type of Task. The solution was to add the missing async keyword that I forgot to add.
I just had the same issue pop up but the resolution was different than the others. I'm working with two async calls within an async method, this code is what was giving me the error:
var fileContents = reader.ReadToEndAsync();
if (fileContents != null)
{
var profile = await Task.Run(() => JsonConvert.DeserializeObject<T>(fileContents));
return profile;
}
This is the fix. I had forgotten the async on the first line:
var fileContents = await reader.ReadToEndAsync();
if (fileContents != null)
{
var profile = await Task.Run(() => JsonConvert.DeserializeObject<T>(fileContents));
return profile;
}
The error message was showing on "fileContents" on the line var profile = ... So it wasn't immediately obvious of where the error was.
Related
I have the method below that is returning this error:
Error CS1983 The return type of an async method must be void, Task, Task<T>, a task-like type, IAsyncEnumerable<T>, or IAsyncEnumerator<T>
But when I click on the error number link in Visual Studio, it takes me to a Microsoft website that just says:
Sorry, we don't have specifics on this C# error
Here is the method:
private async String SaveAIguess(IFormFile file)
{
var picture = GetFile(file.FileName);
await StorageService.Save(picture, file.OpenReadStream());
var resourceUrl = Path.GetFullPath(file.FileName);
return resourceUrl;
}
Is there a way to make it asynchronous and still be able to return the resourceUrl?
Thanks!
Make it return Task<string>:
private async Task<string> SaveAIguess(IFormFile file)
{
var picture = GetFile(file.FileName);
await StorageService.Save(picture, file.OpenReadStream());
var resourceUrl = Path.GetFullPath(file.FileName);
return resourceUrl;
}
async methods either have no return value or anything that can be encapsulated in a Task<>. It's why to get the actual value you do:
var val = await SaveAIguess(file);
await basically "unwraps" the Task and gives you your string.
Asynchronous methods must return either Task, Task<?>, or void. If you change your return type to Task<string> it should work as desired. Of course, any method calling your async method must also be asynchronous or it must call it like SaveAIguess(dat).Result to make it synchronous.
So your final code will look like
private async Task<String> SaveAIguess(IFormFile file)
{
var picture = GetFile(file.FileName);
await StorageService.Save(picture, file.OpenReadStream());
var resourceUrl = Path.GetFullPath(file.FileName);
return resourceUrl;
}
And it can be called like this in another async method:
var str = await SaveAIguess(dat);
Or in a synchronous method
var str = SaveAIGuess(dat).Result
Yes:
private async Task<String> SaveAIguess(IFormFile file)
I am new to Moq and Mocks/Unit Testing in general. After watching a video on Mocking which uses Moq, I thought I had enough understanding to start setting up a few simple tests for a project I am working on. However, no amount of fiddling with the code helps my first test pass.
Here is the code I have:
Interface Being Tested
public interface IDataInterface
{
Task<IList<T>> GetData<T>(string url);
// Other stuff
}
Implementation of Interface Method GetData<T>
public async Task<IList<T>> GetData<T>(string url)
{
try
{
var json = await client.GetAsync(url).Result.Content.ReadAsStringAsync();
var data = (JObject)JsonConvert.DeserializeObject(json);
JArray arr = (JArray)data["resource"];
return arr.ToObject<IList<T>>();
}
catch (InvalidCastException icEx)
{
throw new InvalidCastException("An error occurred when retrieving the data", icEx);
}
// Other catches
}
Service Calling Implemented Interface GetData<T>
public async Task<IList<MyObj>> GetActiveObjs()
{
var data = await _myImplementedInterface.GetData<MyObj>(ActiveUrl);
return data;
}
My Test
[Fact]
public async void MyImplementedInterface_GetActive_ReturnsDataOrEmptyList()
{
var _activeUrl = "http://some.url";
using (var mock = AutoMock.GetLoose())
{
mock.Mock<IDataInterface>()
.Setup(x => x.GetData<MyObj>(_activeUrl))
.Returns(Task.FromResult(_SomeStaticDataRepresentation)));
var svc = mock.Create<MyService>();
var expected = _SomeStaticDataRepresentation;
var actual = await svc.GetActiveObjs();
Assert.True(actual != null);
// Other assertions that never matter because of the null value of _actual_ variable
}
}
Early on, I had issues because the project uses Autofac and Moq, but I resolved those specific issues. However, I cannot seem to get past the null value coming back from the service call. When running the project, the method returns data, just as expected, so I am flummoxed as to where the issue lies. Reviewing various posts and the Moq Quickstart did not provide what I needed to solve this myself, so my hope is there is someone here who can tell me what I am doing wrong. I apologize already as I am certain it is a newbie mistake.
Addressing the implementation first. Avoid mixing async-await and blocking calls like Wait() and .Result which can result in deadlocks.
Reference Async/Await - Best Practices in Asynchronous Programming
public async Task<IList<T>> GetData<T>(string url) {
try {
var response = await client.GetAsync(url);
var json = await response.Content.ReadAsStringAsync();
var data = (JObject)JsonConvert.DeserializeObject(json);
JArray arr = (JArray)data["resource"];
return arr.ToObject<IList<T>>();
} catch (InvalidCastException icEx) {
throw new InvalidCastException("An error occurred when retrieving the data", icEx);
}
// Other catches
}
For the subject method under test, if nothing needs to be awaited then there is no need to make the function async, just return the Task
public Task<IList<MyObj>> GetActiveObjs() {
return _myImplementedInterface.GetData<MyObj>(ActiveUrl);
}
Now for the test, since already using tasks, then the test should be async and the subject awaited as well.
[Fact]
public async Task MyImplementedInterface_GetActive_ReturnsDataOrEmptyList() {
using (var mock = AutoMock.GetLoose()) {
//Arrange
IList<MyObj> expected = _SomeStaticDataRepresentation;
mock.Mock<IDataInterface>()
.Setup(x => x.GetData<MyObj>(It.IsAny<string>()))
.ReturnAsync(expected);
var svc = mock.Create<MyService>();
//Act
var actual = await svc.GetActiveObjs();
//Assert
Assert.True(actual != null);
Assert.True(actual == expected);
// ...
}
}
Assuming, based on what was shown it is uncertain what the active URL would have been, it could be ignored in the test using It.IsAny<string>().
My async method is as below:
public async Task<List<object>> handleSummaryOfWallets()
{
string token = giveMeToken("URL AND CREDS");
Channel channel = new Channel("NANANANA GIROUD", ChannelCredentials.Insecure);
OMGadminAPI.OMGadminAPIClient client = new OMGadminAPI.OMGadminAPIClient(channel);
var summaryBalancesParams = new OMGadminAPIGetCurrenciesSummariesParams();
summaryBalancesParams.AdminAuthTokenSecret = token;
List<object> summariesCurrenciesOMGadmin = new List<object>();
using (var call = client.GetCurrenciesSummaries(summaryBalancesParams))
{
while (await call.ResponseStream.MoveNext())
{
OMGadminAPICurrencySummary currencySummary = call.ResponseStream.Current;
summariesCurrenciesOMGadmin.Add(currencySummary);
Console.WriteLine(summariesCurrenciesOMGadmin);
}
return summariesCurrenciesOMGadmin;
}
}
As you can see, above async method returns list of objects. I call this method as below:
var listOfBalances = balances.handleSummaryOfWallets().Wait();
and it gives me error:
Error CS0815: Cannot assign void to an implicitly-typed variable
From the error, I understand that this is not correct way to call async method. But I need to read ready list of objects from async fetched data. Its request-response, no real stable stream. So I need to generate this list only once per request. I'm using gRPC framework for RPC calls.
Please help me fetch this data and make ready to use.
The Task.Wait method waits for the Task to complete execution. It returns void. That is the reason why the exception.
Now to overcome the exception and to read the return value, one way is as mentioned in other answer and the comments; await the call as below:
public async void TestAsync()
{
var listOfBalances = await handleSummaryOfWallets();
}
Note that your calling method should also be async method now.
As you are calling Wait in your code, it looks that you want the result immediately; you have nothing else left to do that does not depend on result. In that case, you may choose to stop async chain by calling Wait. But you need to do some changes as below:
public void TestAsync()
{
var task = handleSummaryOfWallets();//Just call the method which will return the Task<List<object>>.
task.Wait();//Call Wait on the task. This will hold the execution until complete execution is done.
var listOfBalances = task.Result;//Task is executed completely. Read the result.
}
Note that calling method is no longer async. Other explanation is given in code-comments.
Other short alternative to above code is as below:
public void TestAsync()
{
var listOfBalances = handleSummaryOfWallets().Result;
}
Just use await while calling your method
var listOfBalances = await balances.handleSummaryOfWallets();
I am working on a Windows Universal app using the new runtime for Windows Phone/Store apps. I am sending a request to a server using the following code and expecting a HTML response back. However when I return the string and display it in the UI, it just says:
"System.Threading.Tasks.Task'1[System.String]"
It's not showing me the actual HTML/XML that should be returned. When I use the same URL in a normal Windows Forms app, it's returning the data I expect but the code I use there is different due to it being Win32 not WinRT/this new RT.
Here's my code. I suspect I am not returning the data in the right format or something but I don't know what I should be doing.
var url = new Uri("http://www.thewebsitehere.com/callingstuff/calltotheserveretc");
var httpClient = new HttpClient();
try
{
var result = await httpClient.GetStringAsync(url);
string checkResult = result.ToString();
httpClient.Dispose();
return checkResult;
}
catch (Exception ex)
{
string checkResult = "Error " + ex.ToString();
httpClient.Dispose();
return checkResult;
}
I don't think the problem is in this code snippet but in the caller. I suspect this code is in a method returning a Task (correct so that the caller can wait for this method's HttpClient call to work) but that the caller isn't awaiting it.
The code snippet looks correct and essentially the same as in the docs at https://msdn.microsoft.com/en-us/library/windows/apps/windows.web.http.httpclient.aspx . GetStringAsync returns a Task. The await will handle the Task part and will return a string into var result. If you break inside the function and examine result or checkResult they'll be the desired strings.
The same thing needs to happen with the caller. If this is in a function
Task<string> GetData()
{
// your code snippet from the post
return checkResult; // string return is mapped into the Task<string>
}
Then it needs to be called with await to get the string rather than the task and to wait for GetData's internal await to finish:
var v = GetData(); // wrong <= var will be type Task<string>
var data = await GetData(); // right <= var will be type string
The only time you wouldn't await the Task is if you need to manipulate the Task itself and not just get the result.
The 'await' operator can only be used within an async method. Change its return type to Task<string> should resolve the problem. The try block should be something like this:
try
{
Task<string> t = httpClient.GetStringAsync(url);
string checkResult = t.Result;
httpClient.Dispose();
return checkResult;
}
This question already has answers here:
Nesting await in Parallel.ForEach [duplicate]
(11 answers)
Closed last year.
I had such method:
public async Task<MyResult> GetResult()
{
MyResult result = new MyResult();
foreach(var method in Methods)
{
string json = await Process(method);
result.Prop1 = PopulateProp1(json);
result.Prop2 = PopulateProp2(json);
}
return result;
}
Then I decided to use Parallel.ForEach:
public async Task<MyResult> GetResult()
{
MyResult result = new MyResult();
Parallel.ForEach(Methods, async method =>
{
string json = await Process(method);
result.Prop1 = PopulateProp1(json);
result.Prop2 = PopulateProp2(json);
});
return result;
}
But now I've got an error:
An asynchronous module or handler completed while an asynchronous operation was still pending.
async doesn't work well with ForEach. In particular, your async lambda is being converted to an async void method. There are a number of reasons to avoid async void (as I describe in an MSDN article); one of them is that you can't easily detect when the async lambda has completed. ASP.NET will see your code return without completing the async void method and (appropriately) throw an exception.
What you probably want to do is process the data concurrently, just not in parallel. Parallel code should almost never be used on ASP.NET. Here's what the code would look like with asynchronous concurrent processing:
public async Task<MyResult> GetResult()
{
MyResult result = new MyResult();
var tasks = Methods.Select(method => ProcessAsync(method)).ToArray();
string[] json = await Task.WhenAll(tasks);
result.Prop1 = PopulateProp1(json[0]);
...
return result;
}
.NET 6 finally added Parallel.ForEachAsync, a way to schedule asynchronous work that allows you to control the degree of parallelism:
var urlsToDownload = new []
{
"https://dotnet.microsoft.com",
"https://www.microsoft.com",
"https://twitter.com/shahabfar"
};
var client = new HttpClient();
var options = new ParallelOptions { MaxDegreeOfParallelism = 2 };
await Parallel.ForEachAsync(urlsToDownload, options, async (url, token) =>
{
var targetPath = Path.Combine(Path.GetTempPath(), "http_cache", url);
var response = await client.GetAsync(url, token);
// The request will be canceled in case of an error in another URL.
if (response.IsSuccessStatusCode)
{
using var target = File.OpenWrite(targetPath);
await response.Content.CopyToAsync(target);
}
});
Alternatively, with the AsyncEnumerator NuGet Package you can do this:
using System.Collections.Async;
public async Task<MyResult> GetResult()
{
MyResult result = new MyResult();
await Methods.ParallelForEachAsync(async method =>
{
string json = await Process(method);
result.Prop1 = PopulateProp1(json);
result.Prop2 = PopulateProp2(json);
}, maxDegreeOfParallelism: 10);
return result;
}
where ParallelForEachAsync is an extension method.
Ahh, okay. I think I know what's going on now. async method => an "async void" which is "fire and forget" (not recommended for anything other than event handlers). This means the caller cannot know when it is completed... So, GetResult returns while the operation is still running. Although the technical details of my first answer are incorrect, the result is the same here: that GetResult is returning while the operations started by ForEach are still running. The only thing you could really do is not await on Process (so that the lambda is no longer async) and wait for Process to complete each iteration. But, that will use at least one thread pool thread to do that and thus stress the pool slightly--likely making use of ForEach pointless. I would simply not use Parallel.ForEach...