我正在尝试在 WebForms 应用程序中使用新的 ASP.NET Identity 2.0 身份验证系统,但在允许用户保存数据源之前验证用户时遇到了问题。
问题源于从数据源的 OnUpdating
事件调用 IIdentityValidator.ValidateAsync
。该标记在功能上与默认的动态数据模板相同(除了添加了 Async="true"
),在后面的代码中进行了一些自定义。基本上,我为请求手动设置了 MetaTable
(因为此页面是我的动态数据路由之一的替代品,但我想保留脚手架属性的好处)并且我添加了DetailsDataSource_Updating
事件。虽然下面的代码示例成功地将用户保存到我们的数据库中,但在返回到客户端之前通常会抛出以下错误:
"An asynchronous module or handler completed while an asynchronous operation was still pending."
我花了相当多的时间试图让它工作,但还没有找到不会锁定页面或抛出上述错误的解决方案。我担心我完全误解了 WebForms 中的 async/await,或者更糟的是,async/await 仅真正可用于 MVC 之外的数据库查询/绑定(bind)。
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;
}
}
最佳答案
在用同步Validate方法写一个新的UserValidator的过程中,I found a class in the Identity assembly它用于 UserManager
和 RoleManager
的所有同步包装器。我将此类复制到我的项目中,它允许我同步使用异步方法,只有少数异常(exception)(似乎通过在别处引用结果之前将结果分配给变量来避免主要异常)。
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));
关于c# - WebForms 事件中的异步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23893984/