views:

98

answers:

2

I'm looking to add some basic theme support to my web application, with users being able to customise various parts of the look. These include things like colours, text sizes, fonts, other basic things. I will be storing these in the database and loading them each time a page is accessed.

My question is, how do I go about generating a dynamic CSS file based upon these database values?

I would prefer to do something that is cache-able, but extensible so that if I want to add more editable styles then it wouldn't be a bit issue.

+7  A: 

I think the simplest way would be to add something like the following action method to a controller:

public class CssController : Controller {
    public ActionResult GetCss() {
        StringBuilder sb = new StringBuilder();
        Dictionary<string, string> cssValues = new Dictionary<string, string>();
        // populate dictionary with values from your database
        sb.AppendLine(".myDivClass {");
        foreach (var entry in cssValues) {
            sb.AppendLine(entry.Key + ": " + entry.Value);
        }
        sb.AppendLine("}");
        return Content(sb.ToString(), "text/css");
    }
}

Now in your page you can reference it like so:

<link href="<%: Url.RouteUrl(new { controller=  "CssController", action = "GetCss" }) %>" rel="stylesheet" type="text/css" />

OP EDIT: I made some small changes to the method, but the general premise remains. This is the version I used:

public class CssController : Controller
{
    public ContentResult GetTheme()
    {
        var builder = new StringBuilder();
        IDictionary<string, IDictionary<string, string>> css = new Dictionary<string, IDictionary<string, string>>();

        /* Populate css object from the database */

        foreach (var selector in css)
        {
            builder.Append(selector.Key);
            builder.Append(" { ");
            foreach (var entry in selector.Value)
            {
                builder.Append(string.Format("{0}: {1}; ", entry.Key, entry.Value));
            }
            builder.AppendLine("}");
        }

        return Content(builder.ToString(), "text/css");
    }
}
marcind
awesome! I'll give it a go!
Alastair Pitts
I took your idea and just made it a bit more generic. Also you were missing the `;` from the end of the entry. Thanks a bunch for your answer, it was really really helpful.
Alastair Pitts
Ah good point, forgot about that.
marcind
A: 

Alastair - do you mind posting your more generic solution?

Thanks,

Rick

rboarman
@rboarman: Have a look at the second code block in the accepted answer. That was the generic version I used/wrote.
Alastair Pitts