У меня есть решение.Я изменил часть вызова Server.Transfer на:
if ( ( HttpContext.Current.Handler as Page )?.IsAsync ?? false )
{
if ( transfer )
{
HttpContext.Current.Server.Execute( page, false );
HttpContext.Current.Response.Flush();
Thread.CurrentThread.Abort();
}
else
{
HttpContext.Current.Response.Redirect( page, false );
Thread.CurrentThread.Abort();
}
}
else
{
if ( transfer )
{
HttpContext.Current.Server.Transfer( page, false );
}
else
{
HttpContext.Current.Response.Redirect( page );
}
}
Затем обновил обработчик асинхронных щелчков, чтобы перехватить исключение ThreadAbortException.Обработчик исключений вызывает ResetAbort и CompleteRequest.
private async void SubmitButton_Click( object sender, EventArgs e )
{
try
{
//Awaited async call that returns a value.
//Call to utility classes that eventually call GoToPage( string page, bool transfer )
}
catch ( ThreadAbortException tEx )
{
Thread.ResetAbort();
HttpContext.Current.Response.SuppressContent = true;
HttpContext.Current.ApplicationInstance.CompleteRequest();
}
}
Объяснение: В ASP.NET в обработчике синхронных запросов Server.Transfer и Response.Redirect (посредством внутреннего вызова Response.End) будут вызывать Thread.Abort (вызывать исключение ThreadAbortException),выполнить блокирующий вызов, выполнив синхронную очистку буфера запроса в браузере клиента.Затем вызовите ApplicationInstance.CompleteRequest (), который пропускает дальнейшие события и конвейерные модули.
Таким образом, в случае асинхронного обработчика, CompleteRequest () вызывается внутренне, а не Response.End, исключение ThreadAbortException не генерируется, и код продолжает выполняться после вызова Transfer или Redirect.Мой обработчик событий щелчка для страницы является асинхронным обработчиком пустот, поэтому компилятор делает его асинхронным, и мы получаем асинхронные проблемы Server.Transfer Response.Redirect вниз по течению.
Решение: Server.Execute запускает код страницы, которую ятоже хочу передать и заполняет буфер ответа.Flush сбрасывает буфер в браузер.Предпочитает FlushAsync, избегая синхронного сброса, но содержащий метод не является асинхронным.Прерывание выдает исключение ThreadAbortException и пропускает код после него.Response.Redirect похож.Установите для параметра endReponse значение false, чтобы он не вызывал Response.End для внутреннего использования.Затем прервите поток, чтобы пропустить последующий код после него в стеке.
В обработчике события щелчка я уничтожаю исключение ThreadAbortException в обработчике исключений.ResetAbort предотвращает автоматическое повторное создание исключения после обработчика.Без ResetAbort код выполнялся в последующих событиях.SuppressContent предотвращает одновременное отображение содержимого как текущего, так и передаваемого страниц.Это происходило в некоторых ситуациях, в зависимости от того, где был асинхронный код.CompleteRequest пропускает события и модули http и переходит к событию EndRequest.
Я пытался использовать PageAsyncTask и связанные с ним функции в асинхронной части, чтобы избежать обработчика асинхронных щелчков, но он только запускает задачу.На самом деле его не ожидают, поэтому он завершает выполнение кода, где мне нужно значение, возвращаемое им до его завершения.Помещение всего кода обработчика событий в PageAsyncTask также не сработало, поскольку мне нужно, чтобы он выполнялся в обработчике событий, а не позже.ExecuteRegisteredAsyncTasks работает только в устаревшем контексте синхронизации asp.net.Не работает с AspNetSynchronizationContext.По крайней мере, в .NET 4.6.1.Преобразование в .NET Core не вариант.
Не то, на что я надеялся в решении.Надеюсь, кто-то более знающий, чем я, есть лучшеЭто не означает, что я записываю половину существующей программы.