@@ -62,16 +62,7 @@ public TestHttpServer(Func<HttpListenerContext, Task> handler)
6262
6363 _listenerThread = new Thread ( ( ) =>
6464 {
65- while ( ! _cts . Token . IsCancellationRequested )
66- try
67- {
68- var context = _listener . GetContext ( ) ;
69- Task . Run ( ( ) => HandleRequest ( context ) ) ;
70- }
71- catch ( HttpListenerException ) when ( _cts . Token . IsCancellationRequested )
72- {
73- break ;
74- }
65+ RequestLoop ( ) . GetAwaiter ( ) . GetResult ( ) ;
7566 } ) ;
7667
7768 _listenerThread . Start ( ) ;
@@ -81,10 +72,47 @@ public void Dispose()
8172 {
8273 _cts . Cancel ( ) ;
8374 _listener . Stop ( ) ;
84- _listenerThread . Join ( ) ;
75+ try
76+ {
77+ _listenerThread . Join ( ) ;
78+ }
79+ catch ( ThreadStateException )
80+ {
81+ // Ignore if the listener thread is already dead
82+ }
83+ catch ( ThreadInterruptedException )
84+ {
85+ // Ignore interrupted listener thread, it's now closed anyway
86+ }
8587 GC . SuppressFinalize ( this ) ;
8688 }
8789
90+ private async Task RequestLoop ( )
91+ {
92+ while ( ! _cts . Token . IsCancellationRequested )
93+ try
94+ {
95+ var contextTask = _listener . GetContextAsync ( ) ;
96+ // Wait with a cancellation token.
97+ await contextTask . WaitAsync ( _cts . Token ) ;
98+ // Get the context or throw if there was an error.
99+ var context = await contextTask ;
100+ // Run the handler in the background.
101+ _ = Task . Run ( ( ) => HandleRequest ( context ) ) ;
102+ }
103+ catch ( HttpListenerException ) when ( _cts . Token . IsCancellationRequested )
104+ {
105+ // Ignore, we expect the listener to throw an exception when
106+ // it's stopped
107+ break ;
108+ }
109+ catch ( TaskCanceledException )
110+ {
111+ // Ignore, the CTS was cancelled
112+ break ;
113+ }
114+ }
115+
88116 private async Task HandleRequest ( HttpListenerContext context )
89117 {
90118 try
0 commit comments