12

I have a method that uses a repository (userRepo):

    public override Task<IdentityResult> CreateLocalUserAsync(IUser user, string password, CancellationToken cancellationToken)
    {
        var task = new Task<IdentityResult>(() => {

            TUserEntity newUser = new TUserEntity
            {
                Id = user.Id,
                UserName = user.UserName,
                Password = password
            };

            userRepo.Save(newUser).Flush();

            return new IdentityResult(true);
        }, cancellationToken);

        task.Start();

        return task;
    }

The userRepoobject has a dependency that uses HttpContext.Current. Both of these are resolved using ninject InRequestScope.

The above method is called inside the default AccountController in Mvc 5:

var result = await IdentityManager.Users.CreateLocalUserAsync(user, model.Password);

I have tried adding this setting to web.config:

<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />

Also, I am definitely using .NET 4.5. This is also in my web.config:

<httpRuntime targetFramework="4.5" />

It is not possible to get the information from the HttpContext before I start the task because a dependency of the userRepo in the task is using the information and both objects are resolved using Ninject.

How can I ensure that HttpContext.Current will not be null?

3
  • “How can I ensure that HttpContext.Current will not be null?” Don't use Tasks or async-await at all. It doesn't improve anything in this case. Commented Oct 1, 2013 at 9:00
  • @svick well, await is http-context aware, at least; the problem here is that Task.Start isn't. Commented Oct 1, 2013 at 9:19
  • Link: stackoverflow.com/questions/18383923/… Commented Sep 27, 2016 at 14:33

1 Answer 1

17

The "task friendly sync context" here applies to the continuation from the await: whatever you do with result, it will have the http-context. It does not, however, relate to task.Start. That relates to the TaskScheduler, not the sync-context.

Basically, by performing this on a worker, you are (in the process, as a consequence) divorcing that worker from the http-context. You must either:

  • get the information you need from the http-context and pass that into the worker, or
  • don't use a worker

Personally, I doubt you're gaining much by pushing this onto a worker. If you really want to go async, the ideal would be for your repo to internally support *Async methods. That requires more than using threads: it usually means architectural changes, for example, using async SQL methods. Something written from the ground up to use async and sync-context-aware continuations (aka await) would automatically preserve things like the http-context.

The important difference here is that an async/await implementation is linear but not continuous, i.e.

 <===(work)==>
                    <===(callback; more work)===>
                                                     <===(another callback)===>

where-as your existing code potentially performs things in parallel, i.e.

<==========(original work)=================>
         <===========(task on worker thread)=============>

The fact that the async/await approach is basically linear makes it far more suitable for access to things like http-context, since it knows that (done right) there will only be one thread at a time accessing it - even if it isn't the same thread end-to-end.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.