将 HttpContext.Current.User 与异步等待一起使用的正确方法

2023-12-25

我正在使用异步操作并像这样使用 HttpContext.Current.User

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

    // …
}

我最近重构了代码,以前我必须在每次调用服务时向用户提供信息。 现在我读了这篇文章https://www.trycatchfail.com/2014/04/25/using-httpcontext-safely-after-async-in-asp-net-mvc-applications/ https://www.trycatchfail.com/2014/04/25/using-httpcontext-safely-after-async-in-asp-net-mvc-applications/我不确定我的代码是否仍然有效。 有没有人有更好的方法来处理这个问题?我不想向用户提供对服务的每个请求。


只要你的web.config设置正确 https://web.archive.org/web/20170324060430/https://blogs.msdn.microsoft.com/webdev/2012/11/19/all-about-httpruntime-targetframework/, async/await完美配合HttpContext.Current。我建议设置httpRuntime targetFramework to 4.5删除所有“怪癖模式”行为。

一旦完成,简单明了async/await会工作得很好。仅当您在另一个线程上工作或者您的await代码不正确。


一、“其他线程”问题;这是您链接到的博客文章中的第二个问题。这样的代码当然无法正常工作:

async Task FakeAsyncMethod()
{
  await Task.Run(() =>
  {
    var user = _userService.Current;
    ...
  });
}

这个问题实际上与异步代码无关;它与从(非请求)线程池线程检索上下文变量有关。如果您尝试同步执行此操作,也会出现完全相同的问题。

核心问题是异步版本正在使用fake异步。这不合适,尤其是在 ASP.NET 上。解决方案是简单地删除假异步代码并使其同步(或真正的异步,如果它实际上有真正的异步工作要做):

void Method()
{
  var user = _userService.Current;
  ...
}

链接博客中推荐的技术(包装HttpContext并将其提供给工作线程)是极其危险的。HttpContext被设计为一次只能从一个线程访问,并且 AFAIK 根本不是线程安全的。因此,在不同的线程之间共享它会带来巨大的伤害。


If the await代码不正确,那么会导致类似的问题。ConfigureAwait(false)是库代码中常用的一种技术,用于通知运行时它不需要返回到特定上下文。考虑这段代码:

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(false)告诉 ASP.NET 当前方法的其余部分不需要上下文,然后它立即访问该上下文。然而,当您开始在接口实现中使用上下文值时,问题就不那么明显了:

async Task MyMethodAsync()
{
  await Task.Delay(1000).ConfigureAwait(false);
  var user = _userService.Current;
}

这段代码同样错误,但没有那么明显错误,因为上下文隐藏在接口后面。

因此,一般准则是:use ConfigureAwait(false) if you know该方法不依赖于其上下文(直接或间接);否则,请勿使用ConfigureAwait。如果在您的设计中可以接受让接口实现在其实现中使用上下文,那么任何调用接口方法的方法都应该not use ConfigureAwait(false):

async Task MyMethodAsync()
{
  await Task.Delay(1000);
  var user = _userService.Current; // works fine
}

只要您遵循该准则,async/await将与完美配合HttpContext.Current.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将 HttpContext.Current.User 与异步等待一起使用的正确方法 的相关文章

