WebAPI Tip #1 and #2: HttpStatusCodes and Overriding Conneg

Thursday, March 21, 2013 by K. Scott Allen
4 comments

Henceforth we begin a series of tips and musings on the WebAPI.

Tip #1 – HttpStatusCode is an enum you can use to send specific status codes in a response. Going through the list, it is not always clear what name matches a value you are looking for, so here is a WebAPI controller to dump status codes into JSON.

public class StatusCodesController : ApiController
{
    public HttpResponseMessage Get()
    {
        var type = typeof(HttpStatusCode);
        var values =
            Enum.GetNames(type)                    
                .Select(name => new { name =name, value = (int)Enum.Parse(type, name) });

        var response = new HttpResponseMessage(HttpStatusCode.OK);
        response.Content = new ObjectContent(values.GetType(),
            values,
            Configuration.Formatters.JsonFormatter);

        return response;
    }
}

Tip #2 – The Request.CreateResponse extension method will use a content negotiation strategy to pick the best formatter for the response. In cases where you want to force a specific content type, use the approach in the above code. This example is forcing a JSON request by passing in the JsonFormatter to the ObjectContent ctor (because the XML formatter doesn't like anonymous types).

More to come...

A Quick Quiz using jQuery .data()

Monday, March 18, 2013 by K. Scott Allen
5 comments

Given this markup:

<div id="special" data-timeOut="3">
    
</div>

And this script code:

$(function() {
    var special = $("#special");
    var specialData = special.data();

    for (var p in specialData) {
        if (specialData.hasOwnProperty(p)) {
            special.text(p);
        }
    }
});

Answer the following questions:

Question #1

What output will appear when executing the code on Chrome or IE10?

a) timeOut

b) timeout

c)    (nothing)

d) ice cream

Question #2

What output will appear when executing the code on IE9?

a) timeOut

b) timeout

c)  (nothing)

d) yellow pencil

Let's change data-timeOut to data-time-out:

<div id="special" data-time-out="3">
    
</div>

Question #3

What output will appear when executing the code on IE 10, IE9, or Chrome?

a) timeOut

b) timeout

c)    (nothing)

d) whale teeth

Answers

1: B

2: C

3: A

Moral of the Quiz

Always use the data-some-name style, which gives you camel cased names in JavaScript (someName).

Never use camel case in the data- attribute itself.

RTFM, particularly the section titled "The algorithm for getting the list of name-value pairs".

Hacking Up A Glimpse Plugin

Friday, March 15, 2013 by K. Scott Allen
2 comments

Glimpse is highly extensible. If there is something you want to know about on the server, it's relatively easy to write a plugin that will feed data to the Glimpse dashboard. There is some documentation in the Glimpse GitHub wiki on writing an extension. This post provides a slightly more complex example to show how a Glimpse dashboard tab can interact with data collectors using a message broker.

The Scenario

Let's say you are adding additional IDisplayMode objects into the global ASP.NET MVC DisplayModeProvider. These display modes will select device specific views (an iPhone view, a Kindle Fire view, etc). Now, you want to look in the Glimpse dashboard to easily see what providers are registered, the order of evaluation, and which of the providers the runtime selected for a particular request.

The Filter

There are various extension points in ASP.NET MVC that will let you tap into the processing pipeline. Quite a bit of the core Glimpse.Mvc3 package relies on proxy objects that wrap runtime components (like the view engines) and feed data to Glimpse when interesting things happen (how a view is selected, for example). Once you find a way to tap into the runtime, feeding data to Glimpse is the easy part.

One way to tap into the runtime is to use a global filter (perhaps not the best approach, but it is simple for this demonstration). Here is a result filter that will find the current display mode being used and send the mode to Glimpse as part of a message.

public class GlimpseDisplayModeDump : IResultFilter
{
    private readonly IMessageBroker _broker;

    public GlimpseDisplayModeDump(IMessageBroker broker)
    {
        _broker = broker;
    }

    public void OnResultExecuting(ResultExecutingContext filterContext)
    {

    }

