Difference between these two async implementations - c#

I am using EF's async methods to fetch data from a database. Most of the time all is well. I have come into a few ObjectContextDisposed exceptions of late, and I am curious as to why my solution works:
Here was my original code that threw ObjectContextDisposed:
public Task<List<string>> GetEventParameterMru(EventParameter parameter, int count = 20)
{
using (var repo = new ConfigurationRepository())
{
return repo.GetEventParameterMRU(_CurrentWorkpack, parameter, count)
}
}
Here is my new code that doesn't throw:
public async Task<List<string>> GetEventParameterMru(EventParameter parameter, int count = 20)
{
using (var repo = new ConfigurationRepository())
{
var result = await repo.GetEventParameterMRU(_CurrentWorkpack, parameter, count);
return result;
}
}
Could someone explain to me what the difference is, and why it works?
Just FYI, in all my usages of this method, I call await GetEventParameterMru()
Thanks

GetEventParameterMRU is apparently a method that starts a Task to retrieve some data. So GetEventParameterMRU returns before all operations on the repo have been completed.
Both version of your code use a using statement, which is translated into a try/finally block. In the finally block, repo will be disposed.
In your first version, you return immediatly after calling GetEventParameterMRU (starting the task). That means that repo is disposed immediatly while the Task using repo is still running. So when this Task accesses repo you receive your
ObjectDisposedException
In the second version you use await. The compiler therefor translates your whole method into a state machine. The method returns control to its caller at the await statement, but without passing the finally block.
When the Task completes, execution of your method is continued after the await statement.
So repo is only disposed when the Task has completed. So you don't get an ObjectDisposedException.

Following is my understanding on initial code review:
In first one, which is not Async implementation but still a Task is returned from the using block, which would call the repo.Dispose() in the end, when finally Task is executed (assuming its done by the caller, but holds true even for the method - GetEventParameterMRU starting it), it's quite feasible that repo is disposed by that time, but still operation is on and thus the exception
In second one, that's not the case, even when it has freed the UI / Calling thread, until and unless following completes:
await repo.GetEventParameterMRU(_CurrentWorkpack, parameter, count)
It will not call repo.Dispose() and thus completely avoid the ObjectContextDisposed issue

Let me translate them for you:
First one:
Create repository
Start GetEventParameterMRU on repository as Task
Dispose repository
return Task, that is still working with repository
Second one:
Create repository
Start GetEventParameterMRU on repository as Task
Wait for Task to finish to get result
Dispose repository
return result
As you can see, the problem is quite clear here.

I believe this has to do with the first code not capturing the current SynchronizationContext explicitly, while await DOES capture this explicitly.
Some further reading:
https://msdn.microsoft.com/en-us/magazine/gg598924.aspx

Related

Difference Await and ContinueWith

