preserve HttpContext的异步用的WebAPI外出时(中等信任)preserve、HttpContext、WebAPI

2023-09-02 01:59:30 作者:情不知所起一往而深

我建立了一套ASP.Net托管必须使用旧库,它在很大程度上取决于HttpContext.Current的WebAPI服务。我无法确保这方面是pserved在所有参与的异步调用的方法$ P $。我曾尝试在以下code几个变化与计谋/ Task.Wait和TaskScheduler.FromCurrentSynchronizationContext()。

I am building a set of ASP.Net hosted WebAPI services that must use an old library which depends heavily on HttpContext.Current. I am having trouble ensuring that context is preserved in all the methods that participate in an async call. I have tried several variations with await/Task.Wait and TaskScheduler.FromCurrentSynchronizationContext() on the below code.

    [HttpGet]
    public Task<IEnumerable<string>> ContinueWith()
    {
        Thread.CurrentThread.CurrentCulture = new CultureInfo("fr-FR");  //or another culture that is not the default on your machine
        Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;

        var output = new List<string> { TestOutput("Action start") };

        var task = Task.Factory.StartNew(() =>
            {
                Thread.Sleep(1000);
                return TestOutput("In Task");
            }).ContinueWith(slowString =>
            {
                output.Add(slowString.Result);

                output.Add(TestOutput("Action end"));
                return output as IEnumerable<string>;
            });

        output.Add(TestOutput("Action Mid"));

        return task;
    }

    private string TestOutput(string label)
    {
        var s = label + " ThreadID: " + Thread.CurrentThread.ManagedThreadId.ToString(CultureInfo.InvariantCulture);
        s += " " + Thread.CurrentThread.CurrentCulture.EnglishName;
        s += HttpContext.Current == null ? " No Context" : " Has Context";
        Debug.WriteLine(s);
        return s;
    }

我想能够确保的CurrentCulture是FR-FR,并且HttpContext.Current不是null在每个点处TestOutput被调用。我还没有成功地做到了,对于任何事情我都试过了在任务的号召。此外,在一些我的测试线程ID的亘古未变暗示我已经有效地清除了该方法的不同步。我怎样才能确保文化和HttpContext.Current是preserved在每次调用TestOutput,而code是自由地在不同的线程上运行?

I would like to be able to ensure that the CurrentCulture is fr-FR, and that HttpContext.Current is not null at each point where TestOutput is called. I have not succeeded in doing that for the "In Task" call with anything I have tried. Also in some of my test thread id never varies suggesting that I have effectively removed the asynchronicity of the method. How can I ensure that the culture and HttpContext.Current are preserved at each call to TestOutput, and that the code is free to run on different threads?

捕获HttpContext.Current在一个封闭,然后简单地重新设置它不会为我工作,我需要支持中等信任它调用的时候会抛出一个安全异常的HttpContext.Current的制定者。

Capturing HttpContext.Current in a closure and then simply setting it again will not work for me as I need to support Medium Trust which will throw a security exception when calling the HttpContext.Current setter.

推荐答案

上下文是preserved只要你计谋任务。

Context is preserved whenever you await tasks.

你看到的是,有没有上下文的线程池的任务( Task.Run TaskFactory.StartNew ,或者在这方面的BackgroundWorker Delegate.BeginInvoke )。这是正常的和预期的。

What you're seeing is that there's no context for thread pool tasks (Task.Run, TaskFactory.StartNew, or for that matter BackgroundWorker or Thread or Delegate.BeginInvoke). This is normal and expected.

所以,不使用线程池的任务。你比如code,似乎想要做并行处理,具有多线程的的HttpContext ,这根本是不可能的。

So, don't use a thread pool task. Your example code seems to want to do parallel processing with multiple threads having the HttpContext, which simply isn't possible.

您可以执行并行异步方法,如果你想要的,但是这需要你的 Thread.sleep代码其实是可以一个异步方法,而不是基于CPU的方法:

You can do concurrent async methods if you want, but this requires that your Thread.Sleep can actually be an async method instead of a CPU-based method:

[HttpGet]
public async Task<IEnumerable<string>> Test()
{
  Thread.CurrentThread.CurrentCulture = new CultureInfo("fr-FR");
  Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;

  var output = new List<string> { TestOutput("Action start") };

  var task = SlowStringAsync();
  output.Add(TestOutput("Action Mid"));
  output.Add(await task);
  output.Add(TestOutput("Action end"));
  return output;
}

public async Task<string> SlowStringAsync()
{
  await Task.Delay(1000);
  return TestOutput("In Task");
}

如果你的老图书馆是在你的控制,你不能让它异步,那么你就必须同步调用它。这是可以接受调用从异步方法的同步方法在这样的情况:

If your old library is out of your control and you can't make it async, then you'll have to call it synchronously. It's acceptable to call a synchronous method from an async method in situations like this:

[HttpGet]
public async Task<IEnumerable<string>> Test()
{
  Thread.CurrentThread.CurrentCulture = new CultureInfo("fr-FR");
  Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;

  var output = new List<string> { TestOutput("Action start") };

  output.Add(TestOutput("Action Mid"));
  Thread.Sleep(1000);
  output.Add(TestOutput("Not Really In Task"));
  output.Add(TestOutput("Action end"));
  return output;
}