.net - 调用 HttpListener.GetContextAsync() 后如何正确取消请求?
问题描述
我正在努力以一种不会产生 IO 异常的方式关闭 HttpListener。
看来我要么以不寻常的方式使用 HttpListener,要么遗漏了一些明显的东西。
我正在设置一个 HttpListener 来监听来自 OAuth2.0 登录的重定向。我正在尝试启动侦听器,然后打开 Web 浏览器控件以登录,然后在执行重定向后关闭侦听器。
代码还没有完成所有这些,因为我试图先修复这个错误。
如果我关闭登录窗口以中止登录,然后重试但再次中止,我会收到此错误:
The I/O operation has been aborted because of either a thread exit or an application request
这是堆栈跟踪:
System.Net.HttpListener.EndGetContext(IAsyncResult asyncResult)
System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
--- End of stack trace from previous location where exception was thrown ---
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
BridgeIT.cOAuth2.VB$StateMachine_49_ListenForAuth.MoveNext() in xxx\cOAuth2.vb:line 235
我曾尝试使用 Begin/EndGetContext() 方法,但它们只会产生相同的结果。
我错过了什么?
这是我从按钮单击事件调用的登录函数:
Public Function Login(ByVal vsLoginUrl As String, ByVal vsClientID As String, ByVal voScopes As IEnumerable(Of String)) As Boolean
Dim bSuccess As Boolean = False
Dim oAR As AuthenticationResult = Nothing
Dim frm As frmOAuth2LoginDlg
Dim sResponseType As String = "code"
Dim sScope As String = String.Join(" ", voScopes)
Dim sState As String = gsPracticeID
Dim sCodeChallenge As String = GenerateCodeChallenge()
Dim sCodeChallengeMethod As String = "S256"
'Append query string params
vsLoginUrl = $"{vsLoginUrl}?response_type={sResponseType}&client_id={vsClientID}&redirect_uri={msRedirectURL}&scope={sScope}&state={sState}&code_challenge={sCodeChallenge}&code_challenge_method={sCodeChallengeMethod}"
Try
'Listen for the the oAuth redirect
ListenForAuth()
'Open web browser control
frm = New frmOAuth2LoginDlg(vsLoginUrl)
frm.ShowDialog()
'Do something after logging in
Catch ex As Exception
ShowError(Err.Number, Err.Description, ex)
Finally
CloseRedirectListener()
DisposeOfObject(frm)
End Try
End Function
和监听器功能:
Private Async Sub ListenForAuth()
Dim oContext As HttpListenerContext
Dim oRequest As HttpListenerRequest
Dim oResponse As HttpListenerResponse
moRedirectListener = New HttpListener
moRedirectListener.Prefixes.Add(msRedirectURL)
moRedirectListener.Start()
Try
oContext = Await moRedirectListener.GetContextAsync()
oRequest = oContext.Request
'Do something with the request
Catch oex As ObjectDisposedException
' Safely ignore this if the listener has been closed
' Else rethrow the exception
If oex.ObjectName <> "System.Net.HttpListener" Then
Throw
End If
Catch ex As Exception
ShowError(Err.Number, Err.Description, ex)
End Try
End Sub
和 CloseRedirectListener 函数:
Private Sub CloseRedirectListener()
If moRedirectListener IsNot Nothing Then
moRedirectListener.Stop()
moRedirectListener.Prefixes.Remove(msRedirectURL)
moRedirectListener.Close()
End If
End Sub
解决方案
在这个问题上似乎没有太多动静,所以我会为其他人发布我的解决方案,直到提供更好的解决方案。
捕获特定异常是我发现异步处理取消请求的唯一方法:
Private Async Function ListenForAuth(frm As frmOAuth2LoginDlg) As Task
Dim oContext As HttpListenerContext
Dim oRequest As HttpListenerRequest
moRedirectListener = New HttpListener
moRedirectListener.Prefixes.Add(RedirectURL)
moRedirectListener.Start()
Try
oContext = Await moRedirectListener.GetContextAsync()
oRequest = oContext.Request
' Do something with the request
' Handle the exceptions in the case of cancelled requests
Catch oObjectDisposedException As ObjectDisposedException
' If the Listener has been closed then safely ignore this
' Else rethrow
If oObjectDisposedException.ObjectName <> "System.Net.HttpListener" Then
Throw
End If
Catch oHttpListenerException As System.Net.HttpListenerException
' If the Listener has been stopped then safely ignore this
' Else rethrow
If oHttpListenerException.Message <> "The I/O operation has been aborted because Of either a thread Exit Or an application request" Then
Throw
End If
Catch ex As Exception
' Do something with other exceptions
Finally
If Application.OpenForms.OfType(Of frmOAuth2LoginDlg).Count > 0 Then
frm.Close()
End If
End Try
End Function
推荐阅读
- android - onSaveInstanceState 和 onRestoreInstanceState 函数不起作用
- c# - 在 DBContext 上设置从 Key Vault 检索的连接字符串的正确方法是什么?
- sql - 如何计算给定表中 2 列的平均时间差?
- javascript - 在 JavaScript 中的条件运算符内执行多个语句
- python - Python解析器层不匹配令牌
- php - 使用日期范围的特定星期几填充 PHP 数组(使用 Laravel)
- c++ - 在不更改参数的情况下将迭代函数转换为递归函数
- javascript - 在标记为模块的脚本标记中使用“import”语句会产生 404 错误
- c++ - 为什么这个以前工作的 boost beast 代码在 1.75.0 版本中突然失败了?(可能回归?)
- javascript - 创建一个接收两个数组的函数。将 arr1 和 arr2 中的所有数字相加。如果 arr1 的总和等于 arr2 返回 true。如果不是,则为假