DotLessResult – MVC ActionResult for dotless

I’ve recently had the need to generate dynamic css for a themable MVC web application. I considered using a basic homegrown templating mechanism, or repurposing Razor, but then found the dotless project on the interwebs.

With the NuGet package it was relatively easy to get up & running, and I’ve abstracted the clunky regex code into an ActionResult subclass, recorded here in case it’s useful for somebody else.

    public class DotLessResult : ActionResult
    {
        public IDictionary<string, string> Parameters { get; set;}
        public string Less { get; set; }
        public bool Minify { get; set; }

        public DotLessResult(string less, IDictionary<string, string> parameters = null, bool minify = false)
        {
            Less = less;
            Parameters = parameters ?? new Dictionary<string, string>();
            Minify = minify;
        }
        
        public DotLessResult(Stream stream, IDictionary<string, string> parameters = null, bool minify = false)
            : this(new StreamReader(stream).ReadToEnd(), parameters, minify) { }

        public override void ExecuteResult(ControllerContext context)
        {
            var output = Less;
            foreach (var key in Parameters.Keys)
            {
                output = Regex.Replace(output, @"\s*@" + key + @":\s*\S+;", "@" + key + ":" + Parameters[key] + ";");
            }
            var css = dotless.Core.Less.Parse(output, new DotlessConfiguration { MinifyOutput = Minify });
            context.HttpContext.Response.ContentType = "text/css";
            using (var writer = new StreamWriter(context.HttpContext.Response.OutputStream, Encoding.UTF8)) {
                writer.Write(css);
                writer.Flush();
            }
        }
    }

This can then be used from your action method like so:

        public ActionResult Styles(string id)
        {
            var stream = GetType().Assembly.GetManifestResourceStream(stylePath + id.Replace(".css", ".less"));
            if (stream == null)
            {
                return HttpNotFound();
            }
            Dictionary<string, string> parameters = new Dictionary<string, string>();
            parameters["backgroundcolor"] = "#1f1400"; // continue for all replaceable parameters
            return new DotLessResult(stream, parameters, true);
        }

The .less source should be stored in your web assembly as an embedded resource, with configurable parameters declared using the syntax “@: <placeholderValue;". Then it's just a case of looping through the supplied parameters dictionary and changing the declaration in the .less source. In the example code here I’m looking for a .less resource with the same name as the requested .css file, but you can obviously use your imagination.

Advertisements

Google Analytics Razor Helper

I experimented today with the Razor helper syntax to consolidate generation of the Google Analytics tracking boilerplate (in ~/App_Code/Helpers.cshtml):

@helper GoogleAnalyticsTracker(string analyticsId) 
{
   if (!String.IsNullOrEmpty(analyticsId))
   {
   <script type="text/javascript">
            var _gaq = _gaq || [];
            _gaq.push(['_setAccount', '@analyticsId']);
            _gaq.push(['_trackPageview']);

            (function () {
                var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
                ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
                var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
            })();
    </script>
    }
}

which can then be used in your layout pages with:

@Helpers.GoogleAnalyticsTracker(Model.GoogleAnalyticsId)

It’s a bit unclear where this mechanism should fit between custom HtmlHelper extension methods and Razor partial views. I guess you’d be looking for functionality that’s less generic than an HtmlHelper extension – you can modify without recompiling, and it’s less simple to share between projects – and smaller/more generic than a partial.

The App_Code requirement for sharing between pages is not ideal, particularly as HtmlHelper extension methods aren’t available without workarounds. Hopefully the team get an update out in a reasonably timeframe.

Technical Interviews

I’ve recently been doing a few technical interviews with candidates for software developer positions. I haven’t done any in a long time and I’d assumed I’d go back and trot out some of the old technical ‘trivia’ questions (“In .NET, is a string a value type or a reference type?” etc). Alternatively, perhaps I’d get organised and do some whiteboard code problems like Joel suggests — however, I came across a rebuttal from John DeRosa that convinced me this approach isn’t all it’s cracked up to be.

Aaron Swartz suggests you’re only trying to answer three questions in a job interview:

  1. Have they done this job in the past?
  2. Are they smart?
  3. Could I work with them?

I would opine those are in increasing order of importance: experience is easy to gain, skills can be improved up to a limit, but if someone’s a tosser they’re probably always going to be a tosser.

The questions I found I ended up being more useful were the ones along the lines of:

  • “What would you have done differently in your last project if you had the chance to do it again/were in charge?”
  • “What is your favourite programming language? What do you like about it? Is there anything you would change about it?”
  • “What level of documentation do you think is appropriate for a typical software project?”
  • “What tools do you think are important for software teams?”
  • “Do you like beer?”

The goal is to get the candidate talking about him/herself and have more of a conversational interaction with them. It’s easy to embellish a job history, but much more difficult to give a plausible retrospective analysis of your role on a fictitious project, so question 1 is covered by going over recent work the candidate has done. Question 2 is fairly easy to pick up on during a bit of to & fro — challenging one or two statements they make gives you a good feel for whether they’re parroting conventional wisdom or they’ve acquired a good understanding of the subject. It’s also always a good idea to teach them something and see whether they internalise or dismiss it, as per one of Aaron’s suggestions.

Lastly, a conversation is the only way you’re going to be able to assess the answer to question 3. This is obviously a subjective call, but you know yourself & your team and you should get a good feel over 60-90 minutes as to whether they’ll fit into the team. I can’t stress enough how much more important cultural fit is than any other consideration. Software development is a team sport.