In Blazor WebAssembly solution, how to host the Blazor WASM client app on a different port to the server API

6.9k views Asked by At

I have a Blazor WebAssembly solution with a client project, server project and shared project, based on the default solution template from Microsoft. I'm editing and debugging in Visual Studio 2019 preview with Google Chrome.

Out-of-the-box, the solution has a single start-up project, which is the server application. That server application has a project reference to the client application. You can set it to use HTTPS by checking "Enable SSL" in the server project properties and I have done that.

When you click on debug it works perfectly.

Now I want to change it so that all my Blazor WASM pages are served from https://localhost:44331 and the API Controller endpoints of the server application are served from https://localhost:44331/api

I want to use this extra "/api" portion of the URL to keep the requests to the API separate from just navigating around the Blazor client app. So if I request "https://localhost:44331/api/something" I know I'm going to hit a point in my web API but if I request "https://localhost:44331/something" I know I'm going to hit a particular page in the Blazor client app. I think it will also be closer to how a normal setup would be in production.

I hope it's clear what I'm trying to do.

The obvious place to start seemed to be changing the "App URL" setting in the "Debug" portion of the Properties of the server app to "http://localhost:52708/api". The project assigns a secure URL of "https://localhost:44331/api". I left the setting the same in the client app, so in the client app, the "App URL" setting in the "Debug" portion of the Properties of the client app is still "http://localhost:52708", with the project assigning a secure URL of "https://localhost:44331".

That breaks everything.

Now "https://localhost:44331/" takes me to a 404 Not Found error and "https://localhost:44331/api" takes me to a page that says:

Loading...
An unhandled error has occurred. Reload

That would have been too easy! Does anybody know the correct way to get the environment how I want please?

3

There are 3 answers

1
benjamin On BEST ANSWER

Ok! I finally figured out a way that works. It is not complicated but it took me days to get to the answer so I'm going to post it here because I think it would be useful to other people.

On your controllers:

[Route("api/[controller]")]
public class SampleController : ControllerBase
    {
    //Etc.
    }

In Startup.cs...

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            //Etc.
            app.UseStaticFiles();
            app.UseRouting();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapRazorPages();
                endpoints.MapControllers();
                endpoints.Map("api/{**slug}", HandleApiFallback);
                endpoints.MapFallbackToFile("{**slug}", "index.html");
            });
        }

        private Task HandleApiFallback(HttpContext context)
        {
            context.Response.StatusCode = StatusCodes.Status404NotFound;
            return Task. CompletedTask;
        }
3
Henk Holterman On

The minimal changes to a fresh app from the Wasm/Hosted template:

WeatherForecastController.cs

//[Route("[controller]")]
  [Route("api/[controller]")]

FetchData.razor

//forecasts = await Http.GetJsonAsync<WeatherForecast[]>("WeatherForecast");
  forecasts = await Http.GetJsonAsync<WeatherForecast[]>("api/WeatherForecast");
0
Ryan D On

This is exactly how we want to run our Blazor WASM apps as sometimes we just want to run the API for testing and don't need the overhead of the client app. For example we run Swagger UI with the launch of our Server project so that can be useful.

To get this working I removed the reference to the Client project from the Server project (we might implement some other software patterns where we don't want this anyway). Then I add a launchSettings.json under the Properties of each project if it's not already there.

Here is an example :

{
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:64185",
      "sslPort": 44377
    }
  },
  "profiles": {
    "https": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
      "applicationUrl": "https://localhost:7105",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

Using the https profile, I edit the port numbers in the applicationUrl of both apps. For some reason only editing the port of the server still somehow serves the client. Editing both ports (usually 2 ports next to each other) seems to work.