I've read some threads regards the difference between await and ContinueWith. But no one has answer me completely.
I've got a DataAccess Layer that insert records in a database using Dapper.
The InsertAsync method is:
public Task<int> InsertAsync(TEntity entity)
{
return Connection.InsertAsync(entity, Transaction).ContinueWith(r => Convert.ToInt32(r.Result));
}
I don't use async and await because in my head who will use this method will waiting for the result.
Is correct?
I don't use async and await because in my head who will use this method will waiting for the result. Is correct?
That is not correct. While the await keyword does indeed wait for Connection.InsertAsync to complete before it calls Convert.ToInt32, the moment it starts waiting for Connection.InsertAsync it releases control back to its caller.
In other words, the caller will not be stuck waiting for Connection.InsertAsync to finish. The caller will be told "this will take a while, feel free to do something else", so it can continue.
Now, if the caller themselves was explicitly told to await the InsertAsync(TEntity) method on the same line that you call the method, then it will wait and it won't do anything else (except release control back to its caller), but that's because it was explicitly instructed to wait at that point.
To explain in code:
// I will wait for this result
var myInt = await Connection.InsertAsync(myEntity);
// I will not do this until I receive myInt
var sum = 1 + 1;
var anotherSum = 2 + 2;
var andAnotherSum = 3 + 3;
Without the await, the caller will just move on to the next command and do its work, all the way up to the point where it is finally told that it must await the task returned from InsertAsync(TEntity).
To explain in code:
// I will ask for this result but not wait for it
var myIntTask = Connection.InsertAsync(myEntity);
// I will keep myself busy doing this work
var sum = 1 + 1;
var anotherSum = 2 + 2;
var andAnotherSum = 3 + 3;
// My work is done. I hope the task is already done too.
// If not, I will have to wait for it because I can't put it off any longer.
var myInt = await myIntTask;
I've read some threads regards the difference between await and ContinueWith.
Functionally speaking, there is no difference between the two. However, the ContinueWith syntax has recently fallen out of popular favor, and the await syntax is much more favored because it reduces nesting and improves readability.
In terms of waiting, the behavior is exactly the same.
Personally, I suspect that ContinueWith is a leftover artifact from initially trying to design async methods the same way that promises in JS work, but this is just a suspicion.
That should be fine. However, there is a recommendation to always pass a taskscheduler to Continue with, to avoid any ambiguity of what context the continuation will run in, even if it does not matter in this particular case.
I would prefer the version
public async Task<int> InsertAsync(TEntity entity)
{
var r = await Connection.InsertAsync(entity, Transaction);
return Convert.ToInt32(r);
}
I consider this easier to read, and it will always execute the continuation on the same context as the caller. Behind the scenes it will produce very similar code to your example.
You should definitely prefer async/await over the ContinueWith method.
public async Task<int> InsertAsync(TEntity entity)
{
var result = await Connection.InsertAsync(entity, Transaction);
return Convert.ToInt32(result);
}
The primitive ContinueWith method has many hidden gotchas. Exceptions thrown synchronously, exceptions wrapped in AggregateExceptions, TaskScheduler.Current ambiguity, SynchronizationContext not captured, nested Task<Task>s not properly unwrapped, will all come and bite you at one point or another, if you get in the habit of following the ContinueWith route.

Calling Async Method from Sync Method

I see a lot of questions about calling asyc methods from sync ones, like here: How to call asynchronous method from synchronous method in C#?
I understand the solutions however, experimentally, I am seeing that I don't need to add a .Wait() or Task.Run(async () => await MyAsyncMethod()) for it to run synchronously. I have a get method that pulls information from a DB.
My code is below and when I run, it waits at var task = GetItemAsync() and I get the correct result from the DB. I find it hard to believe that the DB call could come back before the code would move on which seems to imply that it ran synchronously. Am I missing something?
public object GetItem()
{
var task = GetItemAsync();
var result = task.Result;
return result
}
See The docs on Task<>.Result
System.Threading.Tasks.Task.Result is a blocking call that waits until the task finishes. So it has a built in wait call essentially.
In the remarks section of that microsoft doc:
Accessing the property's get accessor blocks the calling thread until the asynchronous operation is complete; it is equivalent to calling the Wait method.
It's unfortunate that Microsoft did not reflect this in the name of the accessor because it's an extremely critical side effect of this accessor.
The only right way to call awaitable(method which returns Task) method is to await it. But you can await only within the method which returns Task. In legacy code it happens you cannot change the method signature because you have too many reference and you need to basically refactor entire code base. So you have these options:
.Result
.Wait()
.GetAwaiter().GetResult()
Neither of those are good. All of them are going to block the thread. But if you cannot change the method signature to await the execution, I would pick the last option - GetAwaiter().GetResult() becasue it will not wrap the exception into AggregateException

async await vs Result from higher level call?

