0

我有一个通过 Nancy Module Get 方法调用的长时间运行的进程。我希望这个调用是异步的,而不是让浏览器在进程运行时挂起,换句话说,我希望 Get 方法立即返回并让长时间运行的进程去做它的事情。然后,我可以定期检查流程的状态并采取相应措施。

我是 C#5 的 async / await 特性的新手,但我确信这些特性仅用于此类任务。下面的代码显示了我的尝试。我已经添加了一些日志记录,证明它没有按预期异步运行。相反,长时间运行的进程会阻止 Get 方法,因此浏览器会挂起。

模块

public class TestModule : NancyModule
{            
    public TestModule(ITestService testService)
    {
        Get["/longprocess"] = _ =>
            {
                Log.Write("Module : Start");
                testService.LongProcess();
                Log.Write("Module : Finish");
                return HttpStatusCode.OK;
            };
    }
}

服务

public interface ITestService
{
    Task<bool> LongProcess();
}

public class TestService : ITestService
{
    public async Task<bool> LongProcess()
    {
        await LongProcessAsynch();
        return true;
    }

    private Task<bool> LongProcessAsynch()
    {
        Log.Write("LongProcess : Start");
        Thread.Sleep(5000);
        //Task.Delay(5000); <- Has same effect
        Log.Write("LongProcess : Finish");
        return true.AsTask();
    }
}

扩展方法

public static Task<T> AsTask<T>(this T candidate)
{
    var source = new TaskCompletionSource<T>();
    source.SetResult(candidate);
    return source.Task;
}

日志输出

14/06/2012 19:22:29 : Module : Start
14/06/2012 19:22:29 : LongProcess : Start
14/06/2012 19:22:34 : LongProcess : Finish
14/06/2012 19:22:34 : Module : Finish

您可以从上面的日志输出中看到LongProcess()阻塞了 Get 模块的返回。如果任务异步运行,我希望日志看起来像这样:

预期日志

Module : Start
LongProcess : Start
Module : Finish
LongProcess : Finish

我认为实际需要的是把awaitNancyModule Get 方法。可能类似于下面的代码,但我不能这样做,因为我不能将模块构造函数标记为asnyc,所以我不能await在 Get 方法中使用(或者我目前相信)

Get["/longprocess"] = _ =>
    {
        Log.Write("Module : Start");
        await testService.LongProcess();
        Log.Write("Module : Finish");
        return HttpStatusCode.OK;
    }; 

感谢您提供任何帮助、示例或资源指针。

编辑 1

更多研究表明,async默认情况下,asp.net 似乎会主动阻止调用。我相信这与Session它处理非 UI 线程的方式有关。所以我在我的 web.config 中添加了以下内容(见下文)

  • 使用TaskFriendlySynchronizationContext
  • enableSessionState="假"

不幸的是,它没有任何区别,我的async/await调用LongProcess()仍然阻塞。

<configuration>
  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
    <add key="webPages:Enabled" value="false" />
  </appSettings>
  <system.web>
    <httpRuntime targetFramework="4.5"/>
    <pages controlRenderingCompatibilityVersion="4.0" enableSessionState="false" />
    ... more config
</configuration>
4

2 回答 2

1

我是 C#5 的 async / await 特性的新手,但我确信这些特性仅用于此类任务。

No. async/await旨在使异步编程在单个进程的上下文中变得容易。它们不会改变 HTTP 通信的性质。

当您await在 ASP.NET 服务器上使用时(在 HTTP 请求的上下文中),您将 ASP.NET 线程返回到线程池。但是,ASP.NET 知道 HTTP 请求尚未完成,因此它不会完成对客户端(浏览器)的响应。

这是设计使然。

您需要使用 AJAX、SignalR 或其他一些解决方案才能执行您想要的操作。

于 2012-06-15T13:54:58.540 回答
0

尝试在 aspx 页面中设置页面属性Async="true"后,它看起来像这样 <%@ Page Language="C#" AutoEventWireup="true" CodeFile="XXX.aspx.cs" Inherits="xxx" Async="true" %>

在 tcode behile 文件中,您可以制作异步类型的任务和方法,并从中调用await 任务......

它可能有效

于 2015-03-25T12:51:06.553 回答