使用BuildManager.CreateInstanceFromVirtualPath创建页面时,PageAsyncTasks不等待完成

时间:2014-07-01 02:36:41

标签: c# asp.net asynchronous httphandler pageasynctask

我有一个页面,我使用Page.RegisterAsyncTask添加了异步任务。如果正常访问页面,例如通过导航到“/foo.aspx”,那么一切都按预期工作。该应用程序有一些相当复杂的路由,在某些情况下,页面是从调用BuildManager.CreateInstanceFromVirtualPath("~/foo.aspx", typeof(Page)) as IHttpHandler的处理程序创建的,然后在生成的处理程序上调用ProcessRequest。看起来页面在完成之前没有等待注册任务完成。

如何在此方案中让页面等待异步任务完成?

再现样本:

TestPage.aspx:

<%@ Page Language="C#" AutoEventWireup="true" Inherits="WebApplication1.TestPage" Async="true" AsyncTimeout="60" MasterPageFile="~/Site.Master" %>

<asp:Content ContentPlaceHolderID="MainContent" runat="server">
    <asp:Button Text="Do Stuff" OnClick="Button1_Click" ID="Button1" runat="server" />
    <asp:Literal ID="ResultsLiteral" runat="server" />

    <script runat="server">
        protected void Button1_Click(object sender, EventArgs e)
        {
            RegisterAsyncTask(new PageAsyncTask(DoStuff));
        }

        async System.Threading.Tasks.Task DoStuff()
        {
            await System.Threading.Tasks.Task.Delay(5);
            ResultsLiteral.Text = "Done";
        }
    </script>
</asp:Content>

TestHandler.cs

using System.Web;
using System.Web.Compilation;
using System.Web.Routing;
using System.Web.UI;

namespace WebApplication1
{
    public class TestHandler : IHttpHandler
    {
        public bool IsReusable
        {
            get { return false; }
        }

        public void ProcessRequest(HttpContext context)
        {
            GetHttpHandler().ProcessRequest(context);
        }

        IHttpHandler GetHttpHandler(HttpContext context)
        {
            return BuildManager.CreateInstanceFromVirtualPath("~/TestPage.aspx", typeof(Page)) as IHttpHandler;
        }
    }

    public class RouteHandler : IRouteHandler
    {
        public IHttpHandler GetHttpHandler(RequestContext context)
        {
            return new TestHandler();
        }
    }
}

路由(在RouteConfig.cs中添加):

public static void RegisterRoutes(RouteCollection routes)
{
    routes.Add(new Route("TestHandler", new RouteHandler()));
}

重现的步骤:

  1. 导航至TestPage.aspx,点击按钮&amp;消息按预期显示
  2. 导航到/ TestHandler,您应该看到相同的页面,但是如果您单击该按钮,则不会显示该消息。

1 个答案:

答案 0 :(得分:5)

您正在同步调用该页面。您需要异步调用它,否则像Page.RegisterAsyncTask这样的异步API将无法正常运行。尝试这样的事情:

public class TestHandler : IHttpAsyncHandler
{
    private IHttpAsyncHandler _handler;

    public bool IsReusable
    {
        get { return false; }
    }

    public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback callback, object state)
    {
        _handler = GetHttpHandler(context);
        return _handler.BeginProcessRequest(context, callback, state);
    }

    public void EndProcessRequest(IAsyncResult asyncResult)
    {
        _handler.EndProcessRequest(asyncResult);
    }

    public void ProcessRequest(HttpContext context)
    {
        throw new NotSupportedException();
    }

    IHttpAsyncHandler GetHttpHandler(HttpContext context)
    {
        return BuildManager.CreateInstanceFromVirtualPath("~/TestPage.aspx", typeof(Page)) as IHttpAsyncHandler;
    }
}