I have just started building a website using React with a .NET Core backend. The default framework gives me the WeatherForecast
controller. When making calls to this, there are no issues: fetch('weatherforecast')
returns the data.
Next I tried adding a second endpoint, Sitemap
, which is designed to return a JSON string (or array) to the client. Every time it is returning the base HTML page being displayed. In the setupProxy.js
file I have added /sitemap
to the createProxyMiddleware
context and I have used the "add Controller" option in VS2022.
I would blame this on my code but for one thing: when I replace the code in the WeatherForecast
controller with my own to return the sitemap, it works perfectly and returns the data I want.
Since this site will eventually have multiple API endpoints I need to know what I was doing wrong to get this functioning.
Below are the 3 files involved:
//setupProxy.js
const { createProxyMiddleware } = require('http-proxy-middleware');
const context = [
"/weatherforecast",
"/sitemap"
];
module.exports = function (app) {
const appProxy = createProxyMiddleware(context, {
target: 'https://localhost:7245/',
secure: false
});
app.use(appProxy);
};
//app.js
import React, { Component } from 'react';
export default class App extends Component {
static displayName = App.name;
constructor(props) {
super(props);
this.state = { forecasts: [], loading: true, sitemap:[] };
}
componentDidMount() {
this.populateWeatherData();
this.populateSitemapData();
}
static renderForecastsTable(forecasts) {
return (
<div>
<table className='table table-striped' aria-labelledby="tabelLabel">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
{forecasts.map(forecast =>
<tr key={forecast.date}>
<td>{forecast.date}</td>
<td>{forecast.temperatureC}</td>
<td>{forecast.temperatureF}</td>
<td>{forecast.summary}</td>
</tr>
)}
</tbody>
</table>
{/*{JSON.stringify(this.state.sitemap)}*/}
</div>
);
}
render() {
let contents = this.state.loading
? <p><em>Loading... Please refresh once the ASP.NET backend has started. See <a href="https://aka.ms/jspsintegrationreact">https://aka.ms/jspsintegrationreact</a> for more details.</em></p>
: App.renderForecastsTable(this.state.forecasts);
return (
<div>
<h1 id="tabelLabel" >Weather forecast</h1>
<p>This component demonstrates fetching data from the server.</p>
{contents}
</div>
);
}
async populateWeatherData() {
const response = await fetch('weatherforecast');
const data = await response.json();
this.setState({ sitemap: data, loading: false });
//this.setState({ forecasts: data, loading: false });
}
async populateSitemapData() {
const response = await fetch('sitemap');
const data = await response.json();
const temp = data;
console.log(data);
this.setState({ sitemap: temp, loading: false });
}
}
//WeatherForecastController.cs (with my code working)
using Microsoft.AspNetCore.Mvc;
namespace webapi.Controllers;
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet]
public IEnumerable<Intranet2.MCA.SitemapEntry> Get()
//public IEnumerable<WeatherForecast> Get()
{
//return Enumerable.Range(1, 5).Select(index => new WeatherForecast
//{
// Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
// TemperatureC = Random.Shared.Next(-20, 55),
// Summary = Summaries[Random.Shared.Next(Summaries.Length)]
//})
//.ToArray();
return Intranet2.MCA.Data.Sitemap().ToArray<Intranet2.MCA.SitemapEntry>();
}
}
//SitemapController.cs
using Intranet2.MCA;
using Microsoft.AspNetCore.Mvc;
// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
namespace webapi.Controllers
{
[ApiController]
[Route("[controller]")]
public class SitemapController : ControllerBase
{
// GET: api/<SitemapController>
[HttpGet]
//public string Get() //IEnumerable<Intranet2.MCA.SitemapEntry>
//{
// Console.WriteLine("Sitemap Test");
// var siteMap = Data.Sitemap();
// return siteMap;
//}
}
}
//Program.cs
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
I am sure that there is some overkill in the code displayed here but as I don’t know where the problem lies (obviously API call, but where?) I included everything which may play a part.
Any advice on where to find the solution to this would be appreciated. Having read multiple tutorials and pages on this, and even resorting to ChatGPT has availed nothing. Thank you.
*** EDIT ***
When I make a direct call to https://localhost:7245/sitemap
from the address bar it returns the correct data, so the problem appears to be in the proxy code.
2
Answers
So in playing around this morning and trying different things I found that I could call the
sitemap
controller directly from the URL of the browser. After doing that I found that it was working correctly. I modifiedpopulateWeatherData()
to call both API'sand I am now seeing the results I needed on the page. Not sure why it's working now when it wasn't yesterday but I am content.
I think your code about endpoint is correct. and your issue may come from here.
I created a new react asp.net core project, and I added an endpoint in Weather controller which url should be
/weatherforecast/getstring
Then in the react page. I added new property
cont
inthis.state
, and define a function to call the endpoint.Then change
FetchData.renderForecastsTable(this.state.forecasts);
toFetchData.renderForecastsTable(this.state.forecasts, this.state.cont);
, and changestatic renderForecastsTable(forecasts) {
tostatic renderForecastsTable(forecasts,cont) {
, then code worked. So I’m afraid this is the issue.