3

I have two Restful APIs projects that am trying to merge in one application project ( new .net core one) I modified the code in Running multiple independent ASP.NET Core pipelines side by side in the same application to accept WebSockets as following the extension method looks like :

public static IApplicationBuilder UseBranchWithServices(
            this IApplicationBuilder app,
            PathString path,
            Type requiredStartup) {
            var webHost =  WebHost.CreateDefaultBuilder()
                .UseStartup(requiredStartup).Build();
            var serviceProvider = webHost.Services;
            var serverFeatures = webHost.ServerFeatures;


            var appBuilderFactory =
                serviceProvider.GetRequiredService<IApplicationBuilderFactory>();
            var branchBuilder = appBuilderFactory.CreateBuilder(serverFeatures);
            var factory = serviceProvider.GetRequiredService<IServiceScopeFactory>();


            if (path.Value.Contains("/project2")) {

                branchBuilder.Map(
                    "/project2/ws",
                    x =>
                        x.UseMiddleware<project2MicroService.WebSockets.WebSocketMiddleWare>(
                            serviceProvider.GetService<SceneWebSocketHandler>()));

            } else if (path.Value.Contains("/project1")) {

                branchBuilder.Map(
                    "/project1/ws",
                    x => x.UseMiddleware<project1Service.WebSockets.WebSocketMiddleWare>(
                        serviceProvider.GetService<project1WebSocketHandler>()));
            }


            var branchDelegate = branchBuilder.Build();



            return app.Map(
                path,
                builder => {
                    builder.Use(
                        async (context, next) => {
                            if (!context.WebSockets.IsWebSocketRequest) {
                                await branchDelegate(context).ConfigureAwait(false);
                            } else {
                                 await context.WebSockets.AcceptWebSocketAsync().ConfigureAwait(false);
                                 await branchDelegate(context).ConfigureAwait(false);

                            }
                        });
                });
        }

and I call it in my new application for example like

app.UseBranchWithServices("/project2", typeof(project2MicroService.Startup));

while running unit tests the WebSocket connection is accepted but the middleware never been hit any idea how to fix this, please , my unit test

[ClassInitialize]

        public static void TestOneTimeSetUp(TestContext context) {

            var webHostBuilder = WebHost.CreateDefaultBuilder();
            webHostBuilder.UseContentRoot(Directory.GetCurrentDirectory());
            webHostBuilder.UseStartup<Startup>();
            server = new TestServer(webHostBuilder);
            client = server.CreateWebSocketClient();
        }

        /// <summary>
        /// OneTimeTearDown
        /// </summary>
        [ClassCleanup]
        public static void TestOneTimeTeardown() {
            server.Dispose();
        }

        /// <summary>
    /// TestWebsocketCanBeCreated
    /// </summary>
    [TestMethod]
    public void TestWebsocketCanBeCreated() {

        var TEST1wsUri = new UriBuilder(server.BaseAddress + "project1/ws") { Scheme = "ws" }.Uri;
        var TEST1websocket = client.ConnectAsync(TEST1wsUri, CancellationToken.None).Result;

        var TEST2wsUri = new UriBuilder(server.BaseAddress + "project2/ws") { Scheme = "ws" }.Uri;
        var TEST2websocket = client.ConnectAsync(TEST2wsUri, CancellationToken.None).Result; 

        Assert.AreEqual(WebSocketState.Open, TEST2websocket.State);
        Assert.AreEqual(WebSocketState.Open, TEST1websocket.State);



        Task.WaitAll(
            TEST1websocket.CloseAsync(
                WebSocketCloseStatus.NormalClosure,
                "",
                CancellationToken.None));

        Task.WaitAll(
            TEST2websocket.CloseAsync(
                WebSocketCloseStatus.NormalClosure,
                "",
                CancellationToken.None));

        Assert.AreEqual(WebSocketState.Closed, TEST2websocket.State);
        Assert.AreEqual(WebSocketState.Closed, TEST1websocket.State);
    }
Oğuzhan Soykan
  • 2,522
  • 2
  • 18
  • 33
Ali
  • 1,975
  • 5
  • 36
  • 55

2 Answers2

4

You're doing a couple things wrong:

1) you're trying to define route behavior with if/else logic. don't do that. 2) you're not actually declaring what you're trying to hit as part of your pipeline. consider the following:

            // https://stackoverflow.com/questions/48216929/how-to-configure-asp-net-core-server-routing-for-multiple-spas-hosted-with-spase
            app.Map("/rx", rx => {
                rx.UseSpa(rxApp => {
                     rxApp.Options.SourcePath = "../RX";
                    if (envIsDevelopment) rxApp.UseProxyToSpaDevelopmentServer("http://localhost:3000");
                });
            });
            app.Map("/V2", ng => {
                // https://learn.microsoft.com/en-us/aspnet/core/client-side/spa/angular?view=aspnetcore-2.2
                app.UseSpa(angularApp =>
                {
                    angularApp.Options.SourcePath = "../UI";

                    if (envIsDevelopment) angularApp.UseProxyToSpaDevelopmentServer("http://localhost:4200");
                });
            });

source

Note that link there: Filip W.'s blog

This is a different use case but it's an example of how you can map two different routes to different destinations. You're trying to switch on the URL and that's not how the pipeline works. It's a declarative pipeline; you have to define the routes according to .NET Core's built-in plugins (or add dependencies that contain other middleware plugins).

Take a look here:

https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.builder.mapextensions.map?view=aspnetcore-3.1

...and don't reinvent the wheel.

Chaim Eliyah
  • 2,743
  • 4
  • 24
  • 37
3

I had looked at the solution you got but it didn't work for me. So, we created a solution for that it does exactly the job that you wanted and works seamlessly for a long time.

https://github.com/damianh/lab/tree/master/dotnet/AspNetCoreNestedApps/AspNetCoreNestedApps

If I summarize with code;

 public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
 {
     app.IsolatedMap<NestedStartup>("/nested");
     app.IsolatedMap<XApp>("/xroute");
     app.Run(async context => await context.Response.WriteAsync("Hello World!"));
 }

You can separate your applications based on Startup and routing easily. But, keep that in mind somethings might not work for pipeline since you're branching after the main container built. We covered hosted services for branches.

Oğuzhan Soykan
  • 2,522
  • 2
  • 18
  • 33
  • It is a vague problem and another topic. It depends on your application, intention and most importantly the implementation that you use for caching. In my project, I have no problem with caching. – Oğuzhan Soykan Jan 06 '20 at 09:43
  • your work is elegant will give it a try I used another approach will share it with you – Ali Jan 06 '20 at 10:43