3

I have working web client, it uses "wwwroot/appsettings.json" file for its configuration.

Now I would like to override just single settings using environment variable for it (as an example, in reality there will be many, arbitrary, overrides). Is there ready to use mechanism, similar to ASP.NET Core server (all it takes is calling extension method and combining json, env. variables)?

I am not asking about multiple .json files and switching between them depending on ENVIRONMENT variable, it is completely different scenario.

So far I didn't find anything even close, so thinking about DIY approach I see an ugly path -- moving client configuration file into hosting server, adding main node in client .json file like "client", using environment variables with prefix "client", merging those data using ASP.NET server mechanism, dumping it back to file for the client usage. And hoping it will work :-).

astrowalker
  • 3,123
  • 3
  • 21
  • 40
  • Blazor uses the same framework as .NET Core, or now I guess .NET 5.0 too. By default it automatically pulls environment variables in. If you have not created your own host builder it is already doing what you want. – Crowcoder Mar 22 '21 at 12:02
  • @Crowcoder, thank you, but even in server I don't see anything automatic -- I call `AddEnvironmentVariables` extension method to take env. variables into account. I tried this for web client in "Program.cs" but both original "builder.Configuration" and manually built config using mentioned method give me the same result and I don't see env. variables in those configs. For the record I dump configs with `Console.WriteLine` in "Index.razor" page and check output in browser console. – astrowalker Mar 23 '21 at 07:32
  • You don't need to call AddEnvirinmentVariables, it is already done in the default host builder. There must be something else wrong. I use environment variables to override appsettings all the time. – Crowcoder Mar 23 '21 at 11:12
  • @Crowcoder, I don't know what is wrong, I can just tell what I see -- there is no 100% equivalent flow at the client as it is at server. For example I tried to read env. variables by hand -- they are not set. – astrowalker Mar 23 '21 at 12:43
  • WebAssembly does not support Env vars, does it? Would be weird if it did. – H H Mar 23 '21 at 13:51
  • I totally missed that you're using webassembly – Crowcoder Mar 23 '21 at 22:28
  • @astrowalker Blazor WASM is an SPA running on a browser. There are no relevant environment variables there. If you want to pull volatile settings from the server you'll have to do it the same way as any other data - through an HTTP call. You can do that by creating a custom configuration source that calls the server to retrieve settings and caches them. An SPA can't be restarted after settings changes the way a site can, so you need a way to refresh settings on the client. One way would be to refresh settings periodically. Another, to use SignalR to *push* changes or just trigger a refresh – Panagiotis Kanavos Mar 24 '21 at 08:17

1 Answers1

-1

So I followed DIY path :-) If anyone like it here are the steps:

  • create 3 files with empty JSON at web client wwwroot -- appsettings.json, appsettings.Development.json and Production version as well

  • put your entire web client config in appsettings.json at hosting server at "CLIENT" node for example

  • in your server Startup constructor create configuration as usual, but then fetch entire "CLIENT" section and "jsonize" it back (see: https://stackoverflow.com/a/62533775/6734314) -- convert it to string and write to $"wwwroot/appsettings.{env.EnvironmentName}.json" (where env is IWebHostEnvironment)

And that's it -- I tested it in Development mode and in Production. The only drawbacks I see are:

  • it looks weird :-)
  • when executed using VS the written file is put not relative to binary file, but relative to project -- so when you are done you have to delete newly created file (otherwise on the next run VS will complain about conflict between two static files)

You override the settings using env. variables at server side using "CLIENT" prefix, and the rest is as usual.

For the record, I am not saying this is perfect, but I didn't look for anything more than I asked in my question. What I would like to do however is to reduce the number of steps, or even better to use some already existing mechanism. I will be grateful for the improvements/tips within those areas.

astrowalker
  • 3,123
  • 3
  • 21
  • 40
  • The *client* is an SPA running on the end user's browser and just like any SPA has no access to any server-side data. Any settings you want applied to this SPA have to get there the same way any other data does - through an HTTP call. There's absolutely no reason to read settings from `appsettings.json` - that's just a default name for reading settings from JSON files. You could easily use `potato.fries`. For volatile settings it would make more sense to write a custom config source that reads specific settings from the server through an HTTP call – Panagiotis Kanavos Mar 24 '21 at 08:08
  • Besides, what you did won't detect changes to the environment variables until the SPA is downloaded again. You can't force a restart of an SPA the way you can with a site. – Panagiotis Kanavos Mar 24 '21 at 08:15
  • That's not right, besides you can't change any files in the browser from the server. There's no automatic handling for `appsettings.json`. That's just [a default name](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-5.0#default-configuration) used with the [Json File configuration provider](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-5.0#file-configuration-provider). It's no different than calling `cfg.AddJsonFile("potato.fries",reloadOnChange: true);` – Panagiotis Kanavos Mar 24 '21 at 09:27
  • `even desktop apps won't react to them` that's incorrect as well. *Every* config source can raise a change notification. If you use the Options pattern, you can get the latest config values or a specific snapshot. That's not something specific to the file providers, it's built into the config middleware itself. Some providers have built-in change notifications, some don't. In your case though, there are no real files *on the browser*. – Panagiotis Kanavos Mar 24 '21 at 09:31
  • It solves A by making a loooong trip and leaving some parts unsolved (like handling env variable changes. Which you *do* care about, otherwise you wouldn't use them). I do know what `AddJsonFile` does, I've been using .NET Core' config since 2.0 in console apps, before the Generic host came about. I've been using Blazor Wasm for quite a while too – Panagiotis Kanavos Mar 24 '21 at 09:34
  • `now please tell this to Microsoft , so maybe Visual Studio could react to those changes` it does, or rather the web app does. VS has nothing to do with how *applications* and web sites treat changes *in production*. You posted an answer. It's not good, there are easier ways to do it – Panagiotis Kanavos Mar 24 '21 at 09:35
  • If you care about env variables, it's probably because you use them,eg in containers, to distribute configuration. To apply config changes you can restart the container BUT that won't affect clients. You have to restart the clients to get the changes to them. This means your apps will have inconsistent settings until they all reload – Panagiotis Kanavos Mar 24 '21 at 09:36