protected override void Start() { _clientOption.IsServiceUdp = true; _clientOption.UdpServerAddress = ServerAddress; _clientOption.UdpServerPort = UdpServerPort; _clientOption.PingInterval = PingInterval; _clientOption.MtuInterval = MtuInterval; _clientOption.RudpDisconnectTimeout = RudpDisconnectTimeout; _clientOption.TcpServerAddress = ServerAddress; _clientOption.TcpServerPort = TcpServerPort; _clientOption.IsCheckAlive = IsCheckAlive; _clientOption.CheckAliveInterval = CheckAliveInterval; _clientOption.CheckAliveTimeout = CheckAliveTimeout; SetClientOption(_clientOption); _client = new NetClientP2p( _clientOption, DefaultLoggerFactory.Create(builder => { builder.SetMinimumLevel(LogLevel); builder.AddUnityDebugLogger(); })); ClientP2p.SyncType = SyncType; ClientP2p.SyncInterval = SyncInterval; _client.OnErrored += OnError; NetClientGlobal.Instance.SetClient(ClientP2p); }
public NetServer( ServerOption serverOption, NetStatistic statistics = null, ILoggerFactory loggerFactory = null, ISessionFactory sessionFactory = null) { Name = serverOption.Name; _serverOption = serverOption; //_serverOptions.PacketFilter = _serverOptions.PacketFilter ?? new XorPacketFilter(); _loggerFactory = loggerFactory ?? DefaultLoggerFactory.Create(builder => { builder.AddConsoleLogger(); }); _logger = _loggerFactory.CreateLogger("Server"); _statistic = statistics ?? new NetStatistic(); _sessionFactory = sessionFactory ?? new DefaultSessionFactory(_serverOption, _loggerFactory, _statistic); _sessionManager = new SessionManager(_serverOption.MaxSession); if (_serverOption.IsServiceUdp) { _p2pManager = new P2pManager(); OnSessionClosed += _p2pManager.OnSessionClose; } _rpcHandlers = new List <IRpcInvokable>(); }
public NetClient(ClientOption clientOption, ILoggerFactory loggerFactory = null) { _clientOption = clientOption; //_clientOptions.PacketFilter = _clientOptions.PacketFilter ?? new XorPacketFilter(); _loggerFactory = loggerFactory ?? DefaultLoggerFactory.Create(builder => { builder.AddConsoleLogger(); }); _logger = _loggerFactory.CreateLogger(nameof(NetClient)); _receivedPacketQueue = new ConcurrentQueue <NetPacket>(); _packetReader = new NetDataReader(); _statistic = new NetStatistic(); _tcpChannel = new TcpChannel( _clientOption, _loggerFactory.CreateLogger(nameof(TcpChannel)), _statistic); if (_clientOption.IsServiceUdp == true) { _udpChannel = new UdpChannel( _clientOption, _loggerFactory.CreateLogger(nameof(UdpChannel)), _statistic, 0); } _request = new SessionRequest(this, _statistic); _rpcHandlers = new List <IRpcInvokable>(); }
/// <summary> /// Configures the history store logger. /// </summary> /// <param name="historyStore">The history store.</param> /// <returns>IHistoryStore.</returns> public IHistoryStore ConfigureHistoryStoreLogger(IHistoryStore historyStore) { historyStore = historyStore ?? DefaultHistoryStore; if (DefaultLoggerFactory != null && historyStore?.Logger is NullLogger) { historyStore.Logger = DefaultLoggerFactory.CreateLogger(historyStore.GetType()); } return(historyStore); }
public async Task TestCommandLine(Type hostConfiguratorType) { var hostConfigurator = CreateObject <IHostConfigurator>(hostConfiguratorType); using (var server = CreateSocketServerBuilder <StringPackageInfo, CommandLinePipelineFilter>(hostConfigurator) .UseCommand((options) => { options.AddCommand <SORT>(); }).BuildAsServer()) { Assert.Equal("TestServer", server.Name); Assert.True(await server.StartAsync()); OutputHelper.WriteLine("Server started."); var pipelineFilter = new CommandLinePipelineFilter { Decoder = new DefaultStringPackageDecoder() }; var options = new ChannelOptions { Logger = DefaultLoggerFactory.CreateLogger(nameof(TestCommandLine)) }; var client = hostConfigurator.ConfigureEasyClient(pipelineFilter, options); StringPackageInfo package = null; client.PackageHandler += async(s, p) => { package = p; await Task.CompletedTask; }; var connected = await client.ConnectAsync(new IPEndPoint(IPAddress.Loopback, hostConfigurator.Listener.Port)); Assert.True(connected); client.StartReceive(); await client.SendAsync(Utf8Encoding.GetBytes("SORT 10 7 3 8 6 43 23\r\n")); await Task.Delay(1000); Assert.NotNull(package); Assert.Equal("SORT", package.Key); Assert.Equal("3 6 7 8 10 23 43", package.Body); await client.CloseAsync(); await server.StopAsync(); } }
public void TestStringLocator() { var refs = new ManagedReferences(); var factory = new DefaultLoggerFactory(); refs.Put(null, factory); var component = refs.GetOneOptional("ABC"); Assert.Null(component); }
public void TestAutoCreateComponent() { var refs = new ManagedReferences(); var factory = new DefaultLoggerFactory(); refs.Put(null, factory); var logger = refs.GetOneRequired <ILogger>(new Descriptor("*", "logger", "*", "*", "*")); Assert.NotNull(logger); }
public void Run() { var serverOption = new ServerOption() { Name = "SampleGameServer", TcpServerPort = 12000, IsServiceUdp = true, UdpServerPort = 12001, MaxSession = 100, }; var loggerFactory = DefaultLoggerFactory.Create( builder => { builder.SetMinimumLevel(LogLevel.Information); builder.AddConsoleLogger(); } ); var statistics = new NetStatistic(); var sessionFactory = new DefaultSessionFactory( serverOption, loggerFactory, statistics, (createInfo) => { return(new UserSession(createInfo)); }); _server = new NetServer( serverOption, statistics, loggerFactory, sessionFactory); _server.AddRpcService(new LoginRpcServiceSession()); _server.StartAsync().Wait(); _p2pGroup = _server.P2pManager.CreateP2pGroup(); while (true) { var key = Console.ReadKey(); if (key.Key == ConsoleKey.Escape) { Console.WriteLine("quit"); break; } } _server.StopAsync().Wait(); }
public static async Task MainAsync(string[] args) { DefaultLoggerFactory defaultLoggerFactory = new DefaultLoggerFactory(); defaultLoggerFactory.SetProvider(new ConsoleLoggerProvider()); ApplicationContext.ConfigureLogger(defaultLoggerFactory, "MainLogger"); ApplicationContext.Logger.LogDebug("TEST LOG FOR DEBUGGING"); //TryCatch.Invoke(()=> DoAction()); await TryCatch.InvokeAsync(() => DoActionAsync()); }
public async Task TestBindLocalEndPoint(Type hostConfiguratorType) { IAppSession session = default; var hostConfigurator = CreateObject <IHostConfigurator>(hostConfiguratorType); using (var server = CreateSocketServerBuilder <StringPackageInfo, CommandLinePipelineFilter>(hostConfigurator) .UseSessionHandler(async s => { session = s; await Task.CompletedTask; }) .BuildAsServer()) { Assert.Equal("TestServer", server.Name); Assert.True(await server.StartAsync()); OutputHelper.WriteLine("Server started."); var pipelineFilter = new CommandLinePipelineFilter { Decoder = new DefaultStringPackageDecoder() }; var options = new ChannelOptions { Logger = DefaultLoggerFactory.CreateLogger(nameof(TestBindLocalEndPoint)) }; var client = hostConfigurator.ConfigureEasyClient(new EasyClient <StringPackageInfo>(pipelineFilter, options)); var localPort = 8080; client.LocalEndPoint = new IPEndPoint(IPAddress.Loopback, localPort); var connected = await client.ConnectAsync(new IPEndPoint(IPAddress.Loopback, hostConfigurator.Listener.Port)); Assert.True(connected); await Task.Delay(500); Assert.NotNull(session); Assert.Equal(localPort, (session.RemoteEndPoint as IPEndPoint).Port); await client.CloseAsync(); await server.StopAsync(); } }
/// <summary> /// Registers the specified mailer type. /// </summary> /// <typeparam name="T"></typeparam> /// <typeparam name="TSettings">The type of the t settings.</typeparam> /// <param name="settings">The settings.</param> /// <param name="logger">The logger.</param> /// <param name="store">The store.</param> public virtual void Register <T, TSettings>(TSettings settings, ILogger logger = null, IHistoryStore store = null) where TSettings : class, IMailerSettings where T : Mailer <TSettings> { Register(() => { var ctor = typeof(T).GetConstructor(new[] { typeof(TSettings), typeof(ILogger), typeof(IHistoryStore) }); return((T)ctor.Invoke( new object[] { settings, logger ?? DefaultLoggerFactory?.CreateLogger(typeof(T)) ?? NullLogger.Instance, ConfigureHistoryStoreLogger(store) })); }); }
public void FindsNonGuaranteedBombsAndThenRecursivelyFindsGuaranteedBombs() { var logger = DefaultLoggerFactory.CreateLoggerForTests(); string[] data = new[] { "########.........", "#######..........", "######...........", "#####............", "####.............", "###..............", "##...............", "#................", "...........1.....", "........12..4...#", "........11.....##", "..............###", ".............####", "............#####", "...........######", "..........#######", ".........########" }; var game = new GalaxySweeperGame { field = data.ToList() }; var deVakjesArray = GalaxyGameHelper.CreateVakjesArray(game); var stats = BommenBepaler.BepaalBommenMulti2(deVakjesArray, TestBotConfig()); stats.Log(logger); var flattened = TwoDimensionalArrayHelper.Flatten(deVakjesArray).Where(t => t != null).ToList(); LogTopBombs(flattened, logger); GalaxyVisualizator.RenderToConsole(deVakjesArray, logger); Assert.Equal(5, flattened.Count(t => t.VakjeBerekeningen.BerekendVakjeType == BerekendVakjeType.GuaranteedBom)); Assert.Equal(7, flattened.Count(t => t.VakjeBerekeningen.BerekendVakjeType == BerekendVakjeType.GuaranteedNoBom)); }
public void DoesntFindAllTheseFalsePositives() { var logger = DefaultLoggerFactory.CreateLoggerForTests(); //Hier vond hij random bommen string[] data = new[] { "########B3..1.B10", "#######BRR2.B3310", "######1233BR3BR10", "#####001B.2..B200", "####0002B..R21000", "###210013B2100001", "##BB101.R3000001R", "#.3201B3R1000002.", "..R102..1111112R.", ".1.12B2..R.R.R.1#", "...R.3RB21.2RB.##", "...1.R3.....R2###", "....B3..B.12.####", "...B3R..3..R#####", ".....1.2..2######", "..........#######", ".........########" }; var game = new GalaxySweeperGame { field = data.ToList() }; var deVakjesArray = GalaxyGameHelper.CreateVakjesArray(game); var stats = BommenBepaler.BepaalBommenMulti2(deVakjesArray, TestBotConfig()); stats.Log(logger); var flattened = TwoDimensionalArrayHelper.Flatten(deVakjesArray).Where(t => t != null).ToList(); LogTopBombs(flattened, logger); GalaxyVisualizator.RenderToConsole(deVakjesArray, logger); Assert.Equal(0, flattened.Count(t => t.VakjeBerekeningen.BerekendVakjeType == BerekendVakjeType.GuaranteedBom)); }
protected virtual void Start() { _clientOption.TcpServerAddress = ServerAddress; _clientOption.TcpServerPort = TcpServerPort; _clientOption.IsCheckAlive = IsCheckAlive; _clientOption.CheckAliveInterval = CheckAliveInterval; _clientOption.CheckAliveTimeout = CheckAliveTimeout; SetClientOption(_clientOption); _client = new NetClient( _clientOption, DefaultLoggerFactory.Create(builder => { builder.SetMinimumLevel(LogLevel); builder.AddUnityDebugLogger(); })); _client.OnErrored += OnError; }
public void FindsThisOneThatSjoerdsOneDoesToo() { var logger = DefaultLoggerFactory.CreateLoggerForTests(); string[] data = new[] { "########B21000000", "#######13R2000000", "######11RB1011000", "#####B23R201R2121", "####B3R42113R2BB2", "###B33RR3R2R22B3B", "##13B23R4211.113B", "#.1R213BB2....1RR", ".1211R3BB31.1124R", "1R1.1124BB11R2R2#", "11...1R22212321##", ".....11.1R2RB1###", "..121...11132####", ".1BR2.....1B#####", ".12..4...12######", "......3.1B#######", "....2...1########" }; var game = new GalaxySweeperGame { field = data.ToList() }; var deVakjesArray = GalaxyGameHelper.CreateVakjesArray(game); var stats = BommenBepaler.BepaalBommenMulti2(deVakjesArray, TestBotConfig()); stats.Log(logger); var flattened = TwoDimensionalArrayHelper.Flatten(deVakjesArray).Where(t => t != null).ToList(); LogTopBombs(flattened, logger); GalaxyVisualizator.RenderToConsole(deVakjesArray, logger); Assert.Equal(3, flattened.Count(t => t.VakjeBerekeningen.BerekendVakjeType == BerekendVakjeType.GuaranteedBom)); }
protected virtual void Awake() { _clientOption.TcpServerAddress = ServerAddress; _clientOption.TcpServerPort = TcpServerPort; _clientOption.IsCheckAlive = IsCheckAlive; _clientOption.CheckAliveInterval = CheckAliveInterval; _clientOption.CheckAliveTimeout = CheckAliveTimeout; _client = new NetClient( _clientOption, DefaultLoggerFactory.Create(builder => { builder.SetMinimumLevel(LogLevel); builder.AddUnityDebugLogger(); })); _client.OnErrored += OnError; if (_isDontDestroyOnLoad) { DontDestroyOnLoad(gameObject); } }
/// <summary> /// Registers the specified mailer type using a safety mailer proxy. /// </summary> /// <typeparam name="TProxy">The type of the t proxy.</typeparam> /// <typeparam name="TProxySettings">The type of the t proxy settings.</typeparam> /// <typeparam name="TMailer">The type of the t mailer.</typeparam> /// <typeparam name="TMailerSettings">The type of the t settings.</typeparam> /// <param name="settings">The settings.</param> /// <param name="proxySettings">The proxy settings.</param> /// <param name="logger">The logger.</param> /// <param name="store">The store.</param> public virtual void Register <TProxy, TProxySettings, TMailer, TMailerSettings>( IProxyMailerSettings proxySettings, TMailerSettings settings, ILogger logger = null, IHistoryStore store = null) where TProxy : class, IProxyMailer <TProxySettings, TMailer>, IMailer where TProxySettings : class, IProxyMailerSettings where TMailer : class, IMailer <TMailerSettings> where TMailerSettings : class, IMailerSettings { Register(() => { var mailerCtor = typeof(TMailer).GetConstructor(new[] { typeof(TMailerSettings), typeof(ILogger), typeof(IHistoryStore) }); var realMailer = (TMailer)mailerCtor?.Invoke( new object[] { settings, logger ?? DefaultLoggerFactory?.CreateLogger(typeof(TMailer)) ?? NullLogger.Instance, ConfigureHistoryStoreLogger(store) }); var proxyCtor = typeof(TProxy).GetConstructor(new[] { typeof(TMailer), typeof(TProxySettings) }); return((TProxy)proxyCtor?.Invoke( new object[] { realMailer, proxySettings })); }); }
/// <summary> Creates a new REST-only Discord client. </summary> internal BaseDiscordClient(DiscordRestConfig config, API.DiscordRestApiClient client) { ApiClient = client; LogManager = config.LoggerFactory; if (LogManager == null) { LogManager = new DefaultLoggerFactory(); LogManager.AddProvider(new DefaultLoggerProvider()); } _stateLock = new SemaphoreSlim(1, 1); _restLogger = LogManager.CreateLogger <DiscordRestApiClient>(); _isFirstLogin = config.DisplayInitialLog; UseInteractionSnowflakeDate = config.UseInteractionSnowflakeDate; ApiClient.RequestQueue.RateLimitTriggered += async(id, info, endpoint) => { if (info == null) { _restLogger.LogTrace($"Preemptive Rate limit triggered: {endpoint} {(id.IsHashBucket ? $"(Bucket: {id.BucketHash})" : "")}"); } else { _restLogger.LogWarning($"Rate limit triggered: {endpoint} {(id.IsHashBucket ? $"(Bucket: {id.BucketHash})" : "")}"); } return(Task.CompletedTask); }; ApiClient.SentRequest += (method, endpoint, millis) => { _restLogger.LogTrace($"{method} {endpoint}: {millis} ms"); return(Task.CompletedTask); }; }
public async Task TestBindLocalEndPoint(Type hostConfiguratorType) { IAppSession session = default; var hostConfigurator = CreateObject <IHostConfigurator>(hostConfiguratorType); using (var server = CreateSocketServerBuilder <StringPackageInfo, CommandLinePipelineFilter>(hostConfigurator) .UseSessionHandler(async s => { session = s; await Task.CompletedTask; }) .BuildAsServer()) { Assert.Equal("TestServer", server.Name); Assert.True(await server.StartAsync()); OutputHelper.WriteLine("Server started."); var pipelineFilter = new CommandLinePipelineFilter { Decoder = new DefaultStringPackageDecoder() }; var options = new ChannelOptions { Logger = DefaultLoggerFactory.CreateLogger(nameof(TestBindLocalEndPoint)) }; var client = hostConfigurator.ConfigureEasyClient(pipelineFilter, options); var connected = false; var localPort = 0; for (var i = 0; i < 3; i++) { localPort = _rd.Next(40000, 50000); client.LocalEndPoint = new IPEndPoint(IPAddress.Loopback, localPort); try { connected = await client.ConnectAsync(new IPEndPoint(IPAddress.Loopback, hostConfigurator.Listener.Port)); } catch (SocketException e) { if (e.SocketErrorCode == SocketError.AccessDenied || e.SocketErrorCode == SocketError.AddressAlreadyInUse) { continue; } throw e; } break; } Assert.True(connected); await Task.Delay(500); Assert.NotNull(session); Assert.Equal(localPort, (session.RemoteEndPoint as IPEndPoint).Port); await client.CloseAsync(); await server.StopAsync(); } }
private static ILogger CreateLogger() { ILogger selectedLogger = null; Console.WriteLine(); var selectLoggerMenu = new ConsoleMenu(ConsoleMenuType.KeyPress); selectLoggerMenu.MenuOptions.Add(new ConsoleMenuOption("Color Logger", () => selectedLogger = DefaultLoggerFactory.CreateLoggerForConsoleApp())); selectLoggerMenu.MenuOptions.Add(new ConsoleMenuOption("FaST Logger", () => selectedLogger = DefaultLoggerFactory.CreateLoggerForConsoleAppFast())); selectLoggerMenu.RenderMenu(); selectLoggerMenu.WaitForResult(); return(selectedLogger); }
public async Task Start() { // 서버 옵션을 정의 var serverOption = new ServerOption() { Name = "StarterServer", TcpServerPort = 12000, IsServiceUdp = true, UdpServerPort = 12001, MaxSession = 1000, IsCheckAlive = true, CheckAliveInterval = 50000, CheckAliveTimeout = 60000, }; // 로거 팩토리를 생성 var loggerFactory = DefaultLoggerFactory.Create( builder => { builder.SetMinimumLevel(LogLevel.Information); builder.AddConsoleLogger(); } ); var statistics = new NetStatistic(); // UserSession 을 사용하기 위해서 팩토리를 만듬 var sessionFactory = new DefaultSessionFactory( serverOption, loggerFactory, statistics, (createInfo) => { return(new UserSession(createInfo)); }); // 서버를 생성 _server = new NetServer( serverOption, statistics, loggerFactory, sessionFactory); // 자동으로 생성된 Rpc 서비스를 등록함 _server.AddRpcService(new LoginRpcServiceSession()); _server.AddRpcService(new ShopRpcServiceSession()); // P2p 그룹을 만듬 (현재는 1개만 필요하니 한개만 만듬. 여러개 생성가능) _p2pGroup = _server.P2pManager.CreateP2pGroup(); // 서버를 시작함 await _server.StartAsync(); // 메인스레드에 키 입력을 받을 수 있게 함 while (true) { var key = Console.ReadKey(); if (key.Key == ConsoleKey.Escape) { Console.WriteLine("quit"); break; } } // 서버 정지 await _server.StopAsync(); }
public void FindsSetsWithGuaranteedBombs() { var logger = DefaultLoggerFactory.CreateLoggerForTests(); var vakjeLinksBoven = new Vakje('.', 0, 0); var vakjeRechtsBoven = new Vakje('.', 1, 0); var vakjeLinks = new Vakje('.', 0, 1); var vakjeRechts = new Vakje('.', 1, 1); var vakjeLinksOnder = new Vakje('.', 0, 2); var vakjeRechtsOnder = new Vakje('.', 1, 2); var alleVakjes = new List <Vakje>() { vakjeLinksBoven, vakjeRechtsBoven, vakjeRechts, vakjeRechtsOnder, vakjeLinksOnder, vakjeLinks }; var overallSet = new VakjeSetDeluxe(0, 0, alleVakjes); //Set1 groen linksboven var set1 = new VakjeSetDeluxe(0, 0, new List <Vakje>() { vakjeLinks, vakjeLinksBoven }); //Set2 rood top var set2 = new VakjeSetDeluxe(0, 0, new List <Vakje>() { vakjeLinksBoven, vakjeRechtsBoven }); //Set3 Rood rechts (3 set) var set3 = new VakjeSetDeluxe(0, 0, new List <Vakje>() { vakjeRechtsBoven, vakjeRechts, vakjeRechtsOnder }); //Set4 Blauw rechtsboven var set4 = new VakjeSetDeluxe(0, 0, new List <Vakje>() { vakjeRechtsBoven, vakjeRechts }); //Set5 Blauw onder var set5 = new VakjeSetDeluxe(0, 0, new List <Vakje>() { vakjeLinksOnder, vakjeRechtsOnder }); //Set6 Rood linksonder (Enkel) var set6 = new VakjeSetDeluxe(0, 0, new List <Vakje>() { vakjeLinksOnder }); //Set7 Blauw links (Enkel) var set7 = new VakjeSetDeluxe(0, 0, new List <Vakje>() { vakjeLinks }); var alleSets = new List <VakjeSetDeluxe>() { set1, set2, set3, set4, set5, set6, set7 }; var result = SetBepaler.BepaalSetsThatFillMeCompletely(overallSet, alleSets); Assert.Equal(2, result.Count); }
public async Task TestDetachableChannel(Type hostConfiguratorType) { var hostConfigurator = CreateObject <IHostConfigurator>(hostConfiguratorType); using (var server = CreateSocketServerBuilder <TextPackageInfo, LinePipelineFilter>(hostConfigurator) .UsePackageHandler(async(s, p) => { await s.SendAsync(Utf8Encoding.GetBytes("PRE-" + p.Text + "\r\n")); }).BuildAsServer()) { Assert.Equal("TestServer", server.Name); Assert.True(await server.StartAsync()); OutputHelper.WriteLine("Server started."); var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); await socket.ConnectAsync(hostConfigurator.GetServerEndPoint()); var stream = await hostConfigurator.GetClientStream(socket); var channel = new StreamPipeChannel <TextPackageInfo>(stream, socket.RemoteEndPoint, socket.LocalEndPoint, new LinePipelineFilter(), new ChannelOptions { Logger = DefaultLoggerFactory.CreateLogger(nameof(TestDetachableChannel)), ReadAsDemand = true }); channel.Start(); var msg = Guid.NewGuid().ToString(); await channel.SendAsync(Utf8Encoding.GetBytes(msg + "\r\n")); var round = 0; await foreach (var package in channel.RunAsync()) { Assert.NotNull(package); Assert.Equal("PRE-" + msg, package.Text); round++; if (round >= 10) { break; } msg = Guid.NewGuid().ToString(); await channel.SendAsync(Utf8Encoding.GetBytes(msg + "\r\n")); } OutputHelper.WriteLine("Before DetachAsync"); await channel.DetachAsync(); // the connection is still alive in the server Assert.Equal(1, server.SessionCount); // socket.Connected is is still connected Assert.True(socket.Connected); var ns = stream as DerivedNetworkStream; Assert.True(ns.Socket.Connected); // the stream is still usable using (var streamReader = new StreamReader(stream, Utf8Encoding, true)) using (var streamWriter = new StreamWriter(stream, Utf8Encoding, 1024 * 1024 * 4)) { for (var i = 0; i < 10; i++) { var txt = Guid.NewGuid().ToString(); await streamWriter.WriteAsync(txt + "\r\n"); await streamWriter.FlushAsync(); OutputHelper.WriteLine($"Sent {(i + 1)} message over the detached network stream"); var line = await streamReader.ReadLineAsync(); Assert.Equal("PRE-" + txt, line); OutputHelper.WriteLine($"Received {(i + 1)} message over the detached network stream"); } } await server.StopAsync(); } }