I have some code in my business logic layer which consume some repositories which in turn use a DbContext (in the data layer). Most of the code is async. At some point in my business logic, I call several async method of the repositories at once (Task.WhenAll...))
And I ran into an error A second operation started on this context before a previous asynchronous operation completed
My point of view is, the business logic should not care/be aware on how the repositories do their job, so it should be able to use parallelism on async Task if "it pleases so".
So I would like to be able to lock in an async/await friendly way the critical moment where A second operation should wait until the previous asynchronous operation complete.
How can this be done?
Current work-arround: forget Task.WhenAll use await like TPL don't even exist
var postsResult = await _IUserLogic.GetActivePostsAsync();
var usersResult = await _IUserLogic.SearchUsersWithPostAsync(viewModel.Name, viewModel.PostId);
Code To-be
var postsTask = _IUserLogic.GetActivePostsAsync();
var usersTask = _IUserLogic.SearchUsersWithPostAsync(viewModel.Name, viewModel.PostId);
await Ask.WhenAll(postsTask , usersTask );
var postsResult = postsTask.Result;
var usersResult = usersTask.Result;
Each thread needs its own DbContext because DbContext is not thread safe. However, there are a few work-arounds here.
Each repository gets their own, new DbContext. That way, each has their own instance on their own thread. If you need this to be a single transaction, you can use Transaction Scope (newest version allows async calls).
The business layer passes the dbcontext into each repository and will call save changes once at the end. Each repository simply adds their data to the DbSets and you have a single call at the end.
(Worst) Override SaveChanges on DbContext in your instance and create your own lock() so all go through there. However, his pretty much defeats the purpose of Task.WhenAll since you can only save one at a time, anyway.
Do what you did and call them individually.
Related
I'm trying to figure out how to use async/await in C# in my Asp.Net MVC.
The main point seems to be that it helps asp.net for releasing threads from the worker pool when you are doing IO (so they can process other stuff). For doing so you have to promote the async/await modifier from the method doing the IO call up to the controller action (you better have just a few layers).
Is there any point in using this feature without promoting the async/await up to my controller ? (by adding Task.Wait after a call to an Async method for instance).
The answer is "yes", but using Task.Wait() in an action is not a good idea because it can lead to a deadlock situation.
Consider the following from the guide, Async/Await Best Practice by Stephen Cleary:
Figure 3 A Common Deadlock Problem When Blocking on Async Code
public static class DeadlockDemo
{
private static async Task DelayAsync()
{
await Task.Delay(1000);
}
// This method causes a deadlock when called in a GUI or ASP.NET context.
public static void Test()
{
// Start the delay.
var delayTask = DelayAsync();
// Wait for the delay to complete.
delayTask.Wait();
}
}
However, if you add ConfigureAwait(false) to DelayAsync() like this:
await Task.Delay(1000).ConfigureAwait(false)
then you can avoid deadlocks, as explained in the article:
Aside from performance, ConfigureAwait has another important aspect: It can avoid deadlocks. Consider Figure 3 again; if you add “ConfigureAwait(false)” to the line of code in DelayAsync, then the deadlock is avoided. This time, when the await completes, it attempts to execute the remainder of the async method within the thread pool context. The method is able to complete, which completes its returned task, and there’s no deadlock. This technique is particularly useful if you need to gradually convert an application from synchronous to asynchronous.
Do not use Task.Wait as it can deadlock or produce an AggregateException. If you need to do this then you should use Task.WhenAll which is non-blocking.
Generally though, it is safest to use async code end-to-end. The benefit of using async away through the entire stack is that your code will be easier to debug and error handling much simpler.
So yes, if you are going to use async/await - include it in your controller and avoid using blocking code like Task.Wait.
I'm developing an ASP.NET MVC5 application and I have the following situation:
Async controller method calls custom async method 1+ times, each Task object being stored successively in a List
Each custom async method call establishes its own top-level TransactionScope with TransactionScopeAsyncFlow.Enabled
Each custom async method call performs transactional work, then awaits DbContext.SaveChangesAsync()
While this is occurring, the controller method performs its own transactional work within its own unrelated TransactionScope, then awaits Task.WhenAll()
The question arises from using ConfigureAwait(false) when awaiting DbContext.SaveChangesAsync(). Each call to the custom async method starts in the controller method's ASP.NET request context but I don't see any need to recapture it when SaveChangesAsync() returns EXCEPT if it's going to mess up the current transaction. This is important because if an unrecoverable exception occurs in the controller method before I await Task.WhenAll, I need to cancel the async Tasks within a catch block, which means instead of awaiting Task.WhenAll() I'm forced to use the blocking method Task.WaitAll(), which I'm pretty sure will deadlock if the async Tasks are trying to recapture the original request context.
Sorry if this is a repeat question. I did quite a bit of searching and couldn't get a clear answer. Feel free to tell me this is bad programming or whatever, just at least suggest an alternative and leave my mom out of it. Thanks!
How to manage new tasks with PerRequestLifeTimeManager?
Should I create another container inside a new task?(I wouldn't like to change PerRequestLifeTimeManager to PerResolveLifetimeManager/HierarchicalLifetimeManager)
[HttpPost]
public ActionResult UploadFile(FileUploadViewModel viewModel)
{
var cts = new CancellationTokenSource();
CancellationToken cancellationToken = cts.Token;
Task.Factory.StartNew(() =>
{
// _fileService = DependencyResolver.Current.GetService<IFileService>();
_fileService.ProcessFile(viewModel.FileContent);
}, cancellationToken);
}
You should read this article about DI in multi-threaded applications. Although it is written for a different DI library, you'll find most of the information applicable to the concept of DI in general. To quote a few important parts:
Dependency injection forces you to wire all dependencies together in a
single place in the application: the Composition Root. This means that
there is a single place in the application that knows about how
services behave, whether they are thread-safe, and how they should be
wired. Without this centralization, this knowledge would be scattered
throughout the code base, making it very hard to change the behavior
of a service.
In a multi-threaded application, each thread should get its own object
graph. This means that you should typically call
[Resolve<T>()] once at the beginning of the thread’s
execution to get the root object for processing that thread (or
request). The container will build an object graph with all root
object’s dependencies. Some of those dependencies will be singletons;
shared between all threads. Other dependencies might be transient; a
new instance is created per dependency. Other dependencies might be
thread-specific, request-specific, or with some other lifestyle. The
application code itself is unaware of the way the dependencies are
registered and that’s the way it is supposed to be.
The advice of building a new object graph at the beginning of a
thread, also holds when manually starting a new (background) thread.
Although you can pass on data to other threads, you should not pass on
container-controlled dependencies to other threads. On each new
thread, you should ask the container again for the dependencies. When
you start passing dependencies from one thread to the other, those
parts of the code have to know whether it is safe to pass those
dependencies on. For instance, are those dependencies thread-safe?
This might be trivial to analyze in some situations, but prevents you
to change those dependencies with other implementations, since now you
have to remember that there is a place in your code where this is
happening and you need to know which dependencies are passed on. You
are decentralizing this knowledge again, making it harder to reason
about the correctness of your DI configuration and making it easier to
misconfigure the container in a way that causes concurrency problems.
So you should not spin of new threads from within your application code itself. And you should definitely not create a new container instance, since this can cause all sorts of performance problems; you should typically have just one container instance per application.
Instead, you should pull this infrastructure logic into your Composition Root, which allows your controller's code to be simplified. Your controller code should not be more than this:
[HttpPost]
public ActionResult UploadFile(FileUploadViewModel viewModel)
{
_fileService.ProcessFile(viewModel.FileContent);
}
On the other hand, you don't want to change the IFileService implementation, because it shouldn't its concern to do multi-threading. Instead we need some infrastructural logic that we can place in between the controller and the file service, without them having to know about this. They way to do this is by implementing a proxy class for the file service and place it in your Composition Root:
private sealed class AsyncFileServiceProxy : IFileService {
private readonly ILogger logger;
private readonly Func<IFileService> fileServiceFactory;
public AsyncFileServiceProxy(ILogger logger, Func<IFileService> fileServiceFactory)
{
this.logger = logger;
this.fileServiceFactory = fileServiceFactory;
}
void IFileService.ProcessFile(FileContent content) {
// Run on a new thread
Task.Factory.StartNew(() => {
this.BackgroundThreadProcessFile(content);
});
}
private void BackgroundThreadProcessFile(FileContent content) {
// Here we run on a different thread and the
// services should be requested on this thread.
var fileService = this.fileServiceFactory.Invoke();
try {
fileService.ProcessFile(content);
}
catch (Exception ex) {
// logging is important, since we run on a
// different thread.
this.logger.Log(ex);
}
}
}
This class is a small peace of infrastructural logic that allows processing files on a background thread. The only thing left is to configure the container to inject our AsyncFileServiceProxy instead of the real file service implementation. There are multiple ways to do this. Here's an example:
container.RegisterType<ILogger, YourLogger>();
container.RegisterType<RealFileService>();
container.RegisterType<Func<IFileService>>(() => container.Resolve<RealFileService>(),
new ContainerControlledLifetimeManager());
container.RegisterType<IFileService, AsyncFileServiceProxy>();
One part however is missing here from the equation, and this is how to deal with scoped lifestyles, such as the per-request lifestyle. Since you are running stuff on a background thread, there is no HTTPContext and this basically means that you need to start some 'scope' to simulate a request (since your background thread is basically its own new request). This is however where my knowledge about Unity stops. I'm very familiar with Simple Injector and with Simple Injector you would solve this using a hybrid lifestyle (that mixes a per-request lifestyle with a lifetime-scope lifestyle) and you explicitly wrap the call to BackgroundThreadProcessFile in such scope. I imagine the solution in Unity to be very close to this, but unfortunately I don't have enough knowledge of Unity to show you how. Hopefully somebody else can comment on this, or add an extra answer to explain how to do this in Unity.
I have an ASP.NET MVC 4 application targeting .NET 4.5. One of our child actions makes a call out to a web service using HttpClient.
Since we're blocking on IO waiting for the HttpClient response, it makes a great deal of sense to convert the code to the async/await pattern. However, when MVC 4 attempts to execute the child action, we get the following error message:
HttpServerUtility.Execute blocked while waiting for an asynchronous operation to complete.
At first glance, it appears as though MVC 4 does not support async/await within a child action. The only remaining option is to run using synchronous code and force a "Wait" on the async task.
As we all know, touching .Result or .Wait() on an async task in an ASP.NET context will cause an immediate deadlock. My async logic is wrapped in a class library, so I can't use the "await blah.ConfigureAwait(false)" trick. Remember, tagging "async" on the child action and using await causes an error, and that prevents me from configuring the await.
I'm painted into a corner at this point. Is there any way to consume async methods in an MVC 4 child action? Seems like a flat out bug with no workarounds.
There are still parts of MVC that aren't async-friendly; I hope these will be addressed in the future. Please do create a Connect or UserVoice issue for this.
My async logic is wrapped in a class library, so I can't use the "await blah.ConfigureAwait(false)" trick.
You probably should add ConfigureAwait(false) to the calls in your class library (if you can).
You could also hack up an alternate solution. If your class library method doesn't need the ASP.NET context, then you could have a thread pool thread do the (a)waiting for you:
try
{
var result = Task.Run(async () => { await MyHttpRequest(...); }).Result;
}
catch (AggregateException ex) { ... }
The effect is similar to ConfigureAwait(false): since MyHttpRequest runs in a thread pool context, it will not attempt to enter the ASP.NET context when it completes.
The format of Stephen's answer didn't quite work for me (maybe it's an async noob problem, but hey).
I had to do write the async expression in this format to get a strongly typed return value.
Person myPerson = Task.Run(() => asyncMethodWhichGetsPerson(id)).Result;
When I bind my context as InRequestScope, the context is disposed when the code in DelegatingHandler is called (instantiated in Application_Start and executed before controllers are initialized). If I use InTransientScope, then it works but I want 1 context for everything. Based on this answer here, it is the correct way to have 1 context.
Global.asax
static void Configure(HttpConfiguration config)
{
var kernel = NinjectWebCommon.Bootstrapper.Kernel;
config.MessageHandlers.Add(new ApiKeyHandler(kernel.Get<IApiService>()));
}
Bindings
//if i remove InRequestScope here, everything works.
kernel.Bind<EntityDatabaseContext>().ToMethod(context => new EntityDatabaseContext()).InRequestScope();
kernel.Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope();
//repositories
kernel.Bind<IRepository<Application>>().To<Repository<Application>>().InRequestScope();
//services
kernel.Bind<IApiService>().To<ApiService>().InRequestScope();
So Whenever SendAsync gets called in ApiKeyHandler, the context was already disposed. But when a controller is called (after calling the ApiKeyHandler), the context is fine. I'm not too sure what is going on. If it cannot work with InRequestScope, how can I accomplish it like how the answer in the linked question did it? 1 context InTransientScope and all others in InRequestScope?
Using a transient or singleton scoped context for your message handler gives you the limitation that all the entities will be cached for the message handler. E.g. if an entity is changed/deleted or a new one is added your message handler will never adapt to that change. This can be ok in some scenarios where the data is never changed.
If you need to operate on up to date data that will change you can't use these scopes. But InRequestScope means that you have to create a new instance of the service every time using a factory (see factory extension). That way you can have the context in request scope.