Search code examples
c#reactjsdeploymentasp.net-core-webapivite

React Vite Web Api with ASP.NET Core app deployed, but axios fails with a 404 error


I created a full-stack Web API application where the frontend is ASP.NET Core with React.js (I use react vite) and the backend is a C# class library. I succeeded in deploying the frontend on IIS to loacalhost:80. When I browse the site from IIS, I am greeted with the loading icon that I created, which shows me that the frontend is deployed correctly, but the issue is that the loading never stops, because the axios request to "/api/account/getcurrentuser" gives a 404 error. The backend fails to find http://localhost:80/api/account/getcurrentuser.

Here is the detailed error info.

This happens for all axios requests. The server returns a 404 saying that it fails to find the resource. The physical path that it's looking in is C:\Website\EDIConverterDemo\wwwroot\api\account\getcurrentuser. The wwwroot folder is the one in my project's deployed folder. Is it supposed to look there and I need to add something, or is it directed to the wrong place?

The app works perfectly when run locally (not on IIS), and the route in my controller matches the url in my axios GET request.

I thought I may have needed to deploy the backend class library as well, but some research on that end told me that I don't need to deploy it separately. I think my issue is a react issue, specifically because I am using vite.

This is my vite.config.js file. Can it be CORS issue or an issue with the vite proxy? When I run my project locally (not on IIS), the react frontend is based on port 3000, while all calls that start with "/api" are rerouted to my controllers, which are hosted on port 7264. Do I need to change the ports in the proxy? The

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  server: {
    port: 3000,
    strictPort : true,
    proxy: {
      '/api' : {
        target: 'https://localhost:7264',
        changeOrigin: true,
        secure: false,enter image description here
        rewrite: (path) => path.replace(/^\/api/, '/api')
      }
    }
  }
})

Or can it be an issue with the backend?

This is the controller that /api/account/getcurrentuser is supposed to go to:

namespace EDIConverterWeb.Web.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class AccountController : ControllerBase
    {
        [HttpGet]
        [Route("getcurrentuser")]
        public User GetCurrentUser()
        {
            //here is some code that returns null if no user is signed in
            //otherwise, returns the currently logged-in user (object)
        }
    }
}

This is my Program.cs file:

Is something misconfigured which is causing the controller to be missed?

namespace EDIConverterWeb.Web
{
    public class Program
    {
        private static string CookieScheme = "EDIConverter";
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);

            builder.Services.AddAuthentication(CookieScheme)
           .AddCookie(CookieScheme, options =>
           {
               options.Events = new CookieAuthenticationEvents
               {
                   OnRedirectToLogin = context =>
                   {
                       context.Response.StatusCode = 403;
                       context.Response.ContentType = "application/json";
                       var result = System.Text.Json.JsonSerializer.Serialize(new { error = "You are not authenticated" });
                       return context.Response.WriteAsync(result);
                   }
               };
           });

            builder.Services.AddSession();

            // Add services to the container.

            builder.Services.AddControllersWithViews();

            var app = builder.Build();

            // Configure the HTTP request pipeline.
            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.UseSession();
            app.UseAuthentication();
            app.UseAuthorization();

            app.MapControllerRoute(
                name: "default",
                pattern: "{controller}/{action=Index}/{id?}");

            app.MapFallbackToFile("index.html"); ;

            app.Run();
        }
    }
}

This is how my web.config file looks:

<?xml version="1.0"?>
<configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <rule name="React Routes" stopProcessing="true">
                    <match url=".*" />
                    <conditions logicalGrouping="MatchAll">
                        <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
                        <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
                        <add input="{REQUEST_URI}" pattern="^/(api)" negate="true" />
                    </conditions>
                    <action type="Rewrite" url="/" />
                </rule>
            </rules>
        </rewrite>
    </system.webServer>
</configuration>

UPDATE: I don't think it's an issue with React, can you help me figure out how to get the API part of my app running on deploy?

ANOTHER UPDATE: Here is a link to a reproductible demo


Solution

  • 1)Open you project in the visual studio, Right click on the EDIConverterWeb.Web project and click on Publish

    2)In the Target choose Folder option-> Next

    3)Create New folder and give name to it -> click Finish enter image description here

    4)Now Click on the Publish to publish the site and wait until it finish

    5)Now Open iis -> Click on site-> Add new website

    enter image description here

    6)Set the published folder as the site root folder

    enter image description here

    Note: No need to add anything extra code for a now in the web.config file. Just use new publish folder