Kevin
Kevin

Reputation: 267

Best practive to inject css style in .net core / webpack web application

I am starting a new web application. The backend is in c# .net core and the front-end is a react app that is placed in the wwwroot with webpack. The admins of the web application can change some colors (button color, header color, etc.) These colors are saved in a database and should be injected in a style sheet. The production style sheet looks something like

.my-button {
   background: ##main-color##
}

when the css is served i would like to replace ##main-color## with the color that is saved in the database.

In the startup i tried adding a middleware on the request pipeline. However the request to the css file is never triggered here.

In the previous application i used the exact same setup except .net framework was used instead of .net core. I used rewrite rules and a middleware on the request pipeline. The middleware then checked if the css file was requested. When this was the case i read the css file in memory and did a string replace before writing to the response.

I'm struggling to get this to work in .net core and i am wondering how i should implement something like the above?

Upvotes: 2

Views: 342

Answers (2)

Kevin
Kevin

Reputation: 267

I ended up writing a custom IFileProvider that returns a custom IFileInfo and when the css was served the file will be read and altered in the CreateStream() method.

This resulted in something like this:

public Stream CreateReadStream()
        {
            if (_text == null)
            {
                using (var scope = _container.BeginLifetimeScope())
                {
                    var tenantBrandingService = scope.Resolve<ITenantBrandingService>();
                    var settings = tenantBrandingService.Get();

                    using (var stream = _realFile.CreateReadStream())
                    {
                        using (var memoryStream = new MemoryStream())
                        {
                            stream.CopyTo(memoryStream);
                            _text = Encoding.UTF8.GetString(memoryStream.ToArray())
                            .Replace("##mainColor##", settings.MainColor)
                            .Replace("##mainColorText##", settings.MainColorText);                      
                        }
                    }
                }
            }
            return new MemoryStream(Encoding.UTF8.GetBytes(_text));
        }

I used the custom IFileProvider in the app.UseStaticFiles and in the app.UseSpa

Upvotes: 0

Bjego
Bjego

Reputation: 683

I wouldn't change it at runtime. I would setup an automated deployment process which updates your css file before deployment. You could use this plungin in Azure Devops (or TFS) :https://marketplace.visualstudio.com/items?itemName=qetza.replacetokens

But other CI-CD systems are able to do those kinds of tasks as well, maybe with some manual scripting..

But If you still want to update your css file during startup. I would update the program.cs

    public class Program
      {
        public static void Main(string[] args)
        {
         var myColors = new Dictionary<string,string>();
         try{
             var connectionString = Environment.GetEnvironmentVariable("CssDBConnection");
             //select values from DB into the dictionary
             myColors = GrabCssColorsFromDatabase(connectionString);
         }catch(Exception e){
            //use default css values in the dictionary
         }
         finally{
            InjectCss(myColors);
           BuildWebHost(args).Run();
         }

        }

It's similar to this workaround for Nlogs non Layout Targets: https://github.com/NLog/NLog/wiki/WebService-target---Workaround-for-url-variables

If you want to update it on the fly (no new Deployment). Provide an IActionResultEndpoint which returns the injected CssFile.

The Endpoint could be /Home/Styles And again:

  1. Grab Variables from Database, or fallback values
  2. Grab your "cssTemplate"
  3. Inject the variables
  4. Return the generated css file (as FileResult)
  5. You UI should grab the styles from this endpoint then instead of an file

Upvotes: 3

Related Questions