h3mm3's blog

Stories from behind the keyboard

  • RSS
  • Twitter
Showing posts with label MVC. Show all posts
Showing posts with label MVC. Show all posts

Summary

When I customize a web site template, I always replace the color palette looking for a consistent set of colors. In this series I’ll tell how I managed to speed up the whole process, by building a set of Razor functions and push the Razor syntax inside a CSS stylesheet.

In PART ONE we saw how to create a gradient programmatically in order automate a CSS stylesheet using the Razor engine. We started from a base color in the RGB space and converted it to the HSL space. Given its Lightness we could easily build shades and highlights of the starting color.

Let’s agree on some convention

  • RGB : The space where color are defined by their Red, Green and Blue channels. Both R,G and B ranges from 0 to 255
  • HSL: The space where color are defined by their Hue, Saturation and Lightness. Hue ranges in [0,360), Saturation in [0,240], Lightness in [0,240]
  • Hsb: A transform of the HSL space where s is a normalized Saturation and b (brightness, as Microsoft called it) is a normalized Lightness. H is the same Hue of the HSL space.
  • I use lower case for normalized coordinates, UPPER CASE for classic coordinates.

Traveling back to the RGB space

From the HSL representetion of a color we can build a gradient just varying its Lightness. For instance, starting from Blue (H = 240, S = 240, L=120) we can go DarkBlue (L=65) in the shadows, or light blue (say L=160) in the highlighs. In order to get their HTML codes, we have to convert their HSL coordinates to RGB. A useful method written by Oliver in a Stackoverflow thread builds a System.Drawing.Color from αHsb coordinates (α is the opacity of the color, we can stick it to 255). Here comes his method:

/// 
/// Creates a Color from alpha, hue, saturation and brightness.
/// 
/// The alpha channel value.
/// The hue value.
/// The saturation value.
/// The brightness value.
/// A Color with the given values.
public static Color FromAhsb(int alpha, float hue, float saturation, float brightness)
{
    if (0 > alpha
        || 255 < alpha)
    {
        throw new ArgumentOutOfRangeException(
            "alpha",
            alpha,
            "Value must be within a range of 0 - 255.");
    }

    if (0f > hue
        || 360f < hue)
    {
        throw new ArgumentOutOfRangeException(
            "hue",
            hue,
            "Value must be within a range of 0 - 360.");
    }

    if (0f > saturation
        || 1f < saturation)
    {
        throw new ArgumentOutOfRangeException(
            "saturation",
            saturation,
            "Value must be within a range of 0 - 1.");
    }

    if (0f > brightness
        || 1f < brightness)
    {
        throw new ArgumentOutOfRangeException(
            "brightness",
            brightness,
            "Value must be within a range of 0 - 1.");
    }

    if (0 == saturation)
    {
        return Color.FromArgb(
                            alpha,
                            Convert.ToInt32(brightness * 255),
                            Convert.ToInt32(brightness * 255),
                            Convert.ToInt32(brightness * 255));
    }

    float fMax, fMid, fMin;
    int iSextant, iMax, iMid, iMin;

    if (0.5 < brightness)
    {
        fMax = brightness - (brightness * saturation) + saturation;
        fMin = brightness + (brightness * saturation) - saturation;
    }
    else
    {
        fMax = brightness + (brightness * saturation);
        fMin = brightness - (brightness * saturation);
    }

    iSextant = (int)Math.Floor(hue / 60f);
    if (300f <= hue)
    {
        hue -= 360f;
    }

    hue /= 60f;
    hue -= 2f * (float)Math.Floor(((iSextant + 1f) % 6f) / 2f);
    if (0 == iSextant % 2)
    {
        fMid = (hue * (fMax - fMin)) + fMin;
    }
    else
    {
        fMid = fMin - (hue * (fMax - fMin));
    }

    iMax = Convert.ToInt32(fMax * 255);
    iMid = Convert.ToInt32(fMid * 255);
    iMin = Convert.ToInt32(fMin * 255);

    switch (iSextant)
    {
        case 1:
            return Color.FromArgb(alpha, iMid, iMax, iMin);
        case 2:
            return Color.FromArgb(alpha, iMin, iMax, iMid);
        case 3:
            return Color.FromArgb(alpha, iMin, iMid, iMax);
        case 4:
            return Color.FromArgb(alpha, iMid, iMin, iMax);
        case 5:
            return Color.FromArgb(alpha, iMax, iMin, iMid);
        default:
            return Color.FromArgb(alpha, iMax, iMid, iMin);
    }
}

