如何在调用 HttpListener.GetContextAsync() 后正确取消请求?
How to correctly cancel requests after calling HttpListener.GetContextAsync()?
我正在努力以不产生 IO 异常的方式关闭 HttpListener。
我似乎以一种不寻常的方式使用了 HttpListener,或者遗漏了一些明显的东西。
我正在设置一个 HttpListener 来侦听来自 OAuth2.0 登录的重定向。
我正在尝试启动侦听器,然后打开 Web 浏览器控件进行登录,然后在执行重定向后关闭侦听器。
代码还没有完成所有这些,因为我正在尝试先修复此错误。
如果我关闭登录 window 以中止登录,然后重试但再次中止,我会收到此错误:
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
在这个问题上似乎没有太多进展,所以我会 post 将我的解决方案提供给其他人,直到提供更好的解决方案。
捕获特定异常是我发现的异步处理已取消请求的唯一方法:
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
我正在努力以不产生 IO 异常的方式关闭 HttpListener。
我似乎以一种不寻常的方式使用了 HttpListener,或者遗漏了一些明显的东西。
我正在设置一个 HttpListener 来侦听来自 OAuth2.0 登录的重定向。 我正在尝试启动侦听器,然后打开 Web 浏览器控件进行登录,然后在执行重定向后关闭侦听器。
代码还没有完成所有这些,因为我正在尝试先修复此错误。
如果我关闭登录 window 以中止登录,然后重试但再次中止,我会收到此错误:
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
在这个问题上似乎没有太多进展,所以我会 post 将我的解决方案提供给其他人,直到提供更好的解决方案。
捕获特定异常是我发现的异步处理已取消请求的唯一方法:
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