diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..98b27ad --- /dev/null +++ b/.gitignore @@ -0,0 +1,45 @@ +# Folders +artifacts/ +bin/ +obj/ +.dotnet/ +.nuget/ +.packages/ +.tools/ +.vs/ +.vscode/ +node_modules/ +BenchmarkDotNet.Artifacts/ +.gradle/ +src/SignalR/clients/**/dist/ +modules/ +.ionide/ + +# File extensions +*.aps +*.binlog +*.dll +*.DS_Store +*.exe +*.idb +*.lib +*.log +*.pch +*.pdb +*.pidb +*.psess +*.res +*.snk +*.so +*.suo +*.tlog +*.user +*.userprefs +*.vspx + +# Specific files, typically generated by tools +launchSettings.json +msbuild.ProjectImports.zip +StyleCop.Cache +UpgradeLog.htm +.idea \ No newline at end of file diff --git a/AiRepro.sln b/AiRepro.sln new file mode 100644 index 0000000..9a283c2 --- /dev/null +++ b/AiRepro.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Origin1", "Origin1\Origin1.csproj", "{985F15D9-F3D3-40D7-97B2-082A9DEB9ECF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "App2", "App2\App2.csproj", "{B5A1FDF7-37A4-4947-B627-D6A9F8123586}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "App3", "App3\App3.csproj", "{447E4F97-F345-4A5F-9B11-103AF14CB58E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {985F15D9-F3D3-40D7-97B2-082A9DEB9ECF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {985F15D9-F3D3-40D7-97B2-082A9DEB9ECF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {985F15D9-F3D3-40D7-97B2-082A9DEB9ECF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {985F15D9-F3D3-40D7-97B2-082A9DEB9ECF}.Release|Any CPU.Build.0 = Release|Any CPU + {B5A1FDF7-37A4-4947-B627-D6A9F8123586}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B5A1FDF7-37A4-4947-B627-D6A9F8123586}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B5A1FDF7-37A4-4947-B627-D6A9F8123586}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B5A1FDF7-37A4-4947-B627-D6A9F8123586}.Release|Any CPU.Build.0 = Release|Any CPU + {447E4F97-F345-4A5F-9B11-103AF14CB58E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {447E4F97-F345-4A5F-9B11-103AF14CB58E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {447E4F97-F345-4A5F-9B11-103AF14CB58E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {447E4F97-F345-4A5F-9B11-103AF14CB58E}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/App2/App2.csproj b/App2/App2.csproj new file mode 100644 index 0000000..119cc72 --- /dev/null +++ b/App2/App2.csproj @@ -0,0 +1,12 @@ + + + + netcoreapp3.1 + + + + + + + + diff --git a/App2/App3Client.cs b/App2/App3Client.cs new file mode 100644 index 0000000..9ba1d51 --- /dev/null +++ b/App2/App3Client.cs @@ -0,0 +1,21 @@ +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; + +namespace App2 +{ + public class App3Client + { + private readonly HttpClient _client; + + public App3Client(HttpClient client) + { + _client = client; + } + + public async Task SendAsync(string message) + { + await _client.PostAsync("/ping", new StringContent(message, Encoding.UTF8, "application/json")); + } + } +} \ No newline at end of file diff --git a/App2/Controllers/App2Controller.cs b/App2/Controllers/App2Controller.cs new file mode 100644 index 0000000..571aa1a --- /dev/null +++ b/App2/Controllers/App2Controller.cs @@ -0,0 +1,18 @@ +using System.Threading.Tasks; +using App2; +using Microsoft.AspNetCore.Mvc; + +namespace App3.Controllers +{ + [ApiController] + [Route("")] + public class App2Controller : ControllerBase + { + [HttpPost("ping")] + public async Task Ping([FromBody] object message, [FromServices] App3Client client) + { + await client.SendAsync(message.ToString()); + return Ok(); + } + } +} \ No newline at end of file diff --git a/App2/Program.cs b/App2/Program.cs new file mode 100644 index 0000000..93bca6e --- /dev/null +++ b/App2/Program.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; + +namespace App2 +{ + public class Program + { + public static void Main(string[] args) + { + CreateHostBuilder(args).Build().Run(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureLogging(l => l.AddConsole(o => o.IncludeScopes = true)) + .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }); + } +} \ No newline at end of file diff --git a/App2/Startup.cs b/App2/Startup.cs new file mode 100644 index 0000000..3fcf2d6 --- /dev/null +++ b/App2/Startup.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.HttpsPolicy; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; + +namespace App2 +{ + public class Startup + { + public Startup(IConfiguration configuration) + { + Configuration = configuration; + } + + public IConfiguration Configuration { get; } + + // This method gets called by the runtime. Use this method to add services to the container. + public void ConfigureServices(IServiceCollection services) + { + services.AddApplicationInsightsTelemetry(); + + services.AddControllers(); + services.AddHttpClient(client => + { + client.BaseAddress = new Uri(Configuration["Dependency"]); + }); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + app.UseRouting(); + + app.UseAuthorization(); + + app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); + } + } +} \ No newline at end of file diff --git a/App2/appsettings.Development.json b/App2/appsettings.Development.json new file mode 100644 index 0000000..8983e0f --- /dev/null +++ b/App2/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + } +} diff --git a/App2/appsettings.json b/App2/appsettings.json new file mode 100644 index 0000000..7d2720a --- /dev/null +++ b/App2/appsettings.json @@ -0,0 +1,12 @@ +{ + "Logging": { + "IncludeScopes": true, + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "AllowedHosts": "*", + "Dependency": "http://localhost:5002/app3" +} diff --git a/App3/App3.csproj b/App3/App3.csproj new file mode 100644 index 0000000..119cc72 --- /dev/null +++ b/App3/App3.csproj @@ -0,0 +1,12 @@ + + + + netcoreapp3.1 + + + + + + + + diff --git a/App3/Controllers/App3Controller.cs b/App3/Controllers/App3Controller.cs new file mode 100644 index 0000000..693f75a --- /dev/null +++ b/App3/Controllers/App3Controller.cs @@ -0,0 +1,19 @@ +using System.Text.Json; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; + +namespace App3.Controllers +{ + [ApiController] + [Route("")] + public class App3Controller : ControllerBase + { + [HttpPost("ping")] + public async Task Ping([FromBody] object message, [FromServices] ILogger logger) + { + logger.LogInformation(message.ToString()); + return Ok(); + } + } +} \ No newline at end of file diff --git a/App3/Program.cs b/App3/Program.cs new file mode 100644 index 0000000..ada1140 --- /dev/null +++ b/App3/Program.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; + +namespace App3 +{ + public class Program + { + public static void Main(string[] args) + { + CreateHostBuilder(args).Build().Run(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureLogging(l => l.AddConsole(o => o.IncludeScopes = true)) + .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }); + } +} \ No newline at end of file diff --git a/App3/Startup.cs b/App3/Startup.cs new file mode 100644 index 0000000..f23ad44 --- /dev/null +++ b/App3/Startup.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.HttpsPolicy; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; + +namespace App3 +{ + public class Startup + { + public Startup(IConfiguration configuration) + { + Configuration = configuration; + } + + public IConfiguration Configuration { get; } + + // This method gets called by the runtime. Use this method to add services to the container. + public void ConfigureServices(IServiceCollection services) + { + services.AddApplicationInsightsTelemetry(); + + services.AddControllers(); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + app.UseRouting(); + + app.UseAuthorization(); + + app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); + } + } +} \ No newline at end of file diff --git a/App3/appsettings.Development.json b/App3/appsettings.Development.json new file mode 100644 index 0000000..8983e0f --- /dev/null +++ b/App3/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + } +} diff --git a/App3/appsettings.json b/App3/appsettings.json new file mode 100644 index 0000000..bcd5e52 --- /dev/null +++ b/App3/appsettings.json @@ -0,0 +1,11 @@ +{ + "Logging": { + "IncludeScopes": true, + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "AllowedHosts": "*" +} diff --git a/Origin1/App2Client.cs b/Origin1/App2Client.cs new file mode 100644 index 0000000..6c4c7fa --- /dev/null +++ b/Origin1/App2Client.cs @@ -0,0 +1,23 @@ +using System; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; + +namespace Origin1 +{ + public class App2Client + { + private readonly HttpClient _client; + + public App2Client(HttpClient client) + { + _client = client; + } + + public async Task SendAsync(string message) + { + var resp = await _client.PostAsync("/ping", new StringContent(message, Encoding.UTF8, "application/json")); + Console.WriteLine(await resp.Content.ReadAsStringAsync()); + } + } +} \ No newline at end of file diff --git a/Origin1/Controllers/OriginController.cs b/Origin1/Controllers/OriginController.cs new file mode 100644 index 0000000..d0da38b --- /dev/null +++ b/Origin1/Controllers/OriginController.cs @@ -0,0 +1,18 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; + +namespace Origin1.Controllers +{ + [ApiController] + [Route("")] + public class OriginController : ControllerBase + { + [HttpPost("rest")] + public async Task Rest([FromBody] object message, [FromServices] App2Client client) + { + await client.SendAsync(message.ToString()); + return Ok(); + } + } +} \ No newline at end of file diff --git a/Origin1/Origin1.csproj b/Origin1/Origin1.csproj new file mode 100644 index 0000000..df21503 --- /dev/null +++ b/Origin1/Origin1.csproj @@ -0,0 +1,19 @@ + + + + netcoreapp3.1 + + + + + true + PreserveNewest + + + + + + + + + diff --git a/Origin1/Program.cs b/Origin1/Program.cs new file mode 100644 index 0000000..5771386 --- /dev/null +++ b/Origin1/Program.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; + +namespace Origin1 +{ + public class Program + { + public static void Main(string[] args) + { + CreateHostBuilder(args).Build().Run(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureLogging(l => l.AddConsole(o => o.IncludeScopes = true)) + .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }); + } +} \ No newline at end of file diff --git a/Origin1/Startup.cs b/Origin1/Startup.cs new file mode 100644 index 0000000..aa8f1cc --- /dev/null +++ b/Origin1/Startup.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.HttpsPolicy; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Origin1.WebSockets; + +namespace Origin1 +{ + public class Startup + { + public Startup(IConfiguration configuration) + { + Configuration = configuration; + } + + public IConfiguration Configuration { get; } + + // This method gets called by the runtime. Use this method to add services to the container. + public void ConfigureServices(IServiceCollection services) + { + services.AddApplicationInsightsTelemetry(); + + services.AddControllers(); + services.AddHttpClient(client => + { + client.BaseAddress = new Uri(Configuration["Dependency"]); + }); + services.AddSingleton(); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + app.UseRouting(); + + app.UseDefaultFiles() + .UseStaticFiles(); + + app.UseAuthorization(); + + app.UseWebSockets(); + app.Map("/ws", b => b.UseMiddleware()); + + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); + } + } +} \ No newline at end of file diff --git a/Origin1/WebSockets/ReproWebSocketHandler.cs b/Origin1/WebSockets/ReproWebSocketHandler.cs new file mode 100644 index 0000000..8f5550b --- /dev/null +++ b/Origin1/WebSockets/ReproWebSocketHandler.cs @@ -0,0 +1,17 @@ +using System.Threading.Tasks; + +namespace Origin1.WebSockets +{ + public class ReproWebSocketHandler + { + private readonly App2Client _client; + + public ReproWebSocketHandler(App2Client client) + { + _client = client; + } + + public async Task HandleAsync(string message) + => await _client.SendAsync(message); + } +} \ No newline at end of file diff --git a/Origin1/WebSockets/ReproWebSocketMiddleware.cs b/Origin1/WebSockets/ReproWebSocketMiddleware.cs new file mode 100644 index 0000000..bac567b --- /dev/null +++ b/Origin1/WebSockets/ReproWebSocketMiddleware.cs @@ -0,0 +1,90 @@ +using System; +using System.Buffers; +using System.IO; +using System.Net.WebSockets; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; + +namespace Origin1.WebSockets +{ + public class ReproWebSocketMiddleware + { + private readonly ILogger _logger; + private readonly ReproWebSocketHandler _handler; + private readonly RequestDelegate _next; + + public ReproWebSocketMiddleware( + ILogger logger, + ReproWebSocketHandler handler, + RequestDelegate next) + { + _logger = logger; + _handler = handler; + _next = next; + } + + public async Task Invoke(HttpContext context) + { + try + { + if (!context.WebSockets.IsWebSocketRequest) + { + await _next.Invoke(context); + return; + } + + WebSocket socket = await context.WebSockets.AcceptWebSocketAsync().ConfigureAwait(false); + await Receive(socket, context.RequestAborted); + } + catch (Exception ex) + { + _logger.LogError(ex, ex.Message); + } + } + + + private async Task Receive(WebSocket socket, CancellationToken contextRequestAborted) //, Action handleMessage) + { + while (socket.State == WebSocketState.Open) + { + string serializedMessage = null; + WebSocketReceiveResult result = null; + byte[] bytes = ArrayPool.Shared.Rent(16 * 1024); + try + { + var buffer = new ArraySegment(bytes); + + using MemoryStream ms = new MemoryStream(); + do + { + try + { + result = await socket.ReceiveAsync(buffer, contextRequestAborted).ConfigureAwait(false); + } + catch (OperationCanceledException e) + { + _logger.LogWarning(e, "Request aborted"); + return; + } + + ms.Write(buffer.Array, buffer.Offset, result.Count); + } while (!result.EndOfMessage); + + ms.Seek(0, SeekOrigin.Begin); + + using var reader = new StreamReader(ms, Encoding.UTF8); + serializedMessage = await reader.ReadToEndAsync().ConfigureAwait(false); + } + finally + { + ArrayPool.Shared.Return(bytes); + } + + await _handler.HandleAsync(serializedMessage); + } + } + } +} \ No newline at end of file diff --git a/Origin1/appsettings.Development.json b/Origin1/appsettings.Development.json new file mode 100644 index 0000000..8983e0f --- /dev/null +++ b/Origin1/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + } +} diff --git a/Origin1/appsettings.json b/Origin1/appsettings.json new file mode 100644 index 0000000..3b8d7c7 --- /dev/null +++ b/Origin1/appsettings.json @@ -0,0 +1,12 @@ +{ + "Logging": { + "IncludeScopes": true, + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "AllowedHosts": "*", + "Dependency": "http://localhost:5001/app2" +} diff --git a/Origin1/wwwroot/index.html b/Origin1/wwwroot/index.html new file mode 100644 index 0000000..0727833 --- /dev/null +++ b/Origin1/wwwroot/index.html @@ -0,0 +1,61 @@ + + + + + Title + + + + + + + + + + + \ No newline at end of file