3

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?

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
benjamin
  • 1,364
  • 1
  • 14
  • 26
  • 1
    What version are you on? There were some changes to this model lately. – H H Apr 09 '20 at 11:37
  • I am on Microsoft Visual Studio Community 2019 Preview Version 16.6.0 Preview 2.1. The WASM app targets netstandard2.1 with RazorLang 3.0. The web API targets netcoreapp3.1. Both are in C# 8.0. – benjamin Apr 09 '20 at 12:45

3 Answers3

8

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;
        }
benjamin
  • 1,364
  • 1
  • 14
  • 26
3

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");
H H
  • 263,252
  • 30
  • 330
  • 514
  • Thanks for the very fast response, Henk! When the app is set up this way the Blazor application still intercepts requests to https://localhost:44331/api/anything and displays a page that says "there is nothing at this address". If possible, I would expect a request like this to deliver raw JSON from the web api, or an error, instead of a page on the Blazor WASM app, because I only want the client app to be involved when the URL does not have the "/api" path. Do you see what I mean? – benjamin Apr 09 '20 at 12:39
  • Hi @henk-holterman! I hope you are well. I was wondering if you had a chance to look at this and knew the way to configure controller fallback so that "/api" routes were not routed to the Blazor client app? – benjamin Apr 16 '20 at 13:14
  • Thanks for that, Henk! For ASP-NET-Core people, below is my first attempt at a solution. It seems to get the job done but I'd be glad to know if it is the standard and correct way: – benjamin Apr 16 '20 at 14:27
0

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.

Ryan D
  • 1,023
  • 11
  • 16