ASP.NET 6 + React APIs

Amir Latif 1 Reputation point
2022-06-04T19:59:03.067+00:00

I have been struggling to integrate React with ASP.NET 6

Finally I am using the following configuration at Program.cs

app.UseSpa(spa =>
{
    spa.Options.SourcePath = "FrontEnd";

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

and had WDS_SOCKET_PORT=7207 in the .env.development file of the frontend to refresh the page with every code update

Now my problem is that all APIs respond with 404 (it worked previously very well as WebAPI app without React)

I don't think that I am pointing to a wrong port, knowing that I am using the port the is in "applicationUrl": "https://localhost:7207"

I think the routing configuration needs to be adjusted

Can't solve it

Developer technologies ASP.NET ASP.NET Core
0 comments No comments
{count} votes

4 answers

Sort by: Most helpful
  1. Bruce (SqlWork.com) 77,686 Reputation points Volunteer Moderator
    2022-06-05T16:54:18.167+00:00

    .net 6 changed how proxies work with the react template.

    Typically with react development you want to run watch support. This uses node express to host a website for the react code. This means their are two website, the node and the asp.net core.

    Before net 6, the spa template implemented a proxy so that requests to the spa route actually called the node server. This meant your browser should open the asp.net core site.

    With .net 6 this was changed to the more typical solution of using node expresses api proxy support. This means the browser should open the node express site, and it proxies to the asp.net core site. The spa support in dev mode, just redirects to node server on startup. this is one by setting the proxy value in the react package.json to asp.net core site url (launch.json or visual studio settings).

    also with net 6 , the spa support (which is only need during debugging) is moved to dotnet.exe, and no longer in program.cs, all the magic is is in the project file and the spa proxy package (if the react project is in /FontEnd, just change spa root in project file):

    <Project Sdk="Microsoft.NET.Sdk.Web">    
    
      <PropertyGroup>    
        <TargetFramework>net6.0</TargetFramework>    
        <Nullable>enable</Nullable>    
        <TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>    
        <TypeScriptToolsVersion>Latest</TypeScriptToolsVersion>    
        <IsPackable>false</IsPackable>    
        <SpaRoot>ClientApp\</SpaRoot>    
        <DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>    
        <SpaProxyServerUrl>https://localhost:44456</SpaProxyServerUrl>    
        <SpaProxyLaunchCommand>npm start</SpaProxyLaunchCommand>    
        <ImplicitUsings>enable</ImplicitUsings>    
      </PropertyGroup>    
    
      <ItemGroup>    
        <PackageReference Include="Microsoft.AspNetCore.SpaProxy" Version="6.0.3" />    
      </ItemGroup>    
    
      <ItemGroup>    
        <!-- Don't publish the SPA source files, but do show them in the project files list -->    
        <Content Remove="$(SpaRoot)**" />    
        <None Remove="$(SpaRoot)**" />    
        <None Include="$(SpaRoot)**" Exclude="$(SpaRoot)node_modules\**" />    
      </ItemGroup>    
    
      <Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(SpaRoot)node_modules') ">    
        <!-- Ensure Node.js is installed -->    
        <Exec Command="node --version" ContinueOnError="true">    
          <Output TaskParameter="ExitCode" PropertyName="ErrorCode" />    
        </Exec>    
        <Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." />    
        <Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..." />    
        <Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />    
      </Target>    
    
      <Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">    
        <!-- As part of publishing, ensure the JS resources are freshly built in production mode -->    
        <Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />    
        <Exec WorkingDirectory="$(SpaRoot)" Command="npm run build" />    
    
        <!-- Include the newly-built files in the publish output -->    
        <ItemGroup>    
          <DistFiles Include="$(SpaRoot)build\**" />    
          <ResolvedFileToPublish Include="@(DistFiles-&gt;'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">    
            <RelativePath>wwwroot\%(RecursiveDir)%(FileName)%(Extension)</RelativePath>    
            <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>    
            <ExcludeFromSingleFile>true</ExcludeFromSingleFile>    
          </ResolvedFileToPublish>    
        </ItemGroup>    
      </Target>    
    </Project>    
    

    default program.cs

    var builder = WebApplication.CreateBuilder(args); 
    builder.Services.AddControllersWithViews(); 
    
    var app = builder.Build(); 
    
    if (!app.Environment.IsDevelopment()) 
    { 
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. 
        app.UseHsts(); 
    } 
    
    app.UseHttpsRedirection(); 
    app.UseStaticFiles(); 
    app.UseRouting(); 
    
    
    app.MapControllerRoute( 
        name: "default", 
        pattern: "{controller}/{action=Index}/{id?}"); 
    
    app.MapFallbackToFile("index.html");; 
    
    app.Run(); 
    
    1 person found this answer helpful.
    0 comments No comments

  2. Rennish Joseph 6 Reputation points
    2022-12-30T01:48:08.883+00:00

    After scratching my head for 3-4 hours and reading through so many stack overflow and MS posts, these are the things that worked for me with net 7 react template in VS 2022

    1. Make sure <SpaProxyServerUrl>https://localhost:3000</SpaProxyServerUrl> is pointed to your React dev url
    2. Make sure package.json has an entry with proxy:"netcore url:
    3. The setupProxy.js(ts) never worked for me. I commeneted this file and added the proxy:"server url" in package.json and I no longer got the 404 when hitting the C# controller method from react component

    Hopefully this helps someone in the future!!

    1 person found this answer helpful.

  3. SurferOnWww 4,631 Reputation points
    2022-06-05T01:54:31.467+00:00

    Did you try the Visual Studio 2022 template to create the React.js + ASP.NET Core project? If not, I suggest that you use the template, create the project and compare the template-generated project and your own project. There might be a hint to solve your issue.

    The template-generated project works as SPA without any addition or modification (app.UseSpa(spa => { ...}); is not required).

    208410-react2.jpg

    The Fetch data accesses the ASP.NET Core Web API which is included in the project, obtains the data from the Web API and shows the data as follows:

    208398-react3.jpg


  4. SurferOnWww 4,631 Reputation points
    2022-06-05T05:48:18.203+00:00

    The template uses proxy, on launching, it does not launch most of the time and sometimes it says that the port is busy, choose another one?

    I don't know what's going on in your environment.

    I describe the process in my environment below hoping this will help.

    (1) The proxy settings are included in the setupProxy.js file:

    const createProxyMiddleware = require('http-proxy-middleware');  
    const { env } = require('process');  
      
    const target = env.ASPNETCORE_HTTPS_PORT ? `https://localhost:${env.ASPNETCORE_HTTPS_PORT}` :  
      env.ASPNETCORE_URLS ? env.ASPNETCORE_URLS.split(';')[0] : 'http://localhost:35842';  
      
    const context =  [  
      "/weatherforecast",  
    ];  
      
    module.exports = function(app) {  
      const appProxy = createProxyMiddleware(context, {  
        target: target,  
        secure: false,  
        headers: {  
          Connection: 'Keep-Alive'  
        }  
      });  
      
      app.use(appProxy);  
    };  
    

    (2) Every time the application is started by the Visual Studio the proxy is made available as follows:

    208462-react1.jpg

    (3) The FetchData.js requests the url "weatherforecast" using the following script:

    async populateWeatherData() {  
        const response = await fetch('weatherforecast');  
        const data = await response.json();  
        this.setState({ forecasts: data, loading: false });  
    }  
    

    (4) The above request is properly sent to the http://localhost:44353 (host of Web API) through the proxy and response is returned as expected:

    208452-fiddler.jpg

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.