Web API服务-如何使用"HttpContext.Current"内部异步任务 [英] Web API Service - How to use "HttpContext.Current" inside async task

查看:162
本文介绍了Web API服务-如何使用"HttpContext.Current"内部异步任务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用webApi rest服务的发布"异步方法:

I'm using a "Post" async method of webApi rest service:

public async Task<object> Post([FromBody]string data)
{
      object response = ExecuteServerLogics(data);

      return response;
}

上面的代码效果很好,但是在一些客户的电话中,我们遇到了性能问题.

This above code worked good but in some of the client's calls, we experienced performance issues.

在这里阅读了一些文章之后,我注意到我们的webApi rest服务, 与其传入的Web请求并不是真正地异步工作, 因为我们忘记使用异步/等待模式:

After reading some articles here, i've noticed that our webApi rest service, is not really working asynchronously with its incoming web requests, because we forgot to use async/await pattern :

public async Task<object> Post([FromBody]string data)
{
      object response = await Task<object>.Run( () =>
      {
           return ExecuteServerLogics(data);
      });

      return response;
}

此修复程序之后,我们注意到性能有所提高, 但我们发现了另一个批评者问题: 访问 HttpContext.Current 时-返回Null引用:

After this fix we noticed the performance got better, but we found another critic problem: when accessing HttpContext.Current - it returns Null reference:

public async Task<object> Post([FromBody]string data)
{
      object response = await Task<object>.Run( () =>
      {
           var currentContext = HttpContext.Current; // Returns Null!
           return ExecuteServerLogics(data);
      });

      return response;
}

我们试图找到一种解决方案,在大多数帖子中,我们发现我们应该通过 辅助线程对执行服务器逻辑的内部Task的 HttpContext 引用. 此解决方案的问题在于服务器的逻辑方法使用许多静态类,这些类使用 "HttpContext.Current" ,例如-

We tried to found a solution for it, and in most posts we found that we should pass the worker thread's HttpContext reference into the inner Task that executes the server logics. The problem with this solution is that the server's logics methods, use many static classes that use "HttpContext.Current" such as -

  1. 记录器调用.
  2. 检索用户身份的静态安全类
  3. 静态安全类,用于检索传入请求的会话数据等.

因此,传递工作线程的"HttpContext.Current" 引用不会解决该问题.

Therefore, passing the "HttpContext.Current" reference of the worker thread won't solve it.

当我们尝试下一个解决方案时:

When we tried the next solution:

public async Task<object> Post([FromBody]string data)
    {
          // Save worker context:
          var currentContext = HttpContext.Current; 

          object response = await Task<object>.Run( () =>
          {
               // Set the context of the current task :
               HttpContext.Current = currentContext ; // Causes the calls not to work asynchronously for some reason!

               // Executes logics for current request:
               return ExecuteServerLogics(data);
          });

          return response;
    }

由于某种原因,我们注意到性能再次变差,就像它又恢复了同步工作一样.

for some reason, we noticed the performance got worse again, like it had returned working synchronously again.

我们的问题是:

Our problems are:

1..为什么在上一个示例中,在await任务中设置"HttpContext.Current" , 导致请求返回与同步结果相似的同样糟糕的性能结果?

1. Why in the last example, setting the "HttpContext.Current" inside the await task, causes the requests to return the same bad performance results which similar to the synchronous results?

2..还有另一种方法可以在调用内部任务的内部使用"HttpContext.Current" -"ExecuteServerLogics", 在所有也称为"HttpContext.Current" 的静态类中? 我在某种程度上做错了整个设计吗?

2. Is there another way we can use "HttpContext.Current" inside the inner task that call - "ExecuteServerLogics", and in all the static classes which also call "HttpContext.Current"? am I doing the entire design wrong somehow?

谢谢!

推荐答案

从一开始:

public async Task<object> Post([FromBody]string data)
{
  object response = ExecuteServerLogics(data);
  return response;
}

不要忽略编译器警告;编译器将为此方法生成一条警告,明确指出它将同步运行.

Don't ignore compiler warnings; the compiler will generate a warning for this method that specifically states it will run synchronously.

继续前进:

在一些客户的电话中,我们遇到了性能问题.

in some of the client's calls, we experienced performance issues.

对于单独的单个调用,

服务器上的异步代码不会更快.它只会帮助您扩展服务器.

Asynchronous code on the server will not be faster for a single call in isolation. It only helps you scale your server.

尤其是,Task.Run将抵消async的所有性能优势,然后使性能进一步下降.我相信您测得的性能改善是偶然的.

In particular, Task.Run will negate all the performance benefits of async and then degrade performance a bit beyond that. I believe the improvement in performance that you measured was coincidental.

在大多数帖子中,我们发现我们应该将辅助线程的HttpContext引用传递给执行服务器逻辑的内部Task.

in most posts we found that we should pass the worker thread's HttpContext reference into the inner Task that executes the server logics.

这些帖子有误.恕我直言.当该对象专门设计为只能从请求线程进行访问时,最终只能从后台线程使用HttpContext对象.

Those posts are wrong. IMHO. You end up using the HttpContext object from a background thread, when that object is specifically designed to be only accessed from a request thread.

我整个设计是否以某种方式做错了?

am I doing the entire design wrong somehow?

我确实建议您退后一步,考虑一下大局.收到请求时,它需要做一些工作.该工作是同步完成还是异步完成对客户而言并不重要.两种方法都将花费相同的时间.

I do recommend you take a step back and think about the big picture. When a request comes in, it has a certain amount of work to do. Whether that work is done synchronously or asynchronously is immaterial to the client; both approaches will take about the same amount of time.

如果您需要将早期返回给客户端,那么您将需要一个完全不同的体系结构.通常的方法是将工作排队到可靠的队列(例如Azure队列),具有单独的后端(例如Azure WebRole),并在工作完成时主动通知客户端(例如SignalR).

If you need to return early to the client, then you'll need a completely different architecture. The usual approach is to queue the work to a reliable queue (e.g., Azure queue), have a separate backend (e.g., Azure WebRole), and proactively notify the client when the work is completed (e.g., SignalR).

但这并不是说async是没有用的.如果ExecuteServerLogics是受I/O约束的方法,则应使其成为异步方法而不是阻塞方法,然后可以这样使用异步方法:

That's not to say that async is useless, though. If ExecuteServerLogics is an I/O bound method, then it should be made asynchronous rather than blocking, and then you can use asynchronous methods as such:

public async Task<object> Post([FromBody]string data)
{
  object response = await ExecuteServerLogicsAsync(data);
  return response;
}

这将使您的服务器整体上具有更高的响应能力和可扩展性(即,不会被很多请求淹没).

This will enable your server to be more responsive and scalable overall (i.e., not get overwhelmed by many requests).

这篇关于Web API服务-如何使用"HttpContext.Current"内部异步任务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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