等待使用HttpContext.Current.User与异步的正确方法 [英] Correct way to use HttpContext.Current.User with async await

查看:205
本文介绍了等待使用HttpContext.Current.User与异步的正确方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我与异步操作工作,这样使用HttpContext.Current.User

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);
    }

    // …
}

我有code最近重构,previously我不得不放弃在每次调用该服务的用户。
现在我读这篇文章<一个href=\"http://trycatchfail.com/blog/post/Using-HttpContext-Safely-After-Async-in-ASPNET-MVC-Applications.aspx\">http://trycatchfail.com/blog/post/Using-HttpContext-Safely-After-Async-in-ASPNET-MVC-Applications.aspx而我不知道如果我的code仍然有效。
有没有人更好的方法来处理呢?我不希望给每一个请求服务的用户。

I have the code recently refactored, previously I had to give the user on each call to the service. Now I read this article http://trycatchfail.com/blog/post/Using-HttpContext-Safely-After-Async-in-ASPNET-MVC-Applications.aspx 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.

推荐答案

只要你的<一个href=\"http://blogs.msdn.com/b/webdev/archive/2012/11/19/all-about-httpruntime-targetframework.aspx\"><$c$c>web.config设置是否正确,异步 / 等待工作非常顺利地使用 HttpContext.Current 。我建议设置的httpRuntime targetFramework 4.5 删除所有怪癖模式的行为。

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.

一旦做到这一点,普通的异步 / 伺机将完美的工作。你只会碰到的问题,如果你在另一个线程,或者做的工作你的等待 code是不正确。

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.

首先,其他线程的问题;这是您链接到博客文章的第二个问题。 code这样当然会无法正常工作:

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;
    ...
  });
}

这问题其实无关异步code;它具有与检索从一个(非请求)线程池线程上下文变量的事。如果您尝试同步做会出现相同问题。

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.

的核心问题是,异步版本使用的的异步。这种不恰当的,尤其是在ASP.NET。解决的办法是简单地删除假异步code,并使其同步(或真正的异步,如果它实际上有真正的异步工作要做):

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;
  ...
}

在链接的博客推荐技术(包裹的HttpContext 键,将其提供给工作线程)是极其危险的。 的HttpContext 被设计为只能从一个线程访问的时间和AFAIK不是线程安全的。所以共享它不同的线程之间是要求受伤的世界。

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.

如果在等待 code不正确,那么它会导致类似的问题。 ConfigureAwait(假)是在图书馆code常用来通知它不需要返回到特定的上下文中运行的技术。考虑这个code:

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.
}

在这种情况下,该问题是明显的。 ConfigureAwait(假)告诉ASP.NET当前方法的其余部分并不需要的范围内,然后将其立即访问该上下文。当你开始在你的接口实现使用上下文值,不过,问题是没有那么明显了:

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;
}

这code是同样错误的,但不是明显的错误,因为上下文是隐藏在接口之后。

This code is just as wrong but not as obviously wrong, since the context is hidden behind an interface.

所以,一般的原则是:使用 ConfigureAwait(假)如果您了解,该方法不依赖于它的上下文(直接或间接);否则,不要使用 ConfigureAwait 的。如果它在你的设计可以接受的接口实现使用在其实施的背景下,然后调用接口方法的任何方法应该的的使用 ConfigureAwait(假)

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
}

只要你遵循的准则,异步 / 等待完美运行HttpContext.Current

这篇关于等待使用HttpContext.Current.User与异步的正确方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