Let's say that I have a class with members which require asynchronous actions to initialize (such as file i/o or web requests). I only need to initialize once, and I don't want to reinitialize.
Are Tasks and Async-Await a good fit to accomplish this?
Here's an example of what I'm currently doing:
private Task _initializeTask;
public Task InitializeAsync()
{
return _initializeTask ?? (_initializeTask = Task.Run(
async () =>
{
// Do an action requiring await here
await _storageField.LoadAsync();
}));
}
Does this do what I think it does? Are there better ways to do it?
Is it thread safe? Not a requirement but should be considered.
Edits:
What I think it does? I believe that if _initializeTask hasn't been assigned then it will be assigned a new task that will kick off and then await the async lambda contained within. Any subsequent calls to the method will await the already running (or completed) task that was assigned to _initializedTask.
When do I want it to construct? Typically I'd use this sort of method on a service that I resolve with an IoC container. Multiple dependent classes can be constructed with a reference to the class. Then, before use, each of them awaits InitializeAsync(). If theres multiple dependent classes then I don't want to double up on initializing it.
Factory Method? There usually won't be multiple instances constructed that need to be initialized, so Factory method doesn't seem like a good solution. I've used something like a "static CreateAsync()" method for things like folder wrapper classes, but that didn't let me inject initialized folders into constructors. Async Factory methods don't gain anything when they can't be used with IoC constructor injection.
Your code will work but it is not thread safe, _initializeTask can be changed after checking it for null and before initializing it. This will result in two initializations. I would consider using AsyncLazy<T>, which is inherits from Lazy<T> which is thread safe.
Then assuming LoadAsync returns Task rather than Task<T>, your code becomes (untested):
private AsyncLazy<object> initializeTask = new AsyncLazy<object>(async () =>
{
// Do an action requiring await here
await _storageField.LoadAsync();
return null;
});
public Task InitializeAsync()
{
return _initializeTask.Value;
}
You can also define a non-generic version of `AsyncLazy, so you don't have to return a value from the initialization routine.
public class AsyncLazy : Lazy<Task>
{
public AsyncLazy(Func<Task> taskFactory) :
base(() => Task.Run(taskFactory)) { }
}
Then you can initialize it using an initialization method, however that method is required to be static by the compiler:
private AsyncLazy _initializeTask = new AsyncLazy(LoadStorageAsync);
private static async Task LoadStorageAsync()
{
// Do an action requiring await here
await _storageField.LoadAsync();
}
public Task InitializeAsync()
{
return _initializeTask.Value;
}
Run the asynchronous task from a regular initialization function. In the regular function, check if your app already has a loaded data set that matches your expectations. If the data is not present THEN call the async function.
...
If (BooleanFunctionToDetermineIfDataIsNotPresent){FunctionToLoadFreshData}
...
Private Async Void FunctionToLoadFreshData{...}
The function to load the data must not return a value lest it become a task itself.
If you work in a WebHost (ASP.NETCore app) or generic Host environment you can use simply way to do that with nuget HostInitActions
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IService, MyService>();
services.AddAsyncServiceInitialization()
.AddInitAction<IService>(async (service) =>
{
await service.InitAsync();
});
}
This nuget ensures that your initialization action will be performed asynchronously before the application starts.
Another advantage of this approach is that this initialization action can be defined from any place where services are installed into the IServiceCollection (For example, in an extension method in another project that installs internal implementations of public interfaces). This means that the ASP.NET Core project does not need to know what service and how it should be initialized, and it will still be done.
Related
Is it ok to call activity functions from private methods in a Durable Function orchestrator, or should that be avoided? Here's an example:
[FunctionName(nameof(OrchFunc))]
public async Task OrchFunc(
[OrchestrationTrigger] DurableOrchestrationContext context,
ILogger logger) {
var myParameter = context.GetInput<string>();
// Any issue with doing this with the way checkpoints work?
var result = await MyPrivateFunc(context, myProperty);
}
private async Task<bool> MyPrivateFunc(
DurableOrchestrationContext context,
string myParameter) {
return result = await context.CallActivityAsync<bool>(nameof(MyActivityFunc), myParameter);
}
Keep in mind this is a simple example to clarify the question. I am already aware that it could be called directly from the orchestration function and thereby skip the private function. I'm not looking to see if it makes sense here, but rather just seeking to understand if there would be unintended side effects.
I imagine you've probably moved on from this issue, but for anyone else seeking this out, yes this should work fine. The context will be passed by reference so it will still be the one calling the activity function. Note, however, that the restrictions on orchestrations will still apply to the private method, so no awaiting anything called by something other than the context.
I am working with async actions and use the HttpContext.Current.User like this
public class UserService : IUserService
{
public ILocPrincipal Current
{
get { return HttpContext.Current.User as ILocPrincipal; }
}
}
public class ChannelService : IDisposable
{
// In the service layer
public ChannelService()
: this(new Entities.LocDbContext(), new UserService())
{
}
public ChannelService(Entities.LocDbContext locDbContext, IUserService userService)
{
this.LocDbContext = locDbContext;
this.UserService = userService;
}
public async Task<ViewModels.DisplayChannel> FindOrDefaultAsync(long id)
{
var currentMemberId = this.UserService.Current.Id;
// do some async EF request …
}
}
// In the controller
[Authorize]
[RoutePrefix("channel")]
public class ChannelController : BaseController
{
public ChannelController()
: this(new ChannelService()
{
}
public ChannelController(ChannelService channelService)
{
this.ChannelService = channelService;
}
// …
[HttpGet, Route("~/api/channels/{id}/messages")]
public async Task<ActionResult> GetMessages(long id)
{
var channel = await this.ChannelService
.FindOrDefaultAsync(id);
return PartialView("_Messages", channel);
}
// …
}
I have the code recently refactored, previously I had to give the user on each call to the service.
Now I read this article https://www.trycatchfail.com/2014/04/25/using-httpcontext-safely-after-async-in-asp-net-mvc-applications/ and I’m not sure if my code still works.
Has anyone a better approach to handle this? I don’t want to give the user on every request to the service.
As long as your web.config settings are correct, async/await works perfectly well with HttpContext.Current. I recommend setting httpRuntime targetFramework to 4.5 to remove all "quirks mode" behavior.
Once that is done, plain async/await will work perfectly well. You'll only run into problems if you're doing work on another thread or if your await code is incorrect.
First, the "other thread" problem; this is the second problem in the blog post you linked to. Code like this will of course not work correctly:
async Task FakeAsyncMethod()
{
await Task.Run(() =>
{
var user = _userService.Current;
...
});
}
This problem actually has nothing to do with asynchronous code; it has to do with retrieving a context variable from a (non-request) thread pool thread. The exact same problem would occur if you try to do it synchronously.
The core problem is that the asynchronous version is using fake asynchrony. This inappropriate, especially on ASP.NET. The solution is to simply remove the fake-asynchronous code and make it synchronous (or truly asynchronous, if it actually has real asynchronous work to do):
void Method()
{
var user = _userService.Current;
...
}
The technique recommended in the linked blog (wrapping the HttpContext and providing it to the worker thread) is extremely dangerous. HttpContext is designed to be accessed only from one thread at a time and AFAIK is not threadsafe at all. So sharing it among different threads is asking for a world of hurt.
If the await code is incorrect, then it causes a similar problem. ConfigureAwait(false) is a technique commonly used in library code to notify the runtime that it doesn't need to return to a specific context. Consider this code:
async Task MyMethodAsync()
{
await Task.Delay(1000).ConfigureAwait(false);
var context = HttpContext.Current;
// Note: "context" is not correct here.
// It could be null; it could be the correct context;
// it could be a context for a different request.
}
In this case, the problem is obvious. ConfigureAwait(false) is telling ASP.NET that the rest of the current method does not need the context, and then it immediately accesses that context. When you start using context values in your interface implementations, though, the problem is not as obvious:
async Task MyMethodAsync()
{
await Task.Delay(1000).ConfigureAwait(false);
var user = _userService.Current;
}
This code is just as wrong but not as obviously wrong, since the context is hidden behind an interface.
So, the general guideline is: use ConfigureAwait(false) if you know that the method does not depend on its context (directly or indirectly); otherwise, do not use ConfigureAwait. If it's acceptable in your design to have interface implementations use the context in their implementation, then any method that calls an interface method should not use ConfigureAwait(false):
async Task MyMethodAsync()
{
await Task.Delay(1000);
var user = _userService.Current; // works fine
}
As long as you follow that guideline, async/await will work perfectly with HttpContext.Current.
Async is fine. The problem is when you post the work to a different thread. If your application is setup as 4.5+, the asynchronous callback will be posted in the original context, so you'll also have the proper HttpContext etc.
You don't want to access shared state in a different thread anyway, and with Tasks, you rarely need to handle that explicitly - just make sure you put all your inputs as arguments, and only return a response, rather than reading or writing to a shared state (e.g. HttpContext, static fields etc.)
There is no problem, if your ViewModels.DisplayChannel is a simple object without additional logic.
A problem may occur, if the result of your Task references to "some context objects", f.e. to HttpContext.Current. Such objects are often attached to the thread, but entire code after await may be executed in another thread.
Keep in mind, that UseTaskFriendlySynchronizationContext doesn't solve all your problems. If we are talking about ASP.NET MVC, this setting ensures that Controller.HttpContext contains correct value as before await as after. But it doesn't ensure that HttpContext.Current contains correct value, and after await it still can be null.
I'm using autofac in an owin-driven web api project. I've come to a place where I need to "Fire and Forget" some processing of data.
This normally isn't an issue. But since the dependencies are controlled by the per-request lifetime scope managed by the autofac middleware. I cannot use un-managed resources (which is what i need to do) in my non-awaited async method.
//for example...
public async Task<IEnumerable<MyThings>> GetThings(){
var things = await _thingRepo.GetInterestingThingsAsync();
//fire and forget. -- not awaiting
InjectedObject.DoThingsAsync(things);
return things;
}
The problem here is that I need to use other injected resources (un-managed resources) inside DoThingsAsync. Currently this breaks because they're disposed of when the Owin Request ends.
I could create a child lifetime scope for each invocation but I'm hoping their might be a cleaner way to do such things..
Update:
With the dawn of .Net Framework 4.5.2 I can now use
HostingEnvironment.QueueBackgroundWorkItem Which is preferred Because it will keep IIS from recycling before the work item completes.
I think I found a solution for my use case..
I just Inject this class where I need it:
public class AsyncTask : IAsyncTask
{
private ILifetimeScope _lifetimeScope;
public AsyncTask(ILifetimeScope lifeTimeScope)
{
//disposed of by owning scope...
_lifetimeScope = lifeTimeScope;
}
public async Task Fire<T>(Func<T,Task> asyncAction)
{
using (var scope = _lifetimeScope.BeginLifetimeScope())
{
await asyncAction(scope.Resolve<T>());
}
}
}
public interface IAsyncTask
{
Task Fire<T>(Func<T, Task> action);
}
Then..
_asyncTask.Fire<IEmailService>(svc => svc.SendMillionsOfEmailsAsync(content));
I have the following mvc action.
public async Task<JsonResult> DoSomeLongRunningOperation()
{
return await Task.Run(() =>
{
//Do a lot of long running stuff
//The underlying framework uses the HttpContext.Current.User.Identity.Name so the user is passed on the messagebus.
}
}
In the task the HttpContext gets null. We did a lot of tricking, but nothing assures us of the HttpContext being available always in our new thread.
Is there a solution to use HttpContext within out async tasks?
In our IocContainer we have registered the following object which passes the username to the framework.
public class HttpContextUserIdentityName : ICredentials
{
public string Name
{
get { return HttpContext.Current.User.Identity.Name; }
}
}
This code is called in a lot of places before persisting to the database.
We need either another way of getting the username of the user initiated the webrequest or fix the issue with the HttpContext being null.
Because the persisting to the database happens in the Task I can't access the HttpContext before entering the task.
I also can't think of a safe way to temporary persist the username so I can implement another ICredentials service object.
You almost never want to use Task.Run in an ASP.NET method.
I think the cleanest solution (but the most work) is to implement async-compatible interfaces at your other layers:
public async Task<JsonResult> DoSomeLongRunningOperation()
{
//Do a lot of long running stuff
var intermediateResult = await DoLongRunningStuff();
return await DetermineFinalResult(intermediateResult);
}
You should get whatever information you need from the current context before you start the new thread. In this case, add something like:
string username = HttpContext.Current.User.Username;
before Task.Run and then use that inside of the other thread.
On a side note, as it stands, there's no reason to await the task. You can just return the task directly and not mark the method as Async.
If you need to access the Response object, which will presumably to utilize the results of the long running operation and thus can't be before Task.Run you should do so after the Task.Run (but ensure that the task is awaited). If you end up doing this then you can't do what I suggested in my previous paragraph.
I would try passing in the reference to the HttpContext as the state object, because that should create a new instance of that object on the stack for the thread that executes the work. Instead of using Task.Run, use
return await Task.Factory.StartNew((ctx) =>
{
var context = (HttpContext)ctx;
//Do stuff
}, httpContextObject);
Task.Run and Task.Factory.StartNew return immediately, so asp.net continues on in the event lifecycle in the worker thread that is handling the request while your thread is operating on the object that has already been disposed.
My project is structured by services and repositories (all repositories share the db context). In one of my service layers, I have an asynchronous method that writes to the database using a repository. The web request will finish and dispose of the context before this method can get to use it. I tried to understand NamedScopes as stated in this answer. I still can't seem to understand how to implement it. I'll show how my project is structured and hope someone can help me at the code level.
Bindings
private static void RegisterServices(IKernel kernel)
{
//dbcontext
kernel.Bind<EntityDatabaseContext>().ToMethod(context => new EntityDatabaseContext()).InRequestScope();
//unit of work
kernel.Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope();
//repositories
kernel.Bind<IRepository<Account>>().To<Repository<Account>>().InRequestScope();
//services
kernel.Bind<IAuthenticationService>().To<AuthenticationService>().InRequestScope();
}
AuthenticationService uses constructor injection
public AuthenticationService(UnitOfWork unitOfWork, IRepository<Account> accountRepository){}
A method inside my AuthenticationService
//this is a background process
public Task SomeMethodAsync(string text)
{
//spin it off into a new task
return Task.Factory.StartNew(() => SomeMethod(text));
}
SomeMethod makes use of accountRepository. Please tell me if anymore information is needed. Please help me with the threading issue, if NamedScopes is the solution, how do I implement it in my case?
Basically, a background process is being executed and it is using a context that is being disposed of by ninject due to the request scope.
You should be aware that running background threads can cause you many problems. IIS can decide to recycle the app pool at any time which will terminate your thread immediately (or it doesn't execute in some cases at all) leaving your application in an inconsistent state.
http://haacked.com/archive/2011/10/16/the-dangers-of-implementing-recurring-background-tasks-in-asp-net.aspx
The easiest and least error prone wayto run asyncronous operations is to implement a windows service and delegate those async operations to the windows service e.g. using MSMQ.
If you still want to go the hard way then read about HostingEnvironment.RegisterObject and IRegisteredObject to prevent these inconsistent situations.
The Ninject part is quite easy. Just create some job processor class e.g. MyJobProcessor taking all required dependencies to execute the task. It should implement INotifyWhenDisposed. The easiest way to do so is to derive from DisposeNotifyingObject.
public class MyJobProcessor : DisposeNotifyingObject, IRegisteredObject
{
public void Execute() { ... }
public void Stop(bool immediate) { ... }
}
Inject this processor to the controller and let the Task start it and dispose it when it has finished its work.
Task.Factory.StartNew(() =>
{
try
{
processor.Execute();
}
finally
{
processor.Dispose);
}
});
Specify that it is the scope for its dependencies.
Bind<MyJobProcessor>().ToSelf().Named("MyJobProcessor").DefinesNamedScope("MyJobProcessorScope");
Bind<IUnitOfWork>().To<UnitOfWork>().WhenAnyAnchestorNamed("MyJobProcessor").InNamedScope("MyJobProcessorScope");