    public void OnResultExecuted(ResultExecutedContext filterContext)
    {
        var mode = filterContext.DisplayMode;
        if (_broker != null)
        {
            _broker.Publish(new DisplayModeMessage(mode));
        }
    }
}

The key to the Glimpse <-> IResultFilter interaction is the Glimpse message broker. The message broker allows us to publish messages of any type, and an interested party can subscribe to these messages and aggregate or summarize information from the messages. When the filter executes, it will look at the display mode for the request (passed by MVC as part of the filter context), and pass the mode as part of a message via the message broker.

The Message

The message itself is a simple object that encapsulates the display mode and provides a simple property to retrieve the name (ModeId) of the display mode.

public class DisplayModeMessage
{
    public DisplayModeMessage(IDisplayMode mode)
    {
        Mode = mode;
    }

    public IDisplayMode Mode { get; set; }

    public string ModeId
    {
        get { return Mode.GetName(); }
    }
}

In the above code, GetName is an extension method to compute the name of a display mode. In MVC, the IDisplayMode interface doesn't provide a lot of information, so we'll check to see if the object is actually a DefaultDisplayMode object.

public static class DisplayModeExtensions
{
    public static string GetName(this IDisplayMode mode)
    {
        var asDefault = mode as DefaultDisplayMode;
        if (asDefault != null)
        {
            if (!String.IsNullOrEmpty(asDefault.DisplayModeId))
            {
                return asDefault.DisplayModeId;
            }
            return "Default DefaultDisplayMode";
        }
        if(mode != null)
        {
            return mode.GetType().Name;    
        }
        return "None";
    }
}

The Tab

An object implementing the Glimpse ITab interface has a 1:1 correlation with tabs that appear in the client-side dashboard. It is the job of the tab to provide a name that appears in the dashboard, and to provide data to display in the tab when Glimpse is ready. Here's a tab to show the display mode data.

public class DisplayModeTab : TabBase, ITabSetup
{
    public void Setup(ITabSetupContext context)
    {
        GlobalFilters.Filters.Add(new GlimpseDisplayModeDump(context.MessageBroker));
        context.PersistMessages<DisplayModeMessage>();
    }

    public override object GetData(ITabContext context)
    {
        var result = new List<object[]>();
        var message = context.GetMessages<DisplayModeMessage>().FirstOrDefault();
        var id = message != null ? message.ModeId : "<none>";

        result.Add(new object[] { "Key", "Value" });
        result.Add(new object[] { "Selected Display Mode", id });
        result.Add(new object[] { "All Display Modes",                                 
                          DisplayModeProvider.Instance
                                             .Modes
                                             .Select(mode => mode.GetName()).ToArray()
                                });
        return result;
    }

    public override string Name
    {
        get { return "DisplayMode"; }
    }
}

The GetData method is the key to producing data for a request. In this sample the code will find the DisplayModeMessage for the request, as well as look at all of the registered display modes, and produce a loose collection of what is essentially key/value pairs of data for display. 

The Result

All of the above code can go directly into your MVC project, or into a separate assembly with a reference to Glimpe.Core (the preferred approach). Once the assembly is in the web app's bin directory, Glimpse will pick it up and start interacting with the tab to show data in the browser dashboard. More advanced formatting is possible, too.

image

AngularJS Interview on SSW TV

Thursday, March 14, 2013 by K. Scott Allen
0 comments

A few weeks ago I sat down (in a virtual sense) with Adam Stephensen of SSW. The result is a 20 minute video where we mostly talked about AngularJS. Adam is a great host and I enjoyed the interview immensely. If you want to check it out, click on the screen cap below:

 

image

AngularJS - Controllers, Dependencies, and Minification

Wednesday, March 13, 2013 by K. Scott Allen
3 comments

In working through a series of posts with AngularJS I've been using a controller function like so:

var VideoController = function($scope, Video) {
    // ... stuff 
};

The problem is that the function is in global scope. Some people will wonder what sort of sick mind creates a framework that forces developers to pollute the global scope.

Fortunately, you can register a controller constructor with angular.module instead. This is the same module API we used to create a resource service in a previous post.

