404 on "Fetch data" in .net core spa template app when using proxy development server
Asked Answered
C

3

2

I created an angular project using the .NET core 2.2 and the spa template.

I changed startup.cs to use a proxy development server when serving angular, so I could start my server and my client code independently.

I am using .net core 2.2 documentation and this blog post as a reference:

https://www.codingflow.net/building-single-page-applications-on-asp-net-core-2-2/

app.UseSpa(spa =>
        {
            // To learn more about options for serving an Angular SPA from ASP.NET Core,
            // see https://go.microsoft.com/fwlink/?linkid=864501

            spa.Options.SourcePath = "ClientApp";

            if (env.IsDevelopment())
            {
                //spa.UseAngularCliServer(npmScript: "start");
                spa.UseProxyToSpaDevelopmentServer("http://localhost:4200");
            }
        });

I then ran the following commands in two terminals

dotnet run

_

cd ./ClientApp\
npm start

When I navigate in my browser (chrome) to localhost:4200, webpack will serve my app. However, when I navigate to the fetch-data page from the template, the api call to

http://localhost:4200/api/SampleData/WeatherForecasts

Made in the fetch-data component, part of the standard template

import { Component, Inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app-fetch-data',
  templateUrl: './fetch-data.component.html'
})
    export class FetchDataComponent {
  public forecasts: WeatherForecast[];

  constructor(http: HttpClient, @Inject('BASE_URL') baseUrl: string) {
http.get<WeatherForecast[]>(baseUrl + 'api/SampleData/WeatherForecasts').subscribe(result => {
  this.forecasts = result;
}, error => console.error(error));
  }
}

interface WeatherForecast {
  dateFormatted: string;
  temperatureC: number;
  temperatureF: number;
  summary: string;
}

Returns a 404

GET http://localhost:4200/api/SampleData/WeatherForecasts 404 (Not Found)
HttpErrorResponse {headers: HttpHeaders, status: 404, statusText: "Not Found", url: "http://localhost:4200/api/SampleData/WeatherForecasts", ok: false, …}

Of course, this error is not thrown if I run IIS Express in debug mode from visual studio. This will launch a browser window on a different port (not 4200, 44333 usually) where all of the API requests seem to route fine.

I would like to be able to manage my client code independently of my server code. How can I do this? What is wrong with my current setup?

Cosmonautics answered 12/2, 2019 at 19:39 Comment(0)
E
3

While spliting the SPA project into Front-End and Back-End, you need to change the baseUrl in the angular.

For dotnet run, it will run the .net core project under https://localhost:5001 and http://localhost:5000.

For npm start, it will run the angular project under http://localhost:4200.

For @Inject('BASE_URL') baseUrl: string, it will return the angular url instead of core api url.

So, you need to change the request base url and you could try like:

export class FetchDataComponent {
public forecasts: WeatherForecast[];
private apiUrl: string = "https://localhost:5001/";
constructor(http: HttpClient, @Inject('BASE_URL') baseUrl: string) {
    http.get<WeatherForecast[]>(this.apiUrl + 'api/SampleData/WeatherForecasts').subscribe(result => {
    this.forecasts = result;
    }, error => console.error(error));
}
}

Since Angualr and Core project run under different ports, you need to enable Cors in the Core project like

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    //rest code
    app.UseCors(builder =>
    {
        builder.AllowAnyOrigin()
                .AllowAnyHeader()
                .AllowAnyMethod()
                .AllowCredentials();
    });
    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller}/{action=Index}/{id?}");
    });

    app.UseSpa(spa =>
    {
        // To learn more about options for serving an Angular SPA from ASP.NET Core,
        // see https://go.microsoft.com/fwlink/?linkid=864501

        spa.Options.SourcePath = "ClientApp";

        if (env.IsDevelopment())
        {
            //spa.UseAngularCliServer(npmScript: "start");
            spa.UseProxyToSpaDevelopmentServer("http://localhost:4200");
        }
    });
}
Eolith answered 13/2, 2019 at 6:27 Comment(0)
C
0

Thank you Tao Zhou for your answer. For my project, allowing for request from any origin was not an option, so I had to seek out a different answer.

Angular launches by default on port 4200. I created a proxy.conf.json file, and added it to the same directory as my package.json

{
"/api/*": {
  "target": "https://localhost:5001",
  "secure": false,
  "logLevel": "debug",
  "changeOrigin": true
}

}

I then edit my npm start scrip in package.json to be the following

"scripts": {
    "ng": "ng",
    "start": "npm run ng -- serve --proxy-config proxy.conf.json",

This instructs webpack to proxy all routes beginning with /api to port 5001. This is the convention .NET core for all routes that don't serve a view, and is ideal for my project.

This also allows us to keep stricture controls on header and origin for security reasons.

Cosmonautics answered 13/2, 2019 at 19:55 Comment(0)
M
0

In my case, this helped:

const PROXY_CONFIG = [
  {
    context: [
      "/api/" // add this line
    ],
    target: target,
    secure: false
  }
]
Melantha answered 18/9, 2023 at 21:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.