我如何调用从一个asp.net一个异步过程使用C#5异步/托管的await模块? [英] How do I call an asynchronous process from an asp.net hosted module using C#5 async / await?

查看:100
本文介绍了我如何调用从一个asp.net一个异步过程使用C#5异步/托管的await模块?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个长时间运行的过程,通过南希模块获取的方法调用。而不是让浏览器挂在过程中运行,我想这个调用是异步的,换句话说,我想Get方法马上返回并保持长期运行过程中做的事情。然后我可以检查定期的过程中的地位和采取相应的行动。

我是新来的异步/等待的C#5的功能,但我确信,这些都是为了只是这样的任务。下面的code显示了我的尝试。我已经把一些日志记录,以证明如预期它不是异步运行。相反,长时间运行的进程块Get方法等浏览器挂起。

模块

 公共类TestModule:NancyModule
{
    公共TestModule(ITestService TestService的)
    {
        获得[/ longprocess] = _ =>
            {
                Log.Write(模块:启动);
                testService.LongProcess();
                Log.Write(模块:完成);
                返回的HTTPStatus code.OK;
            };
    }
}

服务

 公共接口ITestService
{
    任务<布尔> LongProcess();
}公共类TestService的:ITestService
{
    公共异步任务<布尔> LongProcess()
    {
        等待LongProcessAsynch();
        返回true;
    }    私人任务<布尔> LongProcessAsynch()
    {
        Log.Write(LongProcess:启动);
        Thread.sleep代码(5000);
        //Task.Delay(5000); < - 有相同的效果
        Log.Write(LongProcess:完成);
        返回true.AsTask();
    }
}

扩展方法

 公共静态任务< T> AsTask< T>(这件T候选人)
{
    无功源=新TaskCompletionSource< T>();
    source.SetResult(候选人);
    返回source.Task;
}

日志输出

  14/06/2012 19时22分29秒:模块:开始
14/06/2012 19时22分29秒:LongProcess:开始
14/06/2012 19时22分34秒:LongProcess:完成
14/06/2012 19时22分34秒:模块:完成

您可以从日志输出上面看到 LongProcess()挡住了获取模块的回报。如果任务异步运行我希望在日志中看起来像这样:

预计登录

 模块:启动
LongProcess:启动
模块:完成
LongProcess:完成

我觉得什么是真正需要的是把等待在NancyModule获取方法。像下面也许是code的东西,但我不能这样做,因为我不能标记模块构造为 asnyc ,所以我不能使用的await Get方法中(或因此我认为当前)

 获取[/ longprocess] = _ =>
    {
        Log.Write(模块:启动);
        等待testService.LongProcess();
        Log.Write(模块:完成);
        返回的HTTPStatus code.OK;
    };

感谢您的帮助,实例或指针资源。

修改1

更多的研究表明,asp.net似乎在默认情况下,积极prevent 异步调用。事做与会话并处理非UI线程我相信的样子。所以我增加了以下到我的web.config(见下文)


  • UseTaskFriendlySynchronizationContext

  • ENABLESESSIONSTATE =FALSE

不幸的是,没有任何区别,我的异步 / 等待来电 LongProcess ()仍然阻塞。

 <结构>
  <&的appSettings GT;
    <添加键=ASPNET:UseTaskFriendlySynchronizationContextVALUE =真/>
    <添加键=网页:启用VALUE =FALSE/>
  < /的appSettings>
  <&的System.Web GT;
    <的httpRuntime targetFramework =4.5/>
    <页面controlRenderingCompatibilityVersion =4.0ENABLESESSIONSTATE =FALSE/>
    ...更多配置
< /结构>


解决方案

  

我是新来的异步/等待的C#5的功能,但我确信,这些都是为了只是这样的任务。


没有。 异步 / 等待目的是为了使异步编程方便的单个进程的上下文中的。他们不改变HTTP通信的性质。

当您使用等待的ASP.NET服务器(HTTP请求的情况下),你的ASP.NET线程返回线程池。但是,ASP.NET意识到该HTTP请求还没有完成,因此它不会完成向客户端(浏览器)的响应。

这是由设计。

您需要使用AJAX,SignalR,或一些其他的解决方案,以你想要的东西。

I have a long running process that is called via a Nancy Module Get method. Rather than have the browser hang while the process runs I would like this call to be asynchronous, in other words I want the Get method to return right away and leave the long running process to do its thing. I could then check the status of the process at regular intervals and act accordingly.

I am new to the async / await features of C#5 but I feel sure these are meant for just this kind of task. The code below shows my attempt. I have put in some Logging that demonstrates that it is not running asynchronously as expected. Instead the long running process blocks the Get method and so the browser hangs.

Module

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

Service

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

Extension Method

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

Log Output

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

You can see from the Log Output above that the LongProcess() is blocking the return of the Get module. If the task was running asynchronously I would expect the log to look something like this:

Expected Log

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

I think what is actually required is to put the await in the NancyModule Get method. Something like the code below perhaps, but I cannot do this because I cannot mark the module constructor as asnyc and so I cannot use await within the Get method (or so I currently believe)

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

Thanks for any help, examples or pointers to resources.

Edit 1

More research reveals that asp.net seems to actively prevent async calls by default. Something to do with the Session and the way it processes non UI threads I believe. So I have added the following to my web.config (see below)

  • UseTaskFriendlySynchronizationContext
  • enableSessionState="false"

Unfortunately it does not make any difference and my async / await call to LongProcess() is still blocking.

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

解决方案

I am new to the async / await features of C#5 but I feel sure these are meant for just this kind of task.

No. async/await are intended to make asynchronous programming easy within the context of a single process. They do not change the nature of HTTP communications.

When you use await on an ASP.NET server (in the context of an HTTP request), you are returning the ASP.NET thread to the thread pool. However, ASP.NET is aware that the HTTP request has not completed, so it does not complete the response to the client (browser).

This is by design.

You'll need to use AJAX, SignalR, or some other solution in order to do what you want.

这篇关于我如何调用从一个asp.net一个异步过程使用C#5异步/托管的await模块?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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