I have this simple repository method:
public async Task<Blog> GetById(int id)
{
return await _dbContext.Blogs.FirstOrDefaultAsync(p => p.Id == id);
}
I read some answers about async await, but I still don't understand how to call this GetById method properly:
public async Task DoSomething1()
{
var blog = await _blogRepository.GetById(1);
Console.WriteLine(blog.Title);
}
or
public void DoSomething2()
{
var blog = _blogRepository.GetById(1).Result;
Console.WriteLine(blog.Title);
}
Properly means: without blocking the thread like described in this post:
https://msdn.microsoft.com/en-us/magazine/dn802603.aspx?f=255&MSPPError=-2147217396
Personally I think, that correct way is DoSomething2 in this situation.
Because thread blocking happens when FirstOrDefaultAsync is running, so this is reason why I use async and await in GetById method, so is it really need to use one more async await in higher methods like in DoSomething1? can I use Result in this situation like in DoSomething2?
What are the advantages and disadvantages of choices?
(I use .NET 4.5)
Regarding first implementation(DoSomething1) You can read here:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/await
An await expression does not block the thread on which it is executing. Instead, it causes the compiler to sign up the rest of the async method as a continuation on the awaited task. Control then returns to the caller of the async method. When the task completes, it invokes its continuation, and execution of the async method resumes where it left off.
Regarding second (DoSomething2)
According to https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task-1.result?redirectedfrom=MSDN&view=netframework-4.7.2#System_Threading_Tasks_Task_1_Result
Accessing the property's get accessor blocks the calling thread until the asynchronous operation is complete; it is equivalent to calling the Wait method.
Once the result of an operation is available, it is stored and is returned immediately on subsequent calls to the Result property. Note that, if an exception occurred during the operation of the task, or if the task has been cancelled, the Result property does not return a value.
To prove it, You can check thread id's before executing and after. For example
var threadId1 = Thread.CurrentThread.ManagedThreadId;
var blogPost = await DoSomething1();
var threadId2 = Thread.CurrentThread.ManagedThreadId;
var blogPost = DoSomething2().Result;
var threadId3 = Thread.CurrentThread.ManagedThreadId;
If You output thread id's, threadId2 and threadId3 in the result will always be the same, so no thread change happens, and the thread is blocked.
{
"threadId1": 30,
"threadId2": 15,
"threadId3": 15
}
It's DoSomething1() that will avoid blocking, not DoSomething2().
You use the async modifier to specify that a method, lambda expression, or anonymous method is asynchronous
An async method runs synchronously until it reaches its first await expression, at which point the method is suspended until the awaited task is complete, in this case, that would be the GetById async method.
You also have an error waiting to happen in your code...
public async Task DoSomething1()
{
var blog = await _blogRepository.GetById(1);
Console.WriteLine(blog.Title); // this line has the bug
}
The GetById method internally uses FirstOrDefault when searching the underlying database, so if you search for a blog that doesn't exist, the method will return a null object... you're then attempting to access that objects Title property, but because its null... you'll get a null reference exception. Check whether the object is null before attempting to access its properties
Task.Result call will block the calling thread until the operation is completed.
Here is an excellent article explains it well
https://montemagno.com/c-sharp-developers-stop-calling-dot-result/
I know this is a controversial topic and I think it deserves controversial answer so here it goes:
First of all, let me make it clear that DoSomething2 is a blocking method; meaning it will run on calling thread and block the calling thread, while DoSomething1 will not block the calling thread and will run on thread pool thread instead.
Now, from my understanding of async methods, their sole purpose is to allow parallelism and hence maximum usage of your CPU. What that means from the desktop developer perspective is, you could have a responsive UI when you call async method and you could update UI while work is being offloaded to non-main thread.
If your application is designed to run units of work in parallel then it makes sense, to me, to use DoSomething1 instead of DoSomething2 as you could get maximum usage out of your CPU, but if your application is designed to run units of work in sequential manner (as I believe you are doing in your console application) you wouldn't be getting any benefit from using DoSomething1 as there will be only one operation running at a time and I would use DoSomething2 instead.
With that being said, you can use AsyncContext.Run(() => MyMethodAsync(args)); in your console app to run your async method on separate context.
To summarize, unless your console app is doing some parallel work on threads, I would say you will be fine using DoSomething2.
P.S you should fix the bug mentioned by #AydinAdn.
if await is applied to the result of a method call that returns a Task Result, then the type of the await expression is Result. If await is applied to the result of a method call that returns a Task, then the type of the await expression is void