Oliver’s method sticks to Microsoft naming convention, where “Brightness” is actually a value in the “Lightness” dimensions and ranges from 0 to 1. “Saturation” is normalized in [0,1] too. “Hue” ranges from 0 to 360.

All in all, FromAhsb(α,H,s,b) is the Transformation function we need to convert a color from HSL to RGB (is our metaphorical star gate back to the RGB space, if you remember the travel took in PART ONE).

From System.Drawing.Color to HTML coding

Getting the HTML code of a System.Drawing.Color is easy as calling this method:

var blue = System.Drawing.Color.Blue;
var blueHtml = System.Drawing.ColorTranslator.ToHtml(blue);

So all we have to do at this time is to put all this stuff together and maybe spice the recipe with a bunch of handy color transformation functions.

Towards a dynamic CSS

At this point we know how to start from an RGB color and build a number of gradations. To use these colors in an ASP.NET MVC project we have to inject their HTML codes into the Site.css style sheet. We don’t want to hard code them, since we aim to build a dynamic template, based on some parameter. For instance, the following Razor code builds a palette of five color swatches:

@{
  var basecolor = "#960000";
  var bg = basecolor.Brightness(0.4f); 
  var fg = "black";
  var menu_bg = basecolor.Delta(brightness:0.5f);
  var anchor_fg = basecolor.Brightness(0.15f); 
}

Starting from any base color, I build a background color setting its brightness to 0.4 (that’s a Luminosity of 0.4x240 = 96). The foreground color is black. The other two color swatches are based from the basecolor too.

Delta(..) and Brightness(..) are two handy extension methods that increment any dimension of an Hsb color or set its brightness component to a chosen value; they return the HTML code of the built color for our convenience.

Our dynamic CSS can be a “razor’d” version of the default Stile.css file. Just rename it to Stile.cshtml and write something like this:

/*----------------------------------------------------------
@using MyColorHelpers;
@{    
    var basecolor = "#960000";
    var bg = basecolor.Brightness(0.4f); 
    var fg = "black";
    var menubg = basecolor.Delta(brightness:0.5f);
    var afg = basecolor.Brightness(0.15f); 
}
Date: @DateTime.Now

The base color for this template is @basecolor. If you'd like
to use a different color start by replacing all instances of
@basecolor with your new color.
----------------------------------------------------------*/
body {
    background-color: @bg;
    font-size: .85em;
    font-family: "Trebuchet MS", Verdana, Helvetica, Sans-Serif;
    margin: 0;
    padding: 0;
    color: @fg;
}
/* [...] */

As you can see, Razor syntax and a couple of extension methods is all we need to have a dynamic CSS.

In the following post we will put all this stuff together; happy programming and stay tuned!

Summary

When I customize a web site template, I always replace the color palette looking for a consistent set of colors. In this series I’ll tell how I managed to speed up the whole process, by building a set of Razor functions and push the Razor syntax inside a CSS stylesheet.

PS: We won’t use LESS.

Refreshing a pre-cooked template

One of the tasks I have to accomplish anytime I start a new web project is how to design the interface and chose consistent colors. Nonetheless, especially for little projects or back-office web sites, what I need mostly is to customize the default web site template that comes with Visual Studio ASP.NET MVC3 projects.

The process of customization is basically a combination of two tasks: customizing the color palette and defining a new layout; if you are using the default ASP.NET MVC3 template, those tasks implicate the manipulation of a couple of files: “/Content/Site.css” and “/Views/Shared/_Layout.cshtml”.

As you can see running you project (or reading the Site.css code):

/*----------------------------------------------------------
The base color for this template is #5c87b2. If you'd like
to use a different color start by replacing all instances of
#5c87b2 with your new color.
----------------------------------------------------------*/

image

