WebForms事件中的异步

时间:2014-05-27 16:02:12

标签: c# asp.net webforms async-await

我试图在WebForms应用程序中使用新的ASP.NET Identity 2.0身份验证系统,但在允许用户保存数据源之前,我无法验证用户。

问题源于从数据源IIdentityValidator.ValidateAsync事件中调用OnUpdating。标记在功能上与默认的动态数据模板相同(除了添加Async="true"),后面的代码中有一些自定义。基本上,我手动为请求设置MetaTable(因为此页面是我的一条动态数据路径的替代品,但我希望保留脚手架属性的好处)并且我已经添加了DetailsDataSource_Updating事件。虽然下面的代码示例成功将用户保存到我们的数据库,但在返回客户端之前通常会抛出以下错误:

  

"在异步操作仍处于未决状态时完成异步模块或处理程序。"

我花了相当多的时间试图让这个工作,但还没有找到一个解决方案,不会锁定页面或抛出上述错误。我担心我完全误解了WebForms中的async / await,或者更糟糕的是,async / await只能用于MVC之外的数据库查询/绑定。

public partial class Edit : System.Web.UI.Page
{
    protected UserManager manager;
    protected CustomMetaTable table;

    protected void Page_Init(object sender, EventArgs e)
    {
        manager = UserManager.GetManager(Context.GetOwinContext());
        table = Global.DefaultModel.GetTable(typeof(User)) as CustomMetaTable;
        DynamicDataRouteHandler.SetRequestMetaTable(Context, table);
        FormView1.SetMetaTable(table);
        DetailsDataSource.EntityTypeFilter = table.EntityType.Name;
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        Title = table.EntityName;
        DetailsDataSource.Include = table.ForeignKeyColumnsNames;
    }

    protected void FormView1_ItemCommand(object sender, FormViewCommandEventArgs e)
    {
        if (e.CommandName == DataControlCommands.CancelCommandName)
        {
            Response.Redirect(table.ListActionPath);
        }
    }

    protected void FormView1_ItemUpdated(object sender, FormViewUpdatedEventArgs e)
    {
        if (e.Exception == null || e.ExceptionHandled)
        {
            Response.Redirect(table.ListActionPath);
        }
    }

    protected async void DetailsDataSource_Updating(object sender, Microsoft.AspNet.EntityDataSource.EntityDataSourceChangingEventArgs e)
    {
        IdentityResult result = await manager.UserValidator.ValidateAsync(e.Entity as User);
        if (!result.Succeeded)
        {
            e.Cancel = true;
        }
    }

1 个答案:

答案 0 :(得分:2)

在使用同步Validate方法编写新UserValidator的过程中,I found a class in the Identity assembly用于UserManagerRoleManager的所有同步包装器。我将这个类复制到我的项目中,它允许我同步使用异步方法,只有少数例外(通过在将变量引用到别处之前将结果分配给变量,似乎可以避免主要异常。)

internal static class AsyncHelper
{
    private static readonly TaskFactory _myTaskFactory = new TaskFactory(
        CancellationToken.None,
        TaskCreationOptions.None, 
        TaskContinuationOptions.None, 
        TaskScheduler.Default);

    public static TResult RunSync<TResult>(Func<Task<TResult>> func)
    {
        return _myTaskFactory.StartNew(func).Unwrap().GetAwaiter().GetResult();
    }

    public static void RunSync(Func<Task> func)
    {
        _myTaskFactory.StartNew(func).Unwrap().GetAwaiter().GetResult();
    }
}

用法:

AsyncHelper.RunSync(() => manager.UserValidator.ValidateAsync(e.Entity as User));