Return a Task instead of awaiting the inner method call [duplicate]

This question already has answers here:
At the end of an async method, should I return or await?
(2 answers)
Closed 5 years ago.
I see some colleague code where he chooses to not await the database call and just return the Task. E.g.
public Task<UpdateResult> AddActivityAsync(ClaimsPrincipal principal, Activity activity)
{
return _userManager.SaveToDatabaseAsync(principal, activity);
}
as _userManager.SaveToDatabaseAsync is async, I would have implemented this way
public async Task<UpdateResult> AddActivityAsync(ClaimsPrincipal principal,
Activity activity)
{
return await _userManager.SaveToDatabaseAsync(principal, activity);
}
The calling method of this method always await it:
await _profile.AddActivityAsync(..., ...)
Is there any benefit to not make the inner method async and just return the Task, letting the caller await it ? I thought we had to write Async all the way down...
It depends on the situation.
You must await, for example, if the code to be awaited is bound to an object that is in an using context (or gets manually disposed):
using (SomeDisposableType obj = ...)
{
await obj.SomeOperationAsync();
}
If you returned the task without awaiting it, then the method might complain that the object had been disposed before it could have finished its job. (not all disposable objects throw an ObjectDisposedException if you attempt to perform something on them after they get disposed but it is generally a good idea to assume so). Consider the opposite:
using (SomeDisposableType obj = ...)
{
// This returns the Task that represents the async operation,
// and because it returns, the control goes out of the using
// scope, and therefore obj gets disposed.
return obj.SomeOperationAsync();
}
So there are cases when awaiting is necessary. If that is not the case, I can't really think of a reason why you couldn't return the Task itself.
You do not need to await a method which returns a Task<T>, the code will just run asynchronously if you have the async keyword on the method. You colleague has removed that and so is running synchronously deliberately and lets the calling code implement it if they so choose.
It depends at which layer this code is being run. If it is deep it may be better to let the higher code layers choose ansynchronous execution and maintain control there.
You definitely don't need to 'write async all the way down'. The purpose of the async keyword is simply to mark a method as being able to return a Task<T> and be able to use the await keyword. The await keyword is what invokes the framework to execute the Task and provide asynchronous processing.
TL;DR: It's a choice.
I welcome anyone improving or correcting me on this as I am no guru.

Entity Framework, DBContext and using() + async?