angular.module("videoApp", ["videoService"])
       .controller("VideoController", function ($scope, Video) {

    // stuff ...
    
});

Not the prettiest syntax, unfortunately, but the controller constructor is out of the global scope and the world is a safer place. However, there is (and was) a problem lurking under the surface. Stay in suspense while we first look at dependencies in AngularJS.

Dependencies

Angular provides services that allow you to register dependencies and inject dependencies as function parameters. If you've worked with IoC containers in a language like C#, you'll be comfortable with the dependency injection in Angular. There is one significant difference, however. In languages like C# a container can examine a constructor method with reflection and find the types of the constructor parameters. Knowing that a constructor needs an ILogger or an IRepository will usually give a container enough information to figure out how to satisfy the dependency.

One of the many challenges for an IoC container in JavaScript is that method parameters and variables don't have an associated type. The question to think about is what to do with a function like the following, where $http represents a dependency to inject.

var ctor = function($http) {
    // stuff ...         
};

With no type information to go on, Angular relies on the next best thing, which is the name of the parameter. $http is the right name to use when you want Angular's built-in service that wraps an XmlHttpRequest object. The $http service offers communication methods  like get, post, put, delete, and jsonp. At test time you can pass in your own test double for the real $http service to avoid network calls in unit tests. Every service registered with Angular will have a specific name, like $http, $timeout (wraps setTimeout), and $location (wraps the address bar). You can register custom services, too.

Using well known names seems simple enough until you start thinking about how Angular actually discovers the parameter names. There is nothing built into JavaScript that will let you grab the names of a function's parameters. The answer is in the Angular source where you'll find a function named annotate, which relies on 4 regular expressions:

var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
var FN_ARG_SPLIT = /,/;
var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;

The annotate function will take a function object and invoke it's toString method to get the code for the function. It then strips out all the comments, parses out the function arguments as a string, and splits the string on the comma character. The result is an array with parameter names inside. Sounds crazy, but it works!

Now to the caveat.

Minification

One of the techniques a JavaScript minifier will use to reduce the amount of code sent to the client is to change the names of local variables and parameters to be as small as possible. A parameter named "$http" might come out of a minifier with the name "n" to save at least 4 bytes.

Once you know how dependency injection with Angular relies on parameter names, you'll realize a minifier can destroy Angular's ability to inject dependencies. Indeed, once you've minified a file you might see exceptions like the following:

Error: Unknown provider: nProvider <- n

The solution is to provide 'annotations' – an array that contains the names of the dependency a function needs, and the function itself.

angular.module("videoApp", ["videoService"])
       .controller("VideoController", ["$scope", "Video", function($scope, Video) {
    // ... stuff
}]);

A minifier won't change the $scope and Video string literals in the array, but it can change the function parameter names (and that's ok, because Angular will now look at the names in the array to resolve dependencies in the same order). In the previous samples (with a constructor function in the global scope), we could have also solved the problem by adding an $inject property to the function. Angular will look for an $inject property and use the names here instead of parsing the names out of the function definition.

VideoController.$inject = ['$scope', 'Video'];

Summary

Heavy stuff in the post, so just remember two things:

- You don't need to declare functions in the global scope to work with AngularJS. Many of the tutorials use this approach just to simplify the code.

- Think about the impact of minification from the start. Since most script files end up minified at some point, start describing your dependencies using the array approach (or $inject approach) from day 1. More details here.

Glimpse 1.0.1!

Tuesday, March 12, 2013 by K. Scott Allen
6 comments

Glimpse is the open source diagnostics platform of the web. You can use Glimpse to see what is happening inside a web application on both the server and client side. It's like Firebug but with configuration, routing, and profiling information from the server included. Nik and Anthony run the project, and they recently pushed out Glimpse v1.0.1.

To lean more, you can listen to a Herding Code episode, or watch a Channel 9 video.

Glimpse and ASP.NET MVC 4

The current version of Glimpse works well with ASP.NET MVC 4.

