locked
Theme system and injecting the theme name to layout file? RRS feed

  • Question

  • User-183185495 posted

    I am storing the name of my theme in the configuration Appsettings Table which is derived from the Iconfiguration service.

    My question is how does one get this value 

    context.Values.TryGetValue(Constants.ThemeConfigKey, out string theme);

    Which I am storing here 

    var config = context.ActionContext.HttpContext.RequestServices.GetService<IConfiguration>();
    context.Values[Constants.ThemeConfigKey] = config["Theme"];
    

    To My Layout file here at present the themes are uploaded by customer so I need to replace the _content with the theme name from the config value that am holding in the headers.

    <link rel="stylesheet" cella-append-version="false" href="~/_content/vendor/bootstrap/css/bootstrap.min.css">
        <link rel="stylesheet" cella-append-version="false" href="~/_content/vendor/owl-carousel/assets/owl.carousel.min.css">
    

    Am using a tag helper at present to do this as follows But this involes me having to add it to every line including images to achieve this is their an easier way using javascript or jquery to achieve this.

    using Microsoft.AspNetCore.Razor.TagHelpers;
    using Microsoft.Extensions.Configuration;
    using Cella.Domain;
    
    namespace Cella.BL.TagHelpers
    {
        [HtmlTargetElement(Attributes = AppendVersionAttributeName)]
        public class AppendVersionTagHelper : TagHelper
        {
            private const string AppendVersionAttributeName = "cella-append-version";
            private readonly IConfiguration _config;
    
            public AppendVersionTagHelper(IConfiguration config)
            {
                _config = config;
            }
    
            [HtmlAttributeName(AppendVersionAttributeName)]
            public bool AppendVersion { get; set; }
    
            public override int Order => int.MinValue;
    
            public override void Process(TagHelperContext context, TagHelperOutput output)
            {
                output.Attributes.RemoveAll(AppendVersionAttributeName);
    
                if (!AppendVersion)
                {
    
    
                    if (output.Attributes.ContainsName("href"))
                    {
                        var href = output.Attributes["href"].Value.ToString();
                        output.Attributes.SetAttribute("href", AppendVersionToUrl(href));
                    }
                }
    
                if (!AppendVersion)
                {
                    if (output.Attributes.ContainsName("src"))
                    {
                        var src = output.Attributes["src"].Value.ToString();
    
                        output.Attributes.SetAttribute("src", AppendVersionToUrl(src));
                    }
                }
    
                if (output.Attributes.ContainsName("href"))
                {
                    var href = output.Attributes["href"].Value.ToString();
                    output.Attributes.SetAttribute("href", AppendThemeNameToUrl(href));
                }
                if (output.Attributes.ContainsName("src"))
                {
                    var src = output.Attributes["src"].Value.ToString();
                    var replace = AppendThemeNameToUrl(src);
                    output.Attributes.SetAttribute("src", replace);
                }
                if (output.Attributes.ContainsName("xlink:href"))
                {
                    var src = output.Attributes["xlink:href"].Value.ToString();
                    var replace = AppDomainNameToImage(src);
                    output.Attributes.SetAttribute("xlink:href", replace);
                }
            }
    
            private string AppDomainNameToImage(string url)
            {
                if (string.IsNullOrWhiteSpace(url))
                {
                    return string.Empty;
                }
    
                var theme = Constants.DomainName + @"/" + _config[Constants.ThemFolderNameConfigKey] + @"/" + _config["Theme"];
            
                url = url.Replace("_DomainName", theme);
    
                return url;
            }
            private string AppendThemeNameToUrl(string url)
            {
                if (string.IsNullOrWhiteSpace(url))
                {
                    return string.Empty;
                }
    
                var theme = _config[Constants.ThemFolderNameConfigKey] + @"/"+ _config["Theme"];
                url = url.Replace("_content", theme);
    
                return url;
            }
            private string AppendVersionToUrl(string url)
            {
                if (string.IsNullOrWhiteSpace(url))
                {
                    return string.Empty;
                }
    
                var version = _config["Global.AssetVersion"];
    
                return url.Contains("?") ? $"{url}&v={version}" : $"{url}?v={version}";
            }
        }
    }

    Thursday, May 27, 2021 8:45 PM