There is a thing that's been bugging me for a long time about Entity Framework.
Last year I wrote a big application for a client using EF. And during the development everything worked great.
We shipped the system in august. But after some weeks I started to see weird memory leaks on the production-server. My ASP.NET MVC 4 process was taking up all the resources of the machine after a couple of days running (8 GB). This was not good. I search around on the net and saw that you should surround all your EF queries and operations in a using() block so that the context can be disposed.
In a day I refactored all my code to use using() and this solved my problems, since then the process sits on a steady memory usage.
The reason I didn't surround my queries in the first place however is that I started my first controllers and repositories from Microsofts own scaffolds included in Visual Studio, these did not surround it's queries with using, instead it had the DbContext as an instance variable of the controller itself.
First of all: if it's really important to dispose of the context (something that wouldn't be weird, the dbconnection needs to be closed and so on), Microsoft maybe should have this in all their examples!
Now, I have started working on a new big project with all my learnings in the back of my head and I've been trying out the new features of .NET 4.5 and EF 6 async and await. EF 6.0 has all these async methods (e.g SaveChangesAsync, ToListAsync, and so on).
public Task<tblLanguage> Post(tblLanguage language)
{
using (var langRepo = new TblLanguageRepository(new Entities()))
{
return langRepo.Add(RequestOrganizationTypeEnum, language);
}
}
In class TblLanguageRepo:
public async Task<tblLanguage> Add(OrganizationTypeEnum requestOrganizationTypeEnum, tblLanguage language)
{
...
await Context.SaveChangesAsync();
return langaugeDb;
}
However, when I now surround my statements in a using() block I get the exception, DbContext was disposed, before the query has been able to return. This is expected behaviour. The query runs async and the using block is finished ahead of the query. But how should I dispose of my context in a proper way while using the async and await functions of ef 6??
Please point me in the right direction.
Is using() needed in EF 6? Why do Microsoft's own examples never feature that? How do you use async features and dispose of your context properly?
Your code:
public Task<tblLanguage> Post(tblLanguage language)
{
using (var langRepo = new TblLanguageRepository(new Entities()))
{
return langRepo.Add(RequestOrganizationTypeEnum, language);
}
}
is disposing the repository before returning a Task. If you make the code async:
public async Task<tblLanguage> Post(tblLanguage language)
{
using (var langRepo = new TblLanguageRepository(new Entities()))
{
return await langRepo.Add(RequestOrganizationTypeEnum, language);
}
}
then it will dispose the repository just before the Task completes. What actually happens is when you hit the await, the method returns an incomplete Task (note that the using block is still "active" at this point). Then, when the langRepo.Add task completes, the Post method resumes executing and disposes the langRepo. When the Post method completes, the returned Task is completed.
For more information, see my async intro.
I would go for the 'one DbContext per request' way, and reuse the DbContext within the request. As all tasks should be completed at the end of the request anyway, you can safely dispose it again.
See i.e.: One DbContext per request in ASP.NET MVC (without IOC container)
Some other advantages:
some entities might already be materialized in the DbContext from
previous queries, saving some extra queries.
you don't have all those extra using statements cluttering your code.
If you are using proper n-tiered programming patters, your controller should never even know that a database request is being made. That should all happen in your service layer.
There are a couple of ways to do this. One is to create 2 constructors per class, one that creates a context and one that accepts an already existing context. This way, you can pass the context around if you're already in the service layer, or create a new one if it's the controller/model calling the service layer.
The other is to create an internal overload of each method and accept the context there.
But, yes, you should be wrapping these in a using.
In theory, the garbage collection SHOULD clean these up without wrapping them, but I don't entirely trust the GC.
I agree with #Dirk Boer that the best way to manage DbContext lifetime is with an IoC container that disposes of the context when the http request completes. However if that is not an option, you could also do something like this:
var dbContext = new MyDbContext();
var results = await dbContext.Set<MyEntity>.ToArrayAsync();
dbContext.Dispose();
The using statement is just syntactic sugar for disposing of an object at the end of a code block. You can achieve the same effect without a using block by simply calling .Dispose yourself.
Come to think of it, you shouldn't get object disposed exceptions if you use the await keyword within the using block:
public async Task<tblLanguage> Post(tblLanguage language)
{
using (var langRepo = new TblLanguageRepository(new Entities()))
{
var returnValue = langRepo.Add(RequestOrganizationTypeEnum, language);
await langRepo.SaveChangesAsync();
return returnValue;
}
}
If you want to keep your method synchronous but you want to save to DB asynchronously, don't use the using statement. Like #danludwig said, it is just a syntactic sugar. You can call the SaveChangesAsync() method and then dispose the context after the task is completed. One way to do it is this:
//Save asynchronously then dispose the context after
context.SaveChangesAsync().ContinueWith(c => context.Dispose());
Take note that the lambda you pass to ContinueWith() will also be executed asynchronously.
IMHO, it's again an issue caused by usage of lazy-loading. After you disposed your context, you can't lazy-load a property anymore because disposing the context closes the underlying connection to the database server.
If you do have lazy-loading activated and the exception occurs after the using scope, then please see https://stackoverflow.com/a/21406579/870604

Categories