The first step is to install the Glimpse.MVC3 package using NuGet (yes, MVC3 will work with MVC4).

The second step is to use your web browser to visit /Glimpse.axd in your application and click the "Turn Glimpse On" button.

Turning On Glimpse

The last step is to visit any page in your application and click on the little Glimpse icon that will appear in the bottom right of the page. Clicking the icon opens up the Glimpse dashboard with server configuration, routing, profiling information, and other diagnostics showing in a tabbed interface.

Glimpse In Action

 

The direction and extensibility of the Glimpse project make Glimpse particularly exciting. There are very few restrictions on what Glimpse can't diagnose, so if there is a feature you'd like to see feel to jump in on the Glimpse GitHub project. I hope to cover some of the server-side extensibility points in a future post.

Enjoy!

DropDownListFor with ASP.NET MVC

Monday, March 11, 2013 by K. Scott Allen
6 comments

Building <select> tags generates a few questions and is something I've written about before (see Dropdown Lists and ASP.NET MVC). Here's a quick example to examine the scenario from different perspectives with the DropDownListFor HTML helper.

Let's say you have a class to represent different flavors of ice cream.

public class IceCreamFlavor
{
    public int Id { get; set; }
    public string Name { get; set; }
}

With DropDownListFor, you typically want a view model that will contain at least 2 properties:

- one property to hold a collection of SelectListItems to build the drop down

- one property to hold the value selected by a user

public class ViewModel
{
    private readonly List<IceCreamFlavor> _flavors;
    
    [Display(Name = "Favorite Flavor")]
    public int SelectedFlavorId { get; set; }
    
    public IEnumerable<SelectListItem> FlavorItems
    {
        get { return new SelectList(_flavors, "Id", "Name");}
    }
}

Assuming the _flavors field is populated with real ice cream flavors from a database or elsewhere, then the following Razor code:

@Html.LabelFor(m=>m.SelectedFlavorId)
@Html.DropDownListFor(m => m.SelectedFlavorId, Model.FlavorItems)
@Html.ValidationMessageFor(m=>m.SelectedFlavorId)
<input type="submit" value="Submit" />                           

.. will give you this in a browser:

DropDownListFor

Do I Have To Use String Literals?

The constructor for a SelectList wants you to identify the data field and text field using strings ("Id" and "Name"). If you want strong typing, use LINQ to project ice cream flavors into SelectListItems.

public IEnumerable<SelectListItem> FlavorItems
{            
    get
    {
        var allFlavors = _flavors.Select(f => new SelectListItem
                                               {
                                                   Value = f.Id.ToString(),
                                                   Text = f.Name           
                                              });
        return allFlavors;
        
    }
}

What About Adding A "Select A Flavor" Entry?

Perhaps you want to prepend a "Select Something Here" item into the option list for the drop down.

public IEnumerable<SelectListItem> FlavorItems
{            
    get
    {
        var allFlavors = _flavors.Select(f => new SelectListItem
                                               {
                                                   Value = f.Id.ToString(),
                                                   Text = f.Name                
                                              });
        return DefaultFlavorItem.Concat(allFlavors);                
    }
}

public IEnumerable<SelectListItem> DefaultFlavorItem
{
    get { return Enumerable.Repeat(new SelectListItem
                                       {
                                           Value = "-1", Text = "Select a flavor"
                                       }, count: 1); }
}

Select a Flavor

How Did It Remember That?

Something you might notice if validation fails is that the drop down list seems to remember the last value selected without you doing any extra work.

In other words, if the user selects "Chocolate" and clicks Submit to post the form to the server, your controller might detect a validation error and re-render the form with validation messages. The drop down list will also re-build the <select> from scratch, but somehow "Choclate" is selected instead of "Select A Flavor". You'll see this behavior because DropDownListFor will peek in ModelState to see the last value for SelectedFlavorId, and build the drop down list with the last selected flavor marked as selected. It's the same magic Web Form programmers see with ViewState.

Hope that helps!

Follow Me On Twitter
RSS Subscribe
Contact
Search Archives
by K. Scott Allen
K.Scott Allen