Unfortunately replacing the base color (#5c87b2)doesn’t suffice, since quite all the elements of the page are tuned with it, providing a consistent look. What you should really do is chose a new base color and build a set of harmonious colors based on it.

A starship travel

It is probable that the simplest way to build a consistent color palette is to chose a base color and then stretch a gradient around it, both towards shadows and highlights.

image

Each color is defined in the RGB space by a triplet of integer numbers ranging from 0 to 255, known as Red, Green and Blue channels. This is a convenient way to think a color, since it is the nearest to how our eyes-brain system perceives lights and how electrical devices create colored light (just think about CRT and LCD displays). But if have to build shadowed or highlighted version of a color, you cannot start from its RGB representation. A more useful starting point is to convert the RGB triplet into an HSL triplet (that is similar to take a starship and travel from the RGB universe to the HSL universe. In this case, the black hole that let out starship change universe is a transformation function),

The HSL acronym stands for Hue, Saturation and Lightness (of course you can find more info here). In this space, the Lightness is all we want to change (zero means absence of light, that’s to say BLACK, maximum value means maximum light, that’s to say WHITE). Any color with a minimum amount of light is defined by the two other coordinates: Hue and Saturation.

Talking about Microsoft .Net and C#, you can easily travel to the HSL space, but System.Drawing can only sell you a  one-way ticket: you can extract Hue, Saturation and Lightness from a System.Color but you cannot build a System.Color from an HSL triplet.

Confusing enough, you extract a Hue via Color.GetHue() method, Saturation via Color.GetSaturation() method, BUT Lightness via Color.GetBrightness(). Basito

Moreover, GetHue() ranges between 0 and 360 (degrees),  but GetSaturation() and GetBrightness() range from 0 and 1 (ok, we can live with it.. just multiply them by, say, a 240 scale value to get handy integer values to deal with).

The following LINQpad snippet lets you travel to the HSL space at light speed!

var colors = from n in new[]{"Red","Green","Blue","White","Black","DarkBlue"}
    let c = Color.FromName(n)
    select new {
     c.Name,
     c.R, c.G, c.B,
     H = (int)c.GetHue(),
     S = (int)(240*c.GetSaturation()),
     L = (int)(240*c.GetBrightness())

colors.Dump();

This is the result:

image

In order to automate the creation of a nice gradient, we need to:

  • Get the HSL of our base color
  • Vary the Lightness value towards shadows or highlights (easy like adding or subtracting a number)
  • Build the RGB triplet from the rendered HSB color.

As we have seen, Step 1 is provided courtesy by Microsoft and Step 2 is simple math. But Step 3 means traveling back to the RGB space, and Microsoft starship doesn’t fly there.

In my next post I’ll tell how to find a star gate back to the RGB space and build a convenient set of Razor C# functions to easily manipulate all this colored stuff. Finally we will integrate this rocket science technology to the CSS language, building a system similar to LESS (but LESS-less) Occhiolino

Happy programming and stay tuned!

..or go to Part 2.

Or, how to enable ASP.NET MVC2 to handle pseudo-file requests under IIS6

Recently I installed an ASP.NET MVC2 web application on a Windows 2003 Server, running IIS6. The Framework 4 was correctly configured, and the application ran flawlessly except when the browser requested URL’s that matched to the following route: “~/Get/{guid}.{ext}”.

Such requests are handled by the Get() method of the FileController class. The method is roughly defined like this:

public ActionResult Get(Guid guid, string ext)
{ 
   //...
   return File( ... ); 
}

In short, the method is meant to serve graphics and other resources to the client (via a FileStreamResult), and hides the details about the actual storage system.

The problem with IIS6 was that when it received a GET request such
"http://domain/get/3F2504E0-4F89-11D3-9A0C-0305E82C3301.png"
it simply looked for an hypothetical (and unexisting) folder “/Get” under the web app root, and returned a HTTP error.

It turned out the problem was IIS6 trying to resolve the URL prior to pass the ASP.Net engine the request. Luckily enough, IIS6 web application configuration panel lets you define additional application maps, in order to redirect a request to the proper handler, based on the file extension of the requested file (in my case … *any* extension).

So I decided to bypass IIS6 totally and I added the .Net Framework 4.0 ISAPI filter (aspnet_isapi.dll) to the “wildcard application maps” section of the web application configuration dialog (see picture below). This setting saved my day!

Setting "aspnet_isapi.dll" as a wildcard application map

Happy programming!

If you want to use HtmlHelper.ActionLink(..) extension method to produce something like a clickable image, you could get into trouble. In effect, the “linkText” string passed to HtmlHelper.ActionLink is automatically HTML-encoded by the helper method before producing the desired anchor element. So it seems somewhat impossible to make this sort of invocation work:

<%= Html.ActionLink(
"<img src='myImage.png'/>",
'TheAction', ...) %>
My solution to this problem was to write an extension method like this one:
public static string ActionLinkEx(
  this HtmlHelper h, string htmlLinkText,
  string actionName, string controllerName,
  object routeValues, object htmlAttributes)
{
  var builtCode = h.ActionLink(
    "*",actionName, controllerName,
    routeValues, htmlAttributes);
  return builtCode.Replace("*",htmlLinkText);
}
The method just wraps the standard HtmlHelper.ActionLink(..). This one prepares an HTML text made by a clickable asterisk (*) linking to the desired action method. Then my helper method replaces the text of the link (the asterisk) with the desired HTML code (passed using the htmlLinkText input parameter).