How to inject data from the server in index.html in an ASP.NET Core 3 React app

Viewed 1045

I have an ASP.NET Core 3.1 React app created with dotnet new react.

I want to be able to embed some configuration values inside index.html so that I can use those in the React app.

I know I could add a Controller to expose these config values and fetch them during client app bootstrap but I want to avoid that request if it's possible and just embed it directly when the server is serving the index.html on the first request/refresh.

Is there a way to inject some javascript code from the ASP.NET Core app inside index.html like is described in this official CRA docs page?

2 Answers

Here's what I did:

  1. Add a script tag with an ID to the head of the index.html. The ID could be anything, here I'm using "appConfig"
<script type="text/javascript" id="appConfig"></script>
  1. Create config file
window.configVar1 = "hello";
window.configVar2 = "world";

In the Main function, before starting the web server:

  1. Load the config file into memory.
var clientAppConfig = File.ReadAllText(configFilePath);
  1. Load index.html into memory using HtmlAgilityPack. Make sure you have the correct file path for index.html. Building through VS2019 uses the path "$APP_HOME/ClientApp/public/index.html" and building with dotnet3.1 cli uses "$APP_HOME/ClientApp/build/index.html". Replace $APP_HOME with your app's home directory.
var doc = new HtmlDocument();
doc.Load(indexFilePath);
  1. Select the script tag using HtmlAgilityPack and replace the inner html with your config.
var configElement = doc.GetElementbyId("appConfig");
configElement.InnerHtml = clientAppConfig;
  1. Save your changes to disk.
doc.Save(indexFilePath);

You can put the code that starts the webserver after this and now your config variables should be available in the global window variable.

There is a similar question here which is answered:

In general, CRA produces projects where the client app is truly separate from the server. As such its intended architecture is to have the client make HTTP requests to the server for any runtime data that it needs. I'm not aware of a simple way to have it get dynamic data in the initial index.html page.

A complex way to achieve that would be to write custom ASP.NET Core middleware that intercepts the request for the index.html page and modifies the response dynamically. However this will be hard to implement robustly and is not something I'd recommend. If you can at all manage it, it's far easier to make the client do an HTTP request to the server for any runtime data it needs.

I've tried the middleware option based on similar work by Rick Strahl and it does work (note you may need to unzip the gzipped response from node). I did also start working on the Response stream wrapping to get around the memory usage and initially found the stream data returned was different. However I did not investigate further as I decided to bootstrap from the client instead.

The index.html page will be cached anyway so injecting server data doesn't really save a request if you have any dynamic data to inject. So there isn't much benefit anyway unless you go the full SSR route.

Related