I have been crawling around on Google a bit now to find any useful examples on how to use Ninject together async/await operations. I have also tried a bit myself to find any pattern that makes this actually work without having to write a lot of code, but I haven't managed to make it work.
To take the most simple description of the basic problem is that the Entity Framework DbContext is created on a per request scope basis (it's an ASP.NET MVC app), but if you try to call any *Async methods it will fail with information that it's already working with an execution (which is obvious enough).
So, what I need is that the call Kernel.Get<MyContext>() creates unique DbContext objects using Ninject and which Ninject takes care of the lifecycle of. Using BeginBlock() or changing scope to InTransientScope() isn't really an option since the first will make the code quite heavy with seperate blocks and disposing of these and the latter set's the caller code as responsible to dispose the DbContext.
An POC example of the code I want to do:
var context1 = NinjectKernelReference.Get<MyContext>(); //I want this to be a unique reference
var context2 = NinjectKernelReference.Get<MyContext>(); //I want this to be a unique reference
var task1 = context1.Customers.Where(c => c.ZipCode == "4444")
.Select(c => new {
c.Name,
c.PhoneNumber
})
.Take(50)
.ToArrayAsync();
var task2 = context2.Customers.CountAsync(c => c.ZipCode == "4444");
Task.WaitAll(task1, task2);
return new Result { task1.Result, task2.Result };
So, is there any way to solve this the "easy" way?
this is how you can control creation of objects yourself:
public interface IContextFactory {
MyContext Create();
}
kernel.Bind<IContextFactory>().ToFactory // requires ninjext.extensions.factory
(Factory Extension Link)
usage:
using(var context1 = IContextFactory.Create())
using(var context2 = IContextFactory.Create())
{
var task1 = context1.Customers.Where(c => c.ZipCode == "4444")
.Select(c => new {
c.Name,
c.PhoneNumber
})
.Take(50)
.ToArrayAsync();
var task2 = context2.Customers.CountAsync(c => c.ZipCode == "4444");
Task.WaitAll(task1, task2);
return new Result { task1.Result, task2.Result };
} // context get's disposed here
note: this requires the context not be bound .InRequestScope(), otherwise, the same object will be returned for both .Create()calls.
If you sometimes need them .InRequestScope() and sometimes not, you might consider using ninject contextual binding
After some digging and reading the response of other users on this post, I realize that it isn't any easy way to do this.
So I decided to go for using the IKernel.BeginBlock to create a "local" Ninject scope within the Parallel thread execution where I did my logic.
It may not be so neat as I would like, but it works.
using( var block1 = NinjectKernelReference.BeginBlock())
using( var block2 = NinjectKernelReference.BeginBlock())
{
var context1 = block1.Get<MyContext>();
var context2 = block2.Get<MyContext>();
var task1 = context1.Customers.Where(c => c.ZipCode == "4444")
.Select(c => new {
c.Name,
c.PhoneNumber
})
.Take(50)
.ToArrayAsync();
var task2 = context2.Customers.CountAsync(c => c.ZipCode == "4444");
Task.WaitAll(task1, task2);
return new Result { task1.Result, task2.Result };
}
It may not be that neat, but it works and I can't see any downsides with this (other than maybe some minor performance issues with BeginBlock and Disposing of it).
Related
After browsing different await vs Task.Run questions on SO my takeaway is that await is better for I/O operations and Task.Run for CPU-intensive operations. However the code with await seems to always be longer than Task.Run. Below is an example method of how I am creating a context object with await in my app:
public async AppContext CreateAppContext()
{
var context = new AppContext();
var customersTask = _dataAccess.GetCustomers();
var usersTask = _dataAccess.GetUsers();
var reportsTask = _dataAccess.GetReports();
context.Customers = await customersTask;
context.Users = await usersTask;
context.Reports = await reportsTask;
return context;
}
If I was to rewrite this with Task.Run I could do
public async AppContext CreateAppContext()
{
var context = new AppContext();
await Task.WhenAll(new[]
{
Task.Run(async () => { context.Customers = await _dataAccess.GetCustomers(); }),
Task.Run(async () => { context.Users = await _dataAccess.GetUsers(); }),
Task.Run(async () => { context.Reports = await _dataAccess.GetReports(); });
})
return context;
}
The difference is not major when I create an object with 3 properties but I have objects where I need to initialize 20+ properties in this manner which makes the await code a lot longer (nearly double) than Task.Run. Is there a way for me to initialize the object using await with code that is not a lot longer than what I can do with Task.Run?
Personally, I prefer an asynchronous factory pattern over that kind of code; but if you need to do concurrent asynchronous work like that multiple times, then you'll probably want to write your own helper method.
The BCL-provided WhenAll works best when either all tasks have no results, or when all tasks have the same type of result. One fairly common approach to help WhenAll work with different types of tasks is to return a tuple of results, which can then be deconstructed into different variables if desired. E.g.,
public static class TaskEx
{
public static async Task<(T1, T2, T3)> WhenAll<T1, T2, T3>(Task<T1> task1, Task<T2> task2, Task<T3> task3)
{
await Task.WhenAll(task1, task2, task3);
return (await task1, await task2, await task3);
}
}
// Usage
public async AppContext CreateAppContext()
{
var context = new AppContext();
(context.Customers, context.Users, conext.Reports) =
await TaskEx.WhenAll(
_dataAccess.GetCustomers(),
_dataAccess.GetUsers(),
_dataAccess.GetReports());
return context;
}
You can even define a tuple GetAwaiter extension method if you want, to make it more implicit:
// Usage
public async AppContext CreateAppContext()
{
var context = new AppContext();
(context.Customers, context.Users, conext.Reports) =
await (
_dataAccess.GetCustomers(),
_dataAccess.GetUsers(),
_dataAccess.GetReports());
return context;
}
There are a couple of disadvantages to these approaches, though. First, you have to define as many overloads as you need. Second, the multiple-assignment code is not very nice; it's fine for 2 or 3 properties, but would get ugly (IMO) if done for much more than that.
So I think what you really want is a custom delegate form of WhenAll. Something like this should work:
public static class TaskEx
{
public static async Task WhenAll(params Func<Task>[] tasks)
{
return Task.WhenAll(tasks.Select(action => action()));
}
}
// Usage
public async AppContext CreateAppContext()
{
var context = new AppContext();
await TaskEx.WhenAll(
async () => context.Customers = await _dataAccess.GetCustomers(),
async () => context.Users = await _dataAccess.GetUsers(),
async () => conext.Reports = await _dataAccess.GetReports());
return context;
}
Since this solution avoids dealing with the different result types entirely, multiple overloads aren't needed.
If you really want to keep your general pattern (which I'd avoid - it would be much better to do all the work and then assign all the results at the same time; look into the return value of Task.WhenAll), all you need is a simple helper method:
static async Task Assign<T>(Action<T> assignment, Func<Task<T>> getValue)
=> assignment(await getValue());
Then you can use it like this:
await Task.WhenAll
(
Assign(i => context.Customers = i, _dataAccess.GetCustomers),
Assign(i => context.Users = i, _dataAccess.GetUsers),
Assign(i => context.Reports = i, _dataAccess.GetReports)
);
There's many other ways to make this even simpler, but this is the most equivalent to your Task.Run code without having to involve another thread indirection just to do an assignment. It also avoids the very common mistake when you happen to use the wrong Task.Run overload and get a race condition (as Task.Run returns immediately instead of waiting for the result).
Also, you misunderstood the "await vs. Task.Run" thing. There's actually not that much difference between await and Task.Run in your code - mainly, it forces a thread switch (and a few other subtle things). The argument is against using Task.Run to run synchronous code; that wastes a thread waiting for a thing to complete, your code doesn't.
Do keep in mind that WhenAll comes with its own complications, though. While it does mean you don't have to worry about some of the tasks ending up unobserved (and not waited on!), it also means you have to completely rethink your exception handling, since you're going to get an AggregateException rather than anything more specific. If you're relying on error handling based on identifying exceptions, you need to be very careful. Usually, you don't want AggregateException to leak out of methods - it's very difficult to handle in a global manner; the only method that knows the possibilities of what can happen is the method that calls the WhenAll. Hopefully.
It's definitely a good idea to run parallel operations like this in a way that cannot produce dangerous and confusing side-effects. In your code, you either get a consistent object returned, or you get nothing - that's exactly the right approach. Be wary of this approach leaking into other contexts - it can get really hard to debug issues where randomly half of the operations succeed and other half fails :)
Is there a way for me to initialize the object using await with code that is not a lot longer than what I can do with Task.Run?
If you want to run all tasks in parallel - in short no, you cant shorten number of lines. Also note that those two snippets are not fully functionally equivalent - see Why should I prefer single await Task.WhenAll over multiple awaits.
You can simplify (and maybe even improve performance a bit) your Task.WhenAll approach by introducing a method which will await and assign. Something along these lines:
public async AppContext CreateAppContext()
{
var context = new AppContext();
await Task.WhenAll(
AwaitAndAssign(val => context.Customers = val, _dataAccess.GetCustomers()),
AwaitAndAssign(val => context.Users = val, _dataAccess.Users()),
AwaitAndAssign(val => context.Reports = val, _dataAccess.GetReports())
);
return context;
async Task AwaitAndAssign<T>(Action<T> assign, Task<T> valueTask) =>
assign(await valueTask);
}
I am using the toolkit languageext package for C# and am running into a problem with the Either class when the Right value is some kind of Task. For some reason this is causing a hang:
var res = repo.GetAccountWithID(accountID)
.Map(c => filesServiceCustomer.Initialize(c))
.Bind(t => t.Result);
Here, GetAccountWithID returns an Either<Exception, Account> and the Initialize method take an Account and returns a Task<Either<Exception, bool>>. However, it would appear that either the Map or Bind calls are hanging.
Does anyone have any idea what might be causing this or what to do about it?
(I'm the author of the language-ext project). There's no fundamental reason for your expression to hang, other than if the Task itself is blocking - Map and Bind are trivial functions that don't do anything particularly clever, and definitely don't do any synchronisation or anything like that. I just added this code to the unit tests in lang-ext, and it returns fine:
public class Account : NewType<Account, Unit>
{
public Account(Unit _) : base(unit) { }
}
Either<Exception, Account> GetAccountWithID(int accountId) =>
Account.New(unit);
Task<Either<Exception, bool>> Initialize(Account c) =>
Task.FromResult(Right<Exception, bool>(true));
[Fact]
public void StackOverflowQuestion()
{
int accountID = 0;
var res = GetAccountWithID(accountID)
.Map(c => Initialize(c))
.Bind(t => t.Result);
}
One thing it's worth mentioning is that it's not great practice to call .Result on a task. You can definitely leverage other features in language-ext to make this work better for you:
For example:
var task = from c in GetAccountWithID(accountID).AsTask()
from r in Initialize(c)
select r;
AsTask lifts the Either<Exception, Account> into a Task<Either<Exception, Account>>, which then means it's usable in a LINQ expression with Initialize (which also returns a Task).
If you're fundamentally opposed to the LINQ syntax, then you can do:
var task = GetAccountWithID(accountID).AsTask().BindT(Initialize);
task is then a Task<Either<Exception, bool>> which you can await:
var res = (await task).IfLeft(false);
Another trick (if you're using version 2.0.*) is to use Sequence which flips the inner and outer monads:
var res = task.Sequence();
That will turn the Task<Either<Exception, bool>> into a Either<Exception, Task<bool>> which you can match on. Obviously it depends on your use-case as to what's most appropriate.
Most probably, your environment has a synchronization context and calling Result or Wait will almost always deadlock.
I don't know what that library does, but this will probably work:
var res = (await repo.GetAccountWithID(accountID)
.Map(c => filesServiceCustomer.Initialize(c)))
.Bind(t => t);
A little more context here on what I found and what is happening. I managed to 'fix' the problem though I am not sure exactly what was causing it or why the fix is needed.
First of all this is running in an Azure API app service. Not sure if that makes a difference or not but it is included for completeness.
Inside the Initialize function there were two lines at the end that look like this:
rootDir = someShare.GetRoodDirectoryReference();
...
dir1 = rootDir.GetDirectoryReference(dir1Name);
await dir1.CreateIfNotExistsAsync();
dir2 = rootDir.GetDirectoryReference(dir2Name);
await dir2.CreateIfNotExistsAsync();
The code was hanging on the await of the first CreateIfNotExistAsync() call (whichever was in that position, it didn't matter). However, I changed this to:
dir1 = rootDir.GetDirectoryReference(dir1Name);
dir2 = rootDir.GetDirectoryReference(dir2Name);
Task<bool> tasks = {
Task.Run(dir1.CreateIfNotExistAsync),
Task.Run(dir2.CreateIfNotExistAsync),
};
Task.WaitAll(tasks);
And, like magic, no more hang!
Now my calling code works as expected. I don't know why this fix is needed. The only thing I can think of is that the continuation created by the await statements were somehow causing a problem. I don't really want to dig into the guts of the compiler-generated continuations if I don't have to, though.
In Scala there is a Promise class that could be used to complete a Future manually. I am looking for an alternative in C#.
I am writing a test and I want it to look it similar to this:
// var MyResult has a field `Header`
var promise = new Promise<MyResult>;
handlerMyEventsWithHandler( msg =>
promise.Complete(msg);
);
// Wait for 2 seconds
var myResult = promise.Future.Await(2000);
Assert.Equals("my header", myResult.Header);
I understand that this is probably not the right pattern for C#, but I couldn't figure out a reasonable way to achieve the same thing even with somewhat different pattern.
EDIT: please note, that async/await doesn't help here, as I don't have a Task to await! I just have an access to a handler that will be run on another thread.
In C#:
Task<T> is a future (or Task for a unit-returning future).
TaskCompletionSource<T> is a promise.
So your code would translate as such:
// var promise = new Promise<MyResult>;
var promise = new TaskCompletionSource<MyResult>();
// handlerMyEventsWithHandler(msg => promise.Complete(msg););
handlerMyEventsWithHandler(msg => promise.TrySetResult(msg));
// var myResult = promise.Future.Await(2000);
var completed = await Task.WhenAny(promise.Task, Task.Delay(2000));
if (completed == promise.Task)
; // Do something on timeout
var myResult = await completed;
Assert.Equals("my header", myResult.Header);
The "timed asynchronous wait" is a bit awkward, but it's also relatively uncommon in real-world code. For unit tests, I would just do a regular asynchronous wait:
var promise = new TaskCompletionSource<MyResult>();
handlerMyEventsWithHandler(msg => promise.TrySetResult(msg));
var myResult = await promise.Task;
Assert.Equals("my header", myResult.Header);
The rough C# equivalent without third-party libraries would be:
// var MyResult has a field `Header`
var promise = new TaskCompletionSource<MyResult>();
handlerMyEventsWithHandler(msg =>
promise.SetResult(msg)
);
// Wait for 2 seconds
if (promise.Task.Wait(2000))
{
var myResult = promise.Task.Result;
Debug.Assert("my header" == myResult.Header);
}
Note that it is usually best to use the await/async to as high a level as possible. Accessing the Result of a Task or using Wait can in some cases introduce deadlocks.
You can use C# Promises library
Open sourced on Github: https://github.com/Real-Serious-Games/C-Sharp-Promise
Available on NuGet: https://www.nuget.org/packages/RSG.Promise/
This is the old school way of doing Promises.
Back then i believe it was called synchronization :)
MyResult result = null;
var are = new AutoResetEvent(false);
handlerMyEventsWithHandler(
msg => {result = msg; are.Set();}
);
// Wait for 2 seconds
if(!are.WaitOne(2000)) {/* handle timeout... */}
Assert.Equals("my header", myResult.Header);
Just for Completeness - to large for a comment.
I agree with Stephen Cleary's answer.
But if you are building a facade around some legacy code this can be used to wrap old API's in a Task like:
public Task<MyResult> GetResultAsync() {
MyResult result = null;
var are = new AutoResetEvent(false);
handlerMyEventsWithHandler(msg => {
result = msg;
are.Set();
});
are.WaitOne();
return Task.FromResult(result);
}
Try looking into the async model. Tasks are the nearest equivalent in c#.
Here's a link to an MS Article explaining their use.
You can download future(https://www.nuget.org/packages/Future/) package from Nuget and can be used as below
Promise<int> promise = new Promise<int>();
new Task(() =>
{
Thread.Sleep(100);
promise.Set(20);
}).Start();
int result=promise.Get();
As per the example you can create a promise object and do a get to get result, get will wait until result is on the object. You do a set from another thread as show in the above example.
This package provides the below two classes
Promise : Which waits indefinitely for the result
TimedPromise : Which waits for the result only till the specified time. If result is not available with in the time, it throws timeout exception
I have a observable made by the Using helper:
var o = Observable.Using(
() => {
return new MyResource
},
res => {
return new Observable.Create<string>(observer => ....);
});
How can I cancel the observable? And by that make sure MyResource is disposed of?
I see there are a Observable.Using( ) that includes a cancellationToken, but signature is so different, that I'm not able to make it work...
Update:
As James points out, by disposing the observable, my resource will be disposed as well. In my case, a plain disposal is not enough. I need to call a method on the resource first. How can that be archived?
You don't need to clean up an observable - just the subscription. Simply call Dispose on the handle returned from Subscribe when you make a subscription to cancel it.
The resource created by the factory delegate supplied as the first argument to Using has a lifetime governed by lifetime of subscriptions to the observable created by Using.
Here's an example:
var xs = Observable.Using(
() => {
var resource = Disposable.Create(() => Console.WriteLine("Binned"));
Console.WriteLine("Created");
return resource;
},
res => Observable.Never<Unit>());
Console.WriteLine("Subscribing");
var sub1 = xs.Subscribe();
var sub2 = xs.Subscribe();
Console.WriteLine("Disposing");
sub1.Dispose();
Gives output:
Subscribing
Created
Created
Disposing
Binned
Since sub2 never finishes and isn't disposed, there is only a single Binned message displayed.
In this example, sub1 completes immediately and there is no cancellation:
var xs = Observable.Using(
() => {
var resource = Disposable.Create(() => Console.WriteLine("Binned"));
Console.WriteLine("Created");
return resource;
},
res => Observable.Return(1));
Console.WriteLine("Subscribing");
var sub1 = xs.Subscribe();
This time the resource is still cleaned up, because the subscription terminated normally:
Subscribing
Created
Binned
The purpose of the overload of Using sporting cancellation tokens is to allow you to cancel asynchronous creation of the resource and the dependent observable. The cancellation tokens are signalled on disposal of subscription handles - of course this scenario is only really going to be useful if you have relatively lengthy creation times and early disposal is likely.
Addendum
To address the corollary to your question:
...a plain disposal is not enough. I need to call a method on the resource first. How can that be [achieved]?
From your resource factory method (the first argument to using), do this:
var xs = Observable.Using(
() =>
{
var processHandle = /* code to create process */
return Disposable.Create(() => /* code to kill process using processHandle */;
},
// Rest of code...
Disposable.Create is a helper method you can use that accepts in Action that's invoked upon disposal.
I am trying to speed up some code of mine,
I make 2 or 3 reads to a slow database, and I want to make these calls run in paralle.
FSKWebInterfaceEntities dbSrc = new FSKWebInterfaceEntities();
public void main()
{
var TaskUsr = GetUserAsync(dev);
var TaskOldCompany = GetOldCompanyAsync(dev);
await Task.WhenAll();
var usr = TaskUsr.Result;
var oldCompanyName = TaskOldCompany.Result;
.....
use my two variables to insert a new entry into my localdb
}
private async Task<ut_User> GetUserAsync(ut_UserAPNdevices dev)
{
return dbSrc.ut_User.FirstOrDefault(x => x.UserID == dev.UserID);
}
private async Task<String> GetOldCompanyAsync(ut_UserAPNdevices dev)
{
return dbSrc.ut_User.FirstOrDefault(x => x.UserID == dev.UserID).Company;
}
On my two helper methods its is underlined green and said that there is no await, and therefore will run synchronously. However I cant return return await dbSrc.ut_User.FirstOrDefault(x => x.UserID == dev.UserID);
How should I modify my code to make the two reads in parallel?
You can await that line because it is not an async method. You can't really await database calls as they are not thread safe. See this thread for an example of a way to do it, and a better explanation as to why not. You can consider using SqlCommands that have async methods as well.
You cannot use the same EF DbContext concurrently. From the EF Team's statement about thread safety:
For the moment, EF will detect if the developer attempts to execute
two async operations at one time and throw.
You still can call them asynchronously, but sequentially:
public async Task main()
{
var sr = await GetUserAsync(dev);
var oldCompany = await GetOldCompanyAsync(dev);
.....
use my two variables to insert a new entry into my localdb
}
Updated to address the comment:
Could you possible post a simple example of how I would change my
above code to use the multiple dbcontext, As I don't really know the
correct way to do it, I would be coding in the dark.
Something like below. I'm not an expert in EF to assure you this will actually improve the processing time. There may be significant overhead of opening the database connection for each context.
public async Task main()
{
var TaskUsr = GetUserAsync(dev);
var TaskOldCompany = GetOldCompanyAsync(dev);
await Task.WhenAll(TaskUsr, TaskOldCompany);
var usr = TaskUsr.Result;
var oldCompanyName = TaskOldCompany.Result;
.....
use my two variables to insert a new entry into my localdb
}
private async Task<ut_User> GetUserAsync(ut_UserAPNdevices dev)
{
using (var dbSrc = new FSKWebInterfaceEntities())
return dbSrc.ut_User.FirstOrDefault(x => x.UserID == dev.UserID);
}
private async Task<String> GetOldCompanyAsync(ut_UserAPNdevices dev)
{
using (var dbSrc = new FSKWebInterfaceEntities())
return dbSrc.ut_User.FirstOrDefault(x => x.UserID == dev.UserID).Company;
}