3

I have a problem I'm struggling with. Some background: Users can in my application choose which color scheme for the app to use, this choice is stored in a database.

What I want to do is based on this choice, on page load, serve the CSS file for the choice the user made.

What I've been trying to do is check the users choice by doing an AJAX request in the _Layout.cshtml page, appending the appropriate CSS to the header. This is working but not great, since there is some delay and it just not a good solution since at times some styling for elements are not correct after the CSS has been loaded.

What I would like to do is to do this check server-side, like for a normal view in the controller (Layout pages lacks controllers as you know so this is where I'm stuck). And then in the _Layout view add the correct CSS.

So dear stack overflowers, do you have any suggestions for me how this could be achieved? My users need that sweet sweet dark theme. ;)

Thanks in advance!

4
  • Yeah, that's what I would do for a normal view connected to a Controller, but since a Layout view lacks a Controller I'm not sure if this is possible to do? Commented Jun 15, 2018 at 14:48
  • It is like MVC5 in that regard AFAIK. The layout's "controller" is actually the controller-action for the view that is using the layout. Commented Jun 15, 2018 at 14:52
  • But this is .net CORE ! Which means you can actually inject models inside your views ... AND inside your _Layout. This might be the right moment to use this functionality. You can also make use of html tag helpers or components to get a cleaner syntax instead of using these dirty if i'm suggesting ... (netcore 2 is awesome, go use it right now !) Commented Jun 15, 2018 at 14:54
  • Thank you very much Wndrr, you and a user over at the C# discord channel both suggested this so I implemented it and it's working great. Since Christian wrote an answer below explaining how I did it I will mark his post as the accepted answer, but you both sent me in the right direction and I thank you for that! :) Commented Jun 15, 2018 at 15:39

2 Answers 2

5

Create a service

public class ThemeService
{
    private readonly MyDbContext  _dbContext;
    private readonly IMemoryCache _memoryCache;

    public ThemeService(MyDbContext dbContext, IMemoryCache memoryCache)
    {
        //Here you can also inject the UserManager<T> if needed
        _dbContext = dbContext;
        _memoryCache = memoryCache;
    }

    public string GetTheme()
    {
        throw new NotImplementedException();
    }
}

And register it to the service container scoped (Since you need the DbContext):

services.AddScoped<ThemeService, ThemeService>();

And in you view, just inject it

@inject ThemeService ThemeService;

And later in the view:

<link type="text/css" href="@ThemeService.GetTheme()" />
Sign up to request clarification or add additional context in comments.

6 Comments

I just came back to write a post about how I solved it but no need anymore, you wrote it for me haha. Got sent in this direction by the user "shadow_kras" over at the Discord C# channel and also by @Wndrr here on SO. Thank you very much, this was exactly what I was looking for, and I can now do the same for some other things I want to add to my Layout view. Excellent answer! :)
@christian Gollhardt thank you for your answer it helped me alot, i am wondering if my service is Async when i add i call it from the layout its now working. any idea on how i can solve this. Thanks again
Do you await them @wandos?
@ChristianGollhardt i tried to but it didnt work, @{await ThemeService.GetTheme(); } didnt work
I have no IDE here, but isn't the correct syntax @await ThemeService.GetThemeAsync() @wandos
|
2

If you simply have a "dark" and "light" theme why not store a bool in the database storing the user's choice and then, in the view's _Layout, do something like this

@if(ViewBag.IsLightTheme)
{
    <link rel="stylesheet"  type="text/css" href="path.to.light.theme" />
}

else
{
    <link rel="stylesheet"  type="text/css" href="path.to.dark.theme" />
}

In the constructor of your controller you would need to assign the value coming from the database to your ViewBag.IsLightTheme var (you might want to use some form of caching there, since this will be called on every single page).

In case you don't just have two themes, you can use a more elaborate way of choosing which href to write based on a switch or something of this sort.

The other option would be to alway use the same URL for your CSS which would actually point to the action of one of your controllers that would execute the call to the database and return a different CSS based on the answer using return Content().

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.