8

In VS2019 Preview you have multiple templates. I'm interested in the following two: enter image description here

I played a bit with both and I observed a difference. In the ASP.NET Core with React.js template, a SPA Proxy Server is started, whereas in the ASP.NET Core with React.js and Redux the simply works without that (the second template is in TS, not JS).

What I mean by simply works without that. I've looked into both .csproj files and I observed a difference (I'll only attach the noteworthy differences):

First template:

...
    <SpaProxyServerUrl>https://localhost:5002</SpaProxyServerUrl>
    <SpaProxyLaunchCommand>npm start</SpaProxyLaunchCommand>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.SpaProxy" Version="6.0.0-preview.6.21355.2" />
  </ItemGroup>
...
 <ItemGroup>
      <DistFiles Include="$(SpaRoot)build\**" />
      <ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
        <RelativePath>wwwroot\%(RecursiveDir)%(FileName)%(Extension)</RelativePath>
...

Second template:

...
# SpaProxy stuff missing
  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="6.0.0-preview.5.21301.17" />
  </ItemGroup>
...
 <ItemGroup>
      <DistFiles Include="$(SpaRoot)build\**; $(SpaRoot)build-ssr\**" />
      <ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
        <RelativePath>%(DistFiles.Identity)</RelativePath>

Note that in the second template Microsoft.AspNetCore.SpaServices.Extensions is used instead of Microsoft.AspNetCore.SpaProxy.

There are also some differences in the Startup.cs files. The second template has some additional middleware used

    public void ConfigureServices(IServiceCollection services)
    {
      services.AddControllersWithViews();

      // NEW
      services.AddSpaStaticFiles(configuration =>
      {
        configuration.RootPath = "ClientApp/build";
      });
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
      ...
      // NEW
      app.UseSpaStaticFiles();
      ...
      // NEW
      app.UseSpa(spa =>
      {
        spa.Options.SourcePath = "ClientApp";

        if (env.IsDevelopment())
        {
          spa.UseReactDevelopmentServer(npmScript: "start");
        }
      });
    }

I also observed that in the JS ClientApp there is a setupProxy.js file whereas in the TS ClientApp there is none. Also the npm start command is set to "start": "rimraf ./build && react-scripts start" and in the TS file it's only react-scripts start.

I tried to make the necessary adjustments to run the JS app like the TS one, but I think I'm missing something since I've ran into an issue:

System.Net.Http.HttpRequestException: Failed to proxy the request to http://localhost:61105/, because the request to the proxy target failed. Check that the proxy target server is running and accepting requests to http://localhost:61105/.

While this error does make sense, I don't get where and how the TS template starts such a proxy server, if it does at all.

My question is: Can I get the behaviour of the TS template in the JS template? If yes, how? If not, why?

2
  • Did you find a solution? I do not want the development proxy at all for various reasons: the HTTPS cert in appsettings.json overrides the one of the proxy giving me SSL warnings, the performance is not the same as the production server, etc. Commented May 17, 2022 at 7:08
  • 1
    Yeah I've spent a few days studying these boilerplates trying to figure out the magic and why 2 boilerplates are different and not consistent with each other?? The expected difference +-Redux lib, but indeed it looks one boilerplate came with .net core 5, another with .net core 6. Painless exp for newcomers becomes painful exp. for existing devs. Microsoft team need to spend a bit more efforts on boilerplates to make them consistent cause it makes a headache to choose & switch between boilerplates. Commented Sep 13, 2022 at 10:00

3 Answers 3

9
  1. Create "ASP.NET Core Web API" project
  2. In launchSettings set https.applicationUrl to "https://localhost:3000;http://localhost:3001"
  3. Change WeatherForecastController from [Route("[controller]")] to [Route("api/[controller]")]
  4. Add a ClientApp folder to the solution
  5. Inside ClientApp run >npm create vite@latest and choose your template (react/vue/etc.)
  6. npm install "vite-plugin-mkcert"
  7. Update vite.config.ts with the following. This will run the frontend on https://localhost:5000 and the backend on https://localhost:5000/api which proxies to https://localhost:3000/api
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import mkcert from "vite-plugin-mkcert";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react(), mkcert()],
  server: {
    port: 5000,
    https: true,
    strictPort: true,
    proxy: {
      "/api": {
        target: "https://localhost:3000",
        changeOrigin: true,
        secure: false,
        rewrite: (path) => path.replace(/^\/api/, "/api"),
      },
    },
  },
  1. Now you can restart your backend without having to start/stop the frontend or mess with the Microsoft SpaProxy nonsense.
Sign up to request clarification or add additional context in comments.

1 Comment

fyi, you are missing the closing tags for defineConfig({. Also, this didn't work for me when I try to access localhost:5000 on the web browser. on postman, it still runs the api with https://localhost:3000/api/WeatherForecast
2

I don't get where and how the TS template starts such a proxy server, if it does at all.

That's what spa.UseReactDevelopmentServer(npmScript: "start") does for you. Look at your package.json and you'll see that the start script starts the proxy server on port 5002.

Comments

1

While this error does make sense, I don't get where and how the TS template starts such a proxy server, if it does at all.

It doesn't. I just spent ages chasing my tail figuring this magic out.. and it's create-react-app: create-react-app docs

If the proxy option is not flexible enough for you, you can get direct access to the Express app instance and hook up your own proxy middleware.

You can use this feature in conjunction with the proxy property in package.json, but it is recommended you consolidate all of your logic into src/setupProxy.js.

Next, create src/setupProxy.js and place the following contents in it:

This github issue about what they've changed and why also provides a bit more context but to be honest, it's a complete hot mess at the moment. I wish I'd just made a spa on .NET 5 rather than trawl through all this mess

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.