All replies

  • User475983607 posted

    Just use standard Razor syntax in the layout to generate whatever path you like.  Is this an ASP.NET Core application???

    Thursday, May 27, 2021 9:27 PM
  • User-183185495 posted

    I tried that I guess what am getting at is their a performance hit for doing it that way would it not be better via some jquery or something?

    Also I want people to avoid having to do this in their custom themes hence looking more for a replace method ?

    mgebhard

    Just use standard Razor syntax in the layout to generate whatever path you like.  Is this an ASP.NET Core application???

    Thursday, May 27, 2021 9:49 PM
  • User475983607 posted

    roguenidb

    I tried that I guess what am getting at is their a performance hit for doing it that way would it not be better via some jquery or something?

    Yeah, that does not sound correct.  Configuration key/values are in memory.  I would think jQuery would be much slower.  Do you have code to review?

    roguenidb

    Also I want people to avoid having to do this in their custom themes hence looking more for a replace method ?

    I do not understand the point you are trying to make.  The values are not stored in configuration???

    Is this an ASP.NET Core question in the wrong support forum???

    Thursday, May 27, 2021 10:03 PM
  • User-183185495 posted

    I am using a EFConfigProvider source and a key value storage system  I persume that will be only loaded at startup what if the user changes a setting will i have to recycle the pool i gather.

    Also what is best way for me to make this strongly typed

    What am trying to achieve is minmal changes that the customer needs to make to the theme working I guess using configuration is minmal enough

        public class EFConfigProvider : ConfigurationProvider
        {
            private Action<DbContextOptionsBuilder> OptionsAction { get; }
    
            public EFConfigProvider(Action<DbContextOptionsBuilder> optionsAction)
            {
                OptionsAction = optionsAction;
            }
    
            public override void Load()
            {
                var builder = new DbContextOptionsBuilder<CellaDBContext>();
                OptionsAction(builder);
    
                using (var dbContext = new CellaDBContext(builder.Options))
                {
                    dbContext.Database.EnsureCreated();
                    Data = !dbContext.Appsettings.Any()
                        ? CreateAndSaveDefaultValues(dbContext)
                        : dbContext.Appsettings.ToDictionary(c => c.Key, c => c.Value);
                }
            }
    
            private static IDictionary<string, string> CreateAndSaveDefaultValues(CellaDBContext dbContext)
            {
                var configValues =
                    new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
                    {            
                    { "Theme", "FrontEnd" },
                    { "AdminTheme", "Default" },
                        { "ApiSecret","not real"},
                        {"Global.AssetVersion","1.0" },
                        {"Global.CatalogOnly" ,"true"},
                        {"Global.CurrencyCulture" ,"en-US"},
                        {"Global.CurrencyDecimalPlace" ,"2"},
                        {"Global.DefaultCultureUI" ,"en-US"},
                        {"ThemesFolderName" ,"Themes"},
    
                        
                    };
                dbContext.Appsettings.AddRange(configValues
                    .Select(kvp => new AppSettings
                    {
                        Key = kvp.Key,
                        Value = kvp.Value
                    })
                    .ToArray());
                dbContext.SaveChanges();
                return configValues;
            }
        }
    }
    

    I am configuring it here.

    ar host = CreateHostBuilder(args)
                    .ConfigureAppConfiguration((hostingContext, configBuilder) =>
                    {
                        var config = configBuilder.Build();
                        var configSource = new EFConfigSource(opts =>
                            opts.UseSqlServer(config.GetConnectionString("DefaultConnection")));
                        configBuilder.Add(configSource);
                    }).Build();
    

    mgebhard

    roguenidb

    I tried that I guess what am getting at is their a performance hit for doing it that way would it not be better via some jquery or something?

    Yeah, that does not sound correct.  Configuration key/values are in memory.  I would think jQuery would be much slower.  Do you have code to review?

    roguenidb

    Also I want people to avoid having to do this in their custom themes hence looking more for a replace method ?

    I do not understand the point you are trying to make.  The values are not stored in configuration???

    Thursday, May 27, 2021 10:08 PM
  • User287926715 posted

    Hi  roguenidb,

    Perhaps you can also use the ABP framework which is easier to maintain. It provides a complete UI theme system, and reusable application modules are developed independently of the theme, so they can be used with any UI theme. You can refer to this document to use.

    ASP.NET Core MVC / Razor Pages: UI Theming

    Best Regards,

    ChaoDeng

    Thursday, June 10, 2021 9:09 AM