随机推荐

  • 如何使用 C# 获取打印作业状态

    我可以打印文档 但不知道如何获取其状态 我查阅了很多资源 MSDN http support microsoft com kb 322091 检查工作状态的链接 https stackoverflow com questions 55637
  • 方法retrieveRequestToken引发“与服务提供商的通信失败:null”

    我正在使用 twitter4j 从我的应用程序发送推文 当我调用方法retrieveRequestToken时 收到错误 与服务提供者的通信失败 null public static void askOAuth Context contex
  • 如何在DotnetNuke 7中临时存储数据?

    我是 DotnetNuke 的新人 请随时向我建议正确的术语 我正在开发 DotnetNuke 7 我使用 C 我有一个包含 30 个字符串字段的表 最多可以有 50 条记录 目前我正在使用数据库管理它 我认为数据不多 我应该将其存储在本地
  • TSQL 选择最大

    Userid FirstName LastName UserUpdate 1 Dan Kramer 1 1 2005 1 Dan Kramer 1 1 2007 1 Dan Kramer 1 1 2009 2 Pamella Slatter
  • 如何使用 Keras 获得可重复的结果?

    我试图使用 Keras 获得可重现的结果 但是每次运行该程序时都会得到不同的结果 我已经设置了 python 哈希种子 Numpy 随机种子 随机种子 TensorFlow 种子和 kernel initializer glorot uni
  • 在Android中将时间戳转换为日期?

    我正在实现一个Android应用程序 我想将时间戳转换为日期 但我无法成功 我尝试过以下事情 请检查一下我是否做错了什么 我正在传递这个值 myTimestamp 1328015914 DateFormat getDateFormat mC
  • 如何在drools中调用Java函数?

    我想从 Utils 类调用 Java 函数 该函数调用 JPA Repository 方法来检索自定义对象 我想从 Drools 决策表中调用这个函数 现在 这个简单的函数给出了空指针异常 我已经为此浪费了几个小时 我在决策表的 导入 部分
  • 如何从服务器获取客户端套接字的确认?

    我有一个向服务器发送消息的客户端套接字 每当服务器收到消息时 我想在客户端得到确认 是否有可能得到这种认可 我使用apache mina开发客户端 提前致谢 TCP中没有消息 只有字节流 有一个内部 ACK 机制可以跟踪有多少流已被正确接收
  • 如何让 PowerShell 等到命令完成后再继续?

    我使用以下行根据其产品 ID 卸载 Office 2007 Start Process C Windows System32 msiexec exe ArgumentList uninstall 90120000 0030 0000 000
  • 使用缓存时的 Rails 字符编码问题

    我正在使用 Rails fragemnet 缓存来缓存一些 html 下面是我的代码
  • Spark 数据集唯一 id 性能 - row_number 与 monotonically_increasing_id

    我想为我的数据集行分配一个唯一的 ID 我知道有两种实现选项 第一个选项 import org apache spark sql expressions Window ds withColumn id row number over Win
  • Cassandra轻量级事务的一致性级别

    我读到了 Cassandra 2 的轻量级事务 这样写的一致性级别是always在法定人数 这是否意味着即使我有一个包含 100 个节点的多数据中心设置 也会涉及整个集群的仲裁 所有数据中心的行副本的大多数 这会不会很慢并且不会影响可用性吗
  • C++11 是否允许非匿名联合包含静态数据成员?

    在 C 11 中 我声明以下联合 union U4 char c int i static int si 当我使用 std c 11 pedantic errors 使用 g 4 7 0 编译此代码时 出现以下错误 经过少量编辑 错误 本地
  • 从 React Native 中的模态窗口打开模态窗口

    我正在尝试打开一个Modal from a TouchHighlight位于另一个模态中 基本上应该发生的是 TouchHighlight在父主干中Modal应该再开一个中学Modal在它之上 而不关闭主Modal 但我收到以下错误 War
  • ASP.NET MVC4 异步控制器 - 为什么使用?

    我试图理解为什么以及何时应该使用async控制器动作 最终 当我使用await其中 它将等待操作完成才能返回视图 例如 public async Task
  • 我们可以从子元素样式中设置父元素样式吗?

    div div div div 我可以从子样式中设置主样式吗 级联样式表只能向下 级联 因此它们根本不是为了执行此操作而设计的 即使在极少数情况下也是如此very如果他们这样做的话就很方便了 您需要 JavaScript 内联样式或不同的布
  • 在Python中交换字符串大小写[重复]

    这个问题在这里已经有答案了 我是Python新手 因此问题是 我正在尝试解决一个简单的问题 其中程序接受一个简单的字符串并交换所有大小写 因此如果我们输入 SimPLE 我们应该得到 sIMple 这是我的代码 def main oldSt
  • grunt-init 模板条件复制文件

    我刚刚开始使用 grunt init 我一切正常 我想知道是否有一种方法可以根据提示 基于先前提示的答案 进行条件复制根文件 您可以使用rename json文件通过docs http gruntjs com project scaffol
  • Google Play 商店:我的应用程序页面不显示排行榜和成就图标/徽章

    本周我在谷歌游戏商店推出了一个应用程序 该应用程序使用 Google Play 游戏排行榜和成就 API Play 商店应用程序中的应用程序页面是否应该像使用这些 API 的其他应用程序中那样显示这些图标 徽章 我需要在任何地方启用它吗 这
  • 将 HttpContext.Current.User 与异步等待一起使用的正确方法

    我正在使用异步操作并像这样使用 HttpContext Current User public class UserService IUserService public ILocPrincipal Current get return H