У меня есть сервер, который запускает TcpListener
для прослушивания входящих соединений на указанный порт. Это осуществляется следующим образом:System.AppDomainUnloadedException в тесте из-нить не останавливая
type TCPListenerServer(discoveryPort:int) =
let server = new TcpListener (IPAddress.Loopback, discoveryPort)
let activeConnections = new List<TcpClient>()
let cancellationToken = new System.Threading.CancellationTokenSource()
let rec loop (pendingConnection:Task<TcpClient>) = async {
let newPendingConnection, client =
match pendingConnection.Status with
| TaskStatus.Created | TaskStatus.WaitingForActivation | TaskStatus.WaitingToRun
| TaskStatus.WaitingForChildrenToComplete | TaskStatus.Running ->
(None, None)
| TaskStatus.Faulted ->
let result = pendingConnection.Exception
raise (new System.NotImplementedException())
| TaskStatus.Canceled ->
raise (new System.NotImplementedException())
| TaskStatus.RanToCompletion ->
let connectionTask = server.AcceptTcpClientAsync()
(Some connectionTask, Some pendingConnection.Result)
| _ ->
raise (new System.NotImplementedException())
// Add the new client to the list
Option.iter (fun c -> activeConnections.Add c) client
// Switch the new pending connection if there is one
let connectionAttempt = defaultArg newPendingConnection pendingConnection
// Check that the connections are still alive
Seq.iter (fun (connection:TcpClient) -> if not connection.Connected then activeConnections.Remove connection |> ignore) activeConnections
Async.Sleep 1000 |> Async.RunSynchronously
return! loop connectionAttempt
}
member x.Start() =
try
server.Start()
let connectionTask = server.AcceptTcpClientAsync()
Async.Start (loop connectionTask, cancellationToken.Token)
with ex ->
server.Stop()
member x.Stop() =
cancellationToken.Cancel()
server.Stop()
member x.ActiveConnections =
activeConnections
И я делаю очень простой тест, который запускает сервер и убеждается исключение не выбрасывается, как следующим образом:
let cleanupTest (serverUsed:TCPListenerServer) =
serverUsed.Stop()
[<TestMethod>]
[<TestCategory(Networking)>]
member x.``Start Server``() =
let server = new TCPListenerServer(44000)
server.Start()
Async.Sleep 5000 |> Async.RunSynchronously
cleanupTest server
тест проходит, но я получаю следующее сообщение об ошибке в тестовом выходе в конце его:
System.AppDomainUnloadedException: пытающемуся получить доступ к выгружается AppDomain. Это может произойти, если тест (ы) начал поток, но не остановить его. Убедитесь, что все потоки, запущенные с помощью теста (ов), остановлены до завершения.
Оглядываясь назад на мой код, я понял, что моя рекурсивная петля никогда не заканчивается, поэтому я подумал, что это может быть причиной. Мое решение заключалось в том, чтобы добавить токен отмены (который находится в моем коде, который я вставил, его там не было), который я вызываю Cancel()
, когда я останавливаю сервер.
К сожалению, это не решило проблему. Что может вызвать это исключение (которое не терпит неудачу в моем тестировании)?