Trip Recorder Using JavaScript’s Geolocation API and Google Maps

I recently saw Ben Nadel’s blog post that did a great job of introducing the built in browser support for geolocation. I have been meaning to write an iPhone client to collect and save GPS data as part of the Truck Tracker project. However, this browser-based location services have the advantage that I can write on web-client and it can be used on any browser that supports the API. This post will explore creating a stand-alone (no integration with Truck Tracker) prototype.

Below is a link to the demo page. The demo application is contained in a single file (all the CSS, JavaScript and HTML) to help facilitate ‘view source’ investigation. This page is optimized to render well on small screens and allow for touch based navigation. In other words, browsing to this page using a desktop client may hurt your eyes….you’ve been warned.

Demo

Before looking at the code, here are a few screen shot from the application on an iPhone:

photo photo-4 photo-5

The image on the left is a screen shot showing the application as it looks right after being loaded. Pressing the “Start Trip” button begins the collection of GPS points and transitions the application to the middle image. Status (number of points, current lat/long with accuracy, and distance traveled) is being updated while points are collected. My iPhone was capable of a sub-second acquisition rate. However, the code (see below) only stores points that are further than 0.05 miles from the last point. This prevents data piling up at long stop lights. Pressing the “End Trip” button will stop the collection of data points and will display the “Start Trip” button. You can then restart collection on the same trip of clear the data by pressing the “Clear Trip” button. The “Map It” button  renders the GPS points on a map using the Google Maps version 3 API.

HTML

The markup for this application is shown below:

<div id="ctrls">
    <a id="toggle" href="#" class="uiElem button green">Start Trip</a>
    <a id="reset" href="#" class="uiElem button blue">Clear Trip</a>
    <a id="map" href="#" class="uiElem button blue">Map It</a>
    <div id="count" class="uiElem">0 Points</div>
    <div id="location" class="uiElem">Unknown</div>
    <div id="distance" class="uiElem">0 miles</div>
</div>
<div id="mapContainer">
    <!-- This is where Google map will go. --->
</div>

The first ‘div’ is a container for the controls and the status information. The three buttons are anchor tags. The status is shown using three ‘div’ elements. The last ‘div’ is the map container.

CSS

Shown below are the styles used:

html,
body {
    height: 100% ;
    margin: 0;
    padding: 0;
    width: 100% ;
}
#mapContainer {
    height: 80% ;
    width: 100% ;
}
#ctrls{
    margin: 10px;
}
.uiElem {
    font: 100px/100% Arial, Helvetica, sans-serif;
    margin: 10px 10px;
    padding: 20px;
    text-align: center;
}
/* CSS3 Gradient Buttons http://www.webdesignerwall.com/tutorials/css3-gradient-buttons/ */
/* button */
.button {
    display: block;
    outline: none;
    cursor: pointer;
    text-align: center;
    text-decoration: none;
    padding: .5em 2em .55em;
    text-shadow: 0 1px 1px rgba(0,0,0,.3);
    -webkit-border-radius: .5em;
    -moz-border-radius: .5em;
    border-radius: .5em;
    -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.2);
    -moz-box-shadow: 0 1px 2px rgba(0,0,0,.2);
    box-shadow: 0 1px 2px rgba(0,0,0,.2);
}
.button:hover {
    text-decoration: none;
}
.button:active {
    position: relative;
    top: 1px;
} 

/* red */
.red {
    color: #faddde;
    border: solid 1px #980c10;
    background: #d81b21;
    background: -webkit-gradient(linear, left top, left bottom, from(#ed1c24), to(#aa1317));
    background: -moz-linear-gradient(top,  #ed1c24,  #aa1317);
    filter:  progid:DXImageTransform.Microsoft.gradient(startColorstr='#ed1c24', endColorstr='#aa1317');
}
.red:hover {
    background: #b61318;
    background: -webkit-gradient(linear, left top, left bottom, from(#c9151b), to(#a11115));
    background: -moz-linear-gradient(top,  #c9151b,  #a11115);
    filter:  progid:DXImageTransform.Microsoft.gradient(startColorstr='#c9151b', endColorstr='#a11115');
}
.red:active {
    color: #de898c;
    background: -webkit-gradient(linear, left top, left bottom, from(#aa1317), to(#ed1c24));
    background: -moz-linear-gradient(top,  #aa1317,  #ed1c24);
    filter:  progid:DXImageTransform.Microsoft.gradient(startColorstr='#aa1317', endColorstr='#ed1c24');
}
/* blue */
.blue {
    color: #d9eef7;
    border: solid 1px #0076a3;
    background: #0095cd;
    background: -webkit-gradient(linear, left top, left bottom, from(#00adee), to(#0078a5));
    background: -moz-linear-gradient(top,  #00adee,  #0078a5);
    filter:  progid:DXImageTransform.Microsoft.gradient(startColorstr='#00adee', endColorstr='#0078a5');
}
.blue:hover {
    background: #007ead;
    background: -webkit-gradient(linear, left top, left bottom, from(#0095cc), to(#00678e));
    background: -moz-linear-gradient(top,  #0095cc,  #00678e);
    filter:  progid:DXImageTransform.Microsoft.gradient(startColorstr='#0095cc', endColorstr='#00678e');
}
.blue:active {
    color: #80bed6;
    background: -webkit-gradient(linear, left top, left bottom, from(#0078a5), to(#00adee));
    background: -moz-linear-gradient(top,  #0078a5,  #00adee);
    filter:  progid:DXImageTransform.Microsoft.gradient(startColorstr='#0078a5', endColorstr='#00adee');
}
/* green */
.green {
    color: #e8f0de;
    border: solid 1px #538312;
    background: #64991e;
    background: -webkit-gradient(linear, left top, left bottom, from(#7db72f), to(#4e7d0e));
    background: -moz-linear-gradient(top,  #7db72f,  #4e7d0e);
    filter:  progid:DXImageTransform.Microsoft.gradient(startColorstr='#7db72f', endColorstr='#4e7d0e');
}
.green:hover {
    background: #538018;
    background: -webkit-gradient(linear, left top, left bottom, from(#6b9d28), to(#436b0c));
    background: -moz-linear-gradient(top,  #6b9d28,  #436b0c);
    filter:  progid:DXImageTransform.Microsoft.gradient(startColorstr='#6b9d28', endColorstr='#436b0c');
}
.green:active {
    color: #a9c08c;
    background: -webkit-gradient(linear, left top, left bottom, from(#4e7d0e), to(#7db72f));
    background: -moz-linear-gradient(top,  #4e7d0e,  #7db72f);
    filter:  progid:DXImageTransform.Microsoft.gradient(startColorstr='#4e7d0e', endColorstr='#7db72f');
}
/* END CSS3 Gradient Buttons */

 

First, a quick and dirty CSS reset is used to help normalize the rendering from the various browsers. Then the mapping container is sized and a bit of margin is added to the controls container. The ‘uiElem’ style is used to set the font size, margins, and padding appropriate for use on small screens that are ‘touch’ driven. In other-words big buttons for my big fingers.

There are no images (except the Google Maps tiles) used to style the above markup. Instead, I am using CSS3 gradients to render the buttons. The folks a Web Design Wall have provided some amazing styles.

JavaScript

The JavaScript is where the application springs to life. There is no ‘server-side’ code backing any of this functionality. First you will need to include the following ‘script’ tags:

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>

The first loads in jQuery and the second enables access to the Google mapping API.

var pts = [];               // All the GPS points
var distIndex = 1;          // Index for distance calculation
var totalDistance = 0.0;    // Total distance travelled
var currentLat = 0.0;       // Current latitude
var currentLng = 0.0;       // Current longitude
var accuracy = 0.0;         // Current accuracy in miles
var minDistance = 0.05;     // Minimum distance (miles) between collected points.
var isStarted = false;      // Flag tracking the application state.
var map = null;             // The map
var markers = [];           // Container for the map markers
var positionTimer;          // The id of the position timer.

The above globals are used to store application data and track state. Next we look at the event handlers for the three buttons (start/stop, reset, and map it).

$("#toggle").click(function(evt){
    evt.preventDefault();
    if(!isStarted){
        $(this).html("End Trip").removeClass("green").addClass("red");
        startGps();
        isStarted = true;
    }else{
        $(this).html("Start Trip").removeClass("red").addClass("green");
        stopGps();
        isStarted = false;
    }
});
$("#reset").click(function(evt){
    evt.preventDefault();
    if(confirm("Clear the data?")){
        pts = [];
        distIndex = 1;
        totalDistance = 0.0;
        currentLat = 0;
        currentLng = 0;
        accuracy = 0;
        updateStatus();
        clearMarkers();
    }
})
$("#map").click(function(evt){
    evt.preventDefault();
    showPoints();
})

The first event handler is for the ‘start/stop’ button. The most important thing happening here is the GPS collection is either started or stopped. There is also a bit of dynamic styling to add a visual indication of the application’s state. The ‘reset’ button simply deletes the collected points, resets the global variables, and updates the UI by calling the ‘updateStatus’ and ‘clearMarkers’ functions (below). Finally, the ‘map it’ button calls the ‘showPoints’ method to display the points on the map.

The JavaScript for updating the status is shown below:

function updateStatus(){
    $("#count").html(pts.length + " Points");
    $("#location").html("(" + currentLat.toFixed(4) + "," + currentLng.toFixed(4) + ") <br />&plusmn;" + accuracy.toFixed(4) + "miles");
    for(var i=distIndex;i<pts.length;i++){
        totalDistance += distance(
            pts[i-1].coords.latitude,
            pts[i-1].coords.longitude,
            pts[i].coords.latitude,
            pts[i].coords.longitude
        );
    }
    distIndex = pts.length;
    $("#distance").html(totalDistance.toFixed(4) + " miles");
}

There is a loop that accumulates the distance of unprocessed (using the ‘distIndex’ variable) points. The distance (in miles) is calculated using the following implementation of the Haversine formula:

function distance(lat1, lng1, lat2, lng2) {
   var radius = 3956.0; // miles

   var deltaLat = ToRadians(lat2 - lat1);
   var deltaLng = ToRadians(lng2 - lng1);
   var sinLat = Math.sin(0.5*deltaLat);
   var sinLng = Math.sin(0.5*deltaLng);
   var cosLat1 = Math.cos(ToRadians(lat1));
   var cosLat2 = Math.cos(ToRadians(lat2));
   var h1 = sinLat*sinLat + cosLat1*cosLat2*sinLng*sinLng;
   var h2 = Math.sqrt(h1);
   var h3 = 2*Math.asin(Math.min(1, h2));
   var distance = radius*h3;
   return distance;
}

function ToRadians(degree) {
   return (degree * (Math.PI / 180));
}

Next are the start and stop functions that control the collection of GPS data.

function startGps(){
   // Check to see if this browser supports geolocation.
   if (navigator.geolocation) {

       positionTimer = navigator.geolocation.watchPosition(
           function( position ){
               if(position.coords.accuracy/609.344>0.5){    // 609.344 meters per mile
                   // First point has low accuracy (cell phone or IP geolocation)
                   // Ignore all low accuracy points.
                   return;
               }
               var dist = distance(currentLat, currentLng, position.coords.latitude, position.coords.longitude);
               if(dist<minDistance){
                   // Ignore points that are within a certain distance to the last point.
                   return;
               }

               pts.push(position);

               // Track current position
               accuracy = position.coords.accuracy/609.344; // 609.344 meters per mile
               currentLat = position.coords.latitude;
               currentLng = position.coords.longitude;

               // Update the status
               updateStatus();
           },
           function( error ){
               console.log( "Something went wrong: ", error );
           },
           {
               timeout: (60 * 1000),
               maximumAge: (1000),
               enableHighAccuracy: true
           }
       );

   } else {
       alert("Your browser does not support geo-location.");
   }
}

function stopGps(){
   navigator.geolocation.clearWatch(positionTimer);
   positionTimer = null;
}

For more details on the browser geolocation API check out the specification. The ‘watchPosition’ function behaves like the JavaScript ‘setInterval’ function and defines a continuous loop for collecting GPS data.

The first bit of logic inside the ‘watchPosition’ callback function determines if the accuracy of the collected point is good enough. The 0.5 mile tolerance was heuristically calculated using my iPhone. The first couple of points can be quite inaccurate. They are probably early estimates of position using either cell phone tower technology or IP lookup.

Next we determines if the new point is far enough away from the last collected point to be processed. This prevents the accumulation of points at long stop lights. If the point passes this filter, it is added to the collection, the current location data is set and the status is updated.

The JavaScript that creates and displays the points is shown next.

var mapContainer = $( "#mapContainer" );
map = new google.maps.Map(
    mapContainer[ 0 ],
    {
        zoom: 1,
        center: new google.maps.LatLng(
            0,
            0
        ),
        mapTypeId: google.maps.MapTypeId.ROADMAP
    }
);

function showPoints(){
    clearMarkers();
    if(pts.length==0){
        map.setCenter(new google.maps.LatLng(0,0));
        map.setZoom(1);
        return;
    }
    var maxLat = -500.0;
    var minLat = 500.0;
    var maxLng = -500.0;
    var minLng = 500.0;
    for(var i=0;i<pts.length;i++){
        var lat = pts[i].coords.latitude;
        var lng = pts[i].coords.longitude;
        if(lat>maxLat){maxLat = lat;}
        if(lat<minLat){minLat = lat;}
        if(lng>maxLng){maxLng = lng;}
        if(lng<minLng){minLng = lng;}
        addMarker(lat, lng);
    }
    if(maxLat==minLat){
        maxLat += 0.5;
        minLat -= 0.5;
    }
    if(minLng==maxLng){
        minLng -= 0.5;
        maxLng += 0.5;
    }
    var sw = new google.maps.LatLng(minLat, minLng);
    var ne = new google.maps.LatLng(maxLat, maxLng);
    var bounds = new google.maps.LatLngBounds(sw, ne);
    map.fitBounds(bounds);
}

function clearMarkers(){
    for(var i=0;i<markers.length;i++){
        marker[i].setMap(null);
        marker[i] = null;
    }
    markers = [];
}

function addMarker( latitude, longitude, label ){
    var marker = new google.maps.Marker({
        map: map,
        position: new google.maps.LatLng(
            latitude,
            longitude
        ),
        title: (label || "")
    });
    markers.push(marker);
}

The map is created when the page loads. When the ‘Map It’ button is pressed, the ‘showPoints’ function is called. That function first clears any current markers from the map and does a quick check for the no data case. If there is data, it loops over all the collected points and adds a marker to the map for each point. Inside this loop, the min/max latitude and longitude are collected. Finally, the map is zoomed to fit the collected points.

Summary

As our mobile devices become equipped with GPS receivers the mobile browsers are exposing API to access this data. The future will see more location aware applications. I believe geo-fencing will become very common.

Posted in geolocation, jQuery, javascript | 7 Comments

Simple Vertical Tabs

There are really two main ways (or a combination of them) to display menus on your web page: horizontally or vertically. Some sites have a combination of the two. For instance a main horizontal menu with vertically expanding sub options. All main menus are either vertical or horizontal.

Many sites have some form of horizontal menu selection across the top. Here are a few screen shots…

image

image 

image

These three example represent one of the most common ways to provide a user a menu of options. The other way of presenting a menu is vertically. Here are a few screen shots…

image  image  image

At some point a menu containing too many options will not fit horizontally. Vertical menu are much better at expanding. Theoretically you can extend your vertical menu forever (please don’t do this though).

When displaying menu options vertically, it is very common to see lists of items. I wanted to add a bit of style to the menu option. This post introduces a page with simple / minimalistic vertical tabs. Here is a screen shot:

image

The demo page itself contains all the code (HTML, CSS, and JavaScript) that you need to reproduce the result. The demo page also contains a brief summary of the key points. In addition you have a live example of a page using the vertical tabs.

Demo

Summary

Check out the demo page for the code. If you have improvements or suggestions please leave a comment.

Posted in css, html, jQuery, web | 1 Comment

The Repository Pattern – Part 2

I previously wrote about using the Repository Pattern with Linq to Fluent NHibernate and MySQL. Since that time, I have had the opportunity to refine and extend this approach. I have also noticed quite a few hits on the old post and thought that sharing these refinements would be useful. If you haven’t read the first post, then go read that first…I’ll wait here.

Code

The Repository Interfaces

I refined the repository interfaces a bit to enable the keyed repository to have a generic key. Previously, I had coded an ‘IIntKeyedRepository’ and an ‘IGuidKeyedRepository’. This can be simplified a bit by having a second order generic interface:

public interface IReadOnlyRepository<TEntity> where TEntity:class
{
    IQueryable<TEntity> All();
    TEntity FindBy(Expression<Func<TEntity, bool>> expression);
    IQueryable<TEntity> FilterBy(Expression<Func<TEntity, bool>> expression);
}
public interface IRepository<TEntity> : IReadOnlyRepository<TEntity> where TEntity:class
{
    bool Add(TEntity entity);
    bool Add(IEnumerable<TEntity> items);
    bool Update(TEntity entity);
    bool Delete(TEntity entity);
    bool Delete(IEnumerable<TEntity> entities);
}
public interface IKeyedRepository<TKey, TEntity> : IRepository<TEntity>
    where TEntity : class, IKeyed<TKey>
{
    TEntity FindBy(TKey id);
}
public interface IKeyed<TKey>
{
    TKey Id { get; }
}

 

Now all of the keyed entities implement the ‘IKeyed’ interface and the repository is of type ‘IKeyedRepository’. This is a bit simpler and more generic.

 Repository Time Bombs

I previously had created an entity that looked like the following:

public class Truck
{
    public virtual int Id { get; private set; }
    public virtual string Name { get; set; }
    public virtual string Type { get; set; }
    public virtual string PlateNumber { get; set; }
    public virtual Driver Driver { get; private set; }
    public virtual IList<Location> Locations { get; private set; }
}

After some testing, I soon realized the ‘Locations’ property was a “time bomb” waiting to happen. Once the resulting list become large, accessing this property is very slow. This “return every thing in the list” query is not scalable and has been removed.

This does not mean that I have removed all the NHibernate relational mappings between my entities. I am using the following rules:

  1. If the relationship goes in the direction where only a single object is returned (the ‘one’ end of a ‘one-to-many’) the mapping is safe to keep.
  2. If the relationship goes in the direction where there is a guaranteed limited small number of items in the list the mapping is probably safe to keep.
  3. If the relationship can return an unbounded number of items (the ‘many’ end of the ‘one-to-many’) the mapping is not safe and is removed.

Entity Validation

A common task is to validation an entity. This validation may be done at a number of layers. I strongly believe that my entities (domain model) should be as anemic as possible. Implementing the validation logic in the entity goes against the single responsibility principle. I prefer to have my validation classes stand on their own using the following interface:

public interface IValidator<T>
{
    bool IsValid(T entity);
    IEnumerable<string> BrokenRules(T entity);
}

To create a concrete example, let’s say we have a ‘User’ entity defined by the following class:

public class User : IKeyed<int>
{
    public virtual int Id { get; private set; }
    public virtual string UserName { get; set; }
    public virtual string FirstName { get; set; }
    public virtual string LastName { get; set; }
    public virtual string Email { get; set; }
}

Then the validator for this entity will look something like the following:

public class UserValidator : IValidator<User>
{
    private readonly IKeyedRepository<int, User> _userRepo;
    public UserValidator(IKeyedRepository<int, User> userRepo)
    {
        _userRepo = userRepo;
    }

    public bool IsValid(User entity)
    {
        return BrokenRules(entity).Count() > 0;
    }

    public IEnumerable<string> BrokenRules(User entity)
    {
        if(string.IsNullOrEmpty(entity.UserName))
        {
            yield return "User name is required.";
        }
        else
        {
            if(_userRepo.FindBy(x=>x.UserName==entity.UserName)!=null)
            {
                yield return "User name is already taken.";
            }
        }
        if(string.IsNullOrEmpty(entity.FirstName))
        {
            yield return "First name is required.";
        }
        if(string.IsNullOrEmpty(entity.LastName))
        {
            yield return "Last name is required.";
        }
        if(string.IsNullOrEmpty(entity.Email))
        {
            yield return "Email address is required.";
        }
        else
        {
            const string patternStrict = @"^(([^<>()[\]\\.,;:\s@\""]+"
                                         + @"(\.[^<>()[\]\\.,;:\s@\""]+)*)|(\"".+\""))@"
                                         + @"((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"
                                         + @"\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+"
                                         + @"[a-zA-Z]{2,}))$";
            Regex regexStrict = new Regex(patternStrict);
            if(!regexStrict.IsMatch(entity.Email))
            {
                yield return "Email must be valid format.";
            }
        }

        yield break;
    }
}

This validator takes as a constructor parameter a reference to the ‘IKeyedRepository’ for the ‘User’ entities. This is used to ensure the ‘UserName’ property is unique in the database. The rest of the validation ensures the require properties exist and are in the expected format.

Service Wrapper

Passing around your generic ‘IRepository’ instances maybe fine for small applications. However, you soon end up with MVC controllers constructors that look like the following:

public HomeController(  ILogger logger,
                        IKeyedRepository<int, User> userRepo,
                        IKeyedRepository<int, Truck> truckRepo,
                        IKeyedRepository<int, Location> locationRepo,
                        IUnitOfWork unitOfWork)
{
    _logger = logger;
    _userRepo = userRepo;
    _truckRepo = truckRepo;
    _locationRepo = locationRepo;
}

Even though we are using a IOC container to manage the life-time of these parameters, this is quickly becoming un-manageable.

Also, there usually exist cross-cutting queries that a single repository cannot handle. For instance find the current location of a truck given a user. Implementing these queries in higher level (presentation or business logic) layers can cause issues. This also usually ends up violating the DRY principle as the queries are replicated in various places. These queries need to have a home.

For this reason, it is a good idea to create a service layer around the generic repository implementations. Assume that we have the following implemented using our favorite ORM:

public class Repository<T> : IKeyedRepository<int, T>
    where T : class, IKeyed<int>
{
    // implementation goes here...
}

 

The goal is to create a service layer that provides access to the desired repositories and the implementation of cross-cutting queries. Here is an example:

public class DataService
{
    private readonly IKeyedRepository<int, User> _userRepo;
    private readonly IKeyedRepository<int, Truck> _truckRepo;
    private readonly IKeyedRepository<int, Location> _locationRepo;
    private readonly IUnitOfWork _unitOfWork;

    public UserService Users { get; private set; }
    public TruckService Trucks { get; private set; }
    public LocationService Locations { get; private set; }

    public DataService(IKeyedRepository<int, User> userRepo,
        IKeyedRepository<int, Truck> truckRepo,
        IKeyedRepository<int, Location> locationRepo,
        IUnitOfWork unitOfWork)
    {
        _userRepo = userRepo;
        _truckRepo = truckRepo;
        _locationRepo = locationRepo;
        _unitOfWork = unitOfWork;

        Users = new UserService(userRepo);
        Trucks = new TruckService(truckRepo);
        Locations = new LocationService(locationRepo);
    }

    public Location GetCurrentLocation(int truckId)
    {
        return _locationRepo
            .FilterBy(x => x.Id == truckId)
            .OrderByDescending(c => c.Timestamp)
            .FirstOrDefault();
    }

    public void Commit()
    {
        _unitOfWork.Commit();
    }
}

The ‘DataService’ class now accepts most of the parameters that were previously injected into the ‘HomeController’. So what have we gained? Since we probably have more than one MVC controller and those other controllers probably had the same large list of constructor parameters we have simplified our controllers and increased the maintainability of our application.

The ‘DataService’ exposes three properties (‘Users’, ‘Trucks’ and ‘Locations’), one additional query (‘GetCurrentLocation’) and the ‘Commit’ method. The additional query is not cross cutting, but you could easily imagine one that did have cross-cutting concerns. The following is an example of one of the properties (the others in the download):

public class UserService
{
    private readonly IKeyedRepository<int, User> _userRepo;
    private readonly UserValidator _validation;

    public UserService(IKeyedRepository<int, User> userRepo)
    {
        _userRepo = userRepo;
        _validation = new UserValidator(userRepo);
    }
    public IList<User> All()
    {
        return _userRepo.All().ToList();
    }

    public User FindBy(Expression<Func<User, bool>> expression)
    {
        return _userRepo.FindBy(expression);
    }

    public IList<User> FilterBy(Expression<Func<User, bool>> expression)
    {
        return _userRepo.FilterBy(expression).ToList();
    }

    public bool Add(User entity, out IEnumerable<string> brokenRules)
    {
        if(!_validation.IsValid(entity))
        {
            brokenRules = _validation.BrokenRules(entity);
            return false;
        }
        brokenRules = null;
        return _userRepo.Add(entity);
    }

    public bool Add(IEnumerable<User> items, out IEnumerable<string> brokenRules)
    {
        foreach (User item in items)
        {
            if(!_validation.IsValid(item))
            {
                brokenRules = _validation.BrokenRules(item);
                return false;
            }
        }
        brokenRules = null;
        return _userRepo.Add(items);
    }

    public bool Update(User entity, out IEnumerable<string> brokenRules)
    {
        if(!_validation.IsValid(entity))
        {
            brokenRules = _validation.BrokenRules(entity);
            return false;
        }
        brokenRules = null;
        return _userRepo.Update(entity);
    }

    public bool Delete(User entity)
    {
        return _userRepo.Delete(entity);
    }

    public bool Delete(IEnumerable<User> entities)
    {
        return _userRepo.Delete(entities);
    }

    public User FindBy(int id)
    {
        return _userRepo.FindBy(id);
    }
}

The ‘UserService’ essentially implements the ‘IKeyedRepository<int, User>’ interface with two small (but important) differences.

  1. All the methods in ‘IKeyedRepository’ that return ‘IQueryable’ now return ‘IList’. This means that the power of LINQ to build up queries stops in this layer. This is an important architecture decision. Higher layers are not going to be able to filter the query results further. The reason for this choice is that we want to force all ‘querying’, ‘filtering’ or ‘paging’ code down into this service layer. This help enforce the DRYness of our application.
  2. Validation logic has been added to the ‘Add’ and ‘Update’ methods. This validation logic is provided by ‘IValidator’ implementations.

Summary

The above refinements and extensions to the previously discussed repository pattern coalesce into a pattern that I have found useful. I hope this additional information is useful to you. If you have additional refinements or suggestions, please feel free to share with the other readers.

Posted in best practice, nhibernate | 13 Comments

GPS Data Logger using the Netduino

The last blog post, I described how to use the Netduino and the ladyada GPS shield to collect GPS points. Since that time the Netduino folks have made public an alpha release of firmware that supports mounting an SD card.

If you are not into accepting the risks and short falls of alpha code, then you may not want to deploy this to your hardware. There were some issues with the firmware running in Parallels on my Mac. That is not a big deal to me. I appreciate the opportunity to provide feedback and get a glimpse of the new SD card mounting code. Just wanted to be up front….buyer be ware!

 

Code

Running the Netduino Firmware 4.1.1 alpha 1 software my main program now looks like the following:

public class Program
{
    private const string _root = "SD_Card";
    private static string _path;
    private static FileStream _fileStream;
    private static StreamWriter _writer;

    private static readonly OutputPort _led2 = new OutputPort(Pins.GPIO_PIN_D3, false);

    public static void Main()
    {
        // Mount the SD card
        //
        StorageDevice.MountSD(_root, SPI.SPI_module.SPI1, Cpu.Pin.GPIO_Pin12);

        // Determine the next file name.
        //
        int fileIndex = 0;
        do
        {
            fileIndex++;
            _path = Path.Combine(_root, "gpsData" + fileIndex + ".txt");

        } while (File.Exists(_path));

        // Open the file stream and the stream writer.
        //
        _fileStream = new FileStream(_path, FileMode.CreateNew, FileAccess.Write, FileShare.None, 512);
        _writer = new StreamWriter(_fileStream);

        // Open the serial port and turn the GPS unit on.
        //
        Thread.Sleep(500);    // The GPS seems to need a little delay
        SerialPort serialPort = new SerialPort("COM1", 4800, Parity.None, 8, StopBits.One);
        OutputPort powerPin = new OutputPort(Pins.GPIO_PIN_D2, false);

        // Create a gps reader, hook up the event, and start the reader thread
        //
        Reader gpsShield = new Reader(serialPort, 100, 0.1);
        gpsShield.GpsData += GpsShield_GpsData;
        gpsShield.Start();

        // The main thread is done.
        //
        Thread.Sleep(Timeout.Infinite);
    }

    private static void GpsShield_GpsData(GpsPoint gpsPoint, string rawLine)
    {
        try
        {
            // Write the raw line to the data file.
            //
            _writer.WriteLine(rawLine);
            _writer.Flush();
            _fileStream.Flush();

            // Flash the led to indicate.
            //
            _led2.Write(true);
            Thread.Sleep(200);
            _led2.Write(false);
        }
        catch (Exception ex)
        {
            //Debug.Print("Exception: " + ex);
        }
    }
}

The first thing that happens in the above code is the SD card is mounted. You are allowed to name the mounted drive. In this case, I have chosen “SD_Card” as the name. The code then determines the next available file name. The process simply looks for files that exist with the name “gpsDataX.txt” where X is a number starting with 1.

Once an available file name is found, the code opens a ‘FileStream’ and wraps a “StreamWriter’ around it. These two objects are global static variable.

The communication to the GPS unit is then established and a ‘Reader’ object created. This code was covered in the previous blog and I will not spend any time on it here. I will point out that the CTOR for the ‘Reader’ object takes three parameters. The last parameter is the minimum distance between GPS points written to the SD drive. In this case, this number is set to 0.1 miles.

The main thread is then put to sleep for ‘Timeout.Infinite’ time.  The main thread can be used to do other work. For instance, you may want to add a display device to show the current location information.

The ‘GpsData’ event handler uses the ‘StreamWriter’ object to write the raw GPS sentence to the mounted SD card. This data is then flushed to the drive. This event handler then flashes ‘LED 2’ for 200 milliseconds to provide an indication that data was written.

Summary

Although this is an alpha release, I like the API for mounting the SD card. Once it is mounted, then it is used like any other disk. Be sure to check the Netduino site regularly if you decide to use the alpha release. I am sure there will be a beta or RTM soon.

Posted in .netmf, geolocation, netduino | 1 Comment

GPS using the Netduino

I recently blogged about using the Arduino board as a GPS data logger. I have been using this to collect geo-location data for the Truck Tracker application. In this post, I will explore using the Netduino for that purpose.

Meet the Netduino

Here is a photo of the Netduino board.

imageThere are more technical specs for the Netduino board on the Netduino site. The two features that stand out to me are:

  • Most of the Arduino shields are compatible with the Netduino. This means that many of the Arduino projects can be ported to the Netduino. In this post, we will look at porting the GPS shield used in the Arduino project to work with the Netduino.
  • The programming environment of the Netduino is the .NET Micro Framework (.NET MF). This allows your favorite flavor of Visual Studio to be used as your IDE.

Here is a photo of the GPS shield mounted to the Netduino.

image

Connections

If you built the GPS shield following the instructions on the ladyada site, then the following are the pin out connections that the Netduino will use to communicate with the GPS shield:

  • TX (Digital I/O Pin 0) – This is the transmit pin, data that comes from the GPS module with location data.
  • RX (Digital I/O Pin 1) – This is the receive pin, data that goes to the GPS module to configure it.
  • PWR (Digital I/O Pin 2) – This pin is connected to a transistor that controls power to the GPS. When this pin is set to LOW the GPS module turns on and when the pin is set to HIGH the GPS turns off.

Once the unit has power, the TX/RX pins are a serial port that is used to communicate with the GPS unit. Once power is applied, GPS data will begin being streamed from the GPS unit.

Basic Programming

The most basic Netduino code to connect and read data from the GPS serial port is shown below:

using System;
using System.IO.Ports;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;

namespace GpsLogger
{
    public class Program
    {
        public static void Main()
        {
            // write your code here
            SerialPort serialPort = new SerialPort("COM1", 4800, Parity.None, 8, StopBits.One);
            serialPort.Open();

            // pin D2 off = gps module turned on
            OutputPort powerPin = new OutputPort(Pins.GPIO_PIN_D2, false);

            while (true)
            {
                int bytesToRead = serialPort.BytesToRead;
                if (bytesToRead > 0)
                {
                    // get the waiting data
                    byte[] buffer = new byte[bytesToRead];
                    serialPort.Read(buffer, 0, buffer.Length);
                    // print out our received data
                    Debug.Print(new String(System.Text.Encoding.UTF8.GetChars(buffer)));
                }

                Thread.Sleep(100); // wait a bit so we get a few bytes at a time...
            }
        }
    }
}

This code is taken from the one of the posts on the very active Netduino community forum. The first thing you will notice is a few new C# using statements. There are a few from the Microsoft.SPOT namespace. SPOT stands for “smart personal object technology” and was developed by Microsoft to personalize household electronics and other everyday devices. Microsoft has extended this namespace to include a range of essential hardware features that programmers can use when developing embedded device firmware. There are also a couple of using statements with a Secretlabs.NETMF.Hardware namespace. Secret Labs is the company that is developing the Netduino hardware and manages the developer community.

The first two lines of the code begins serial communications with the GPS. The Netduino firmware is setup so that “COM1” uses digital pins 0 / 1 for serial TX / RX. The next line of code applies power to the GPS unit. Finally the never ending while loop, reads and prints data to the debugger. Below is a screen shot of the debugger in action.

Did I mention the debugger? You can debug your Netduino embedded project just like you are used to in Visual Studio. Amazingly, break points, watches and live evaluations all work. Great job to who ever figured that out!

 

image

In the bottom right, you can see the debug output showing the serial data coming from the GPS unit.

A Refined Example

The above code is great to get you started reading the GPS data. There is a bit more work to be done to get a reusable GPS shield library. Here are the goals of this GPS library:

  • Encapsulate the GPS code into a few logical classes in a form that is reusable.
  • Take advantage of the Netduino’s support of events by creating an event that other parts of the application can subscribe. The event will be raised when ever new data is available.

Here is the new entry point that is using the library:

public static void Main()
{
    SerialPort serialPort = new SerialPort("COM1", 4800, Parity.None, 8, StopBits.One);

    OutputPort powerPin = new OutputPort(Pins.GPIO_PIN_D2, false);

    Reader gpsShield = new Reader(serialPort, 100, 1.0);
    gpsShield.GpsData += GpsShield_GpsData;
    gpsShield.Start();

    while (true)
    {
        // Do other processing here.
        //
        // Can stop the gps processing by calling...
        //  gpsShield.Stop();
        //
        // Restart by calling...
        //  gpsShield.Start();
        //
        Debug.Print("Main...");
        Thread.Sleep(10000);
    }
}

private static void GpsShield_GpsData(GpsPoint gpsPoint)
{
    Debug.Print("time: " + gpsPoint.Timestamp + "\tLat/Lng: " + gpsPoint.Latitude + "/" + gpsPoint.Longitude);
}

This code starts nearly the same by creating a ‘SerialPort’ and ‘OutputPort’ objects for serial communication and power. It uses constructor injection to create a GPS ‘Reader’ class with access to the ‘SerialPort’ object. The constructor takes three parameters: an instance of ‘SerialPort’, a timeout in milliseconds, and the minimum distance (in miles) between GPS data events. The timeout is used as a bit of a throttle for reading the serial port. The distance parameter allows the hardware take GPS observation points at a higher rate (one per second) and only raise data available events if the distance between the points is larger than this minimum. This allows data to be saved only when the new points are significantly apart thus allowing the SD card memory to be used more efficiently.

Next the “GpsData” event is subscribed to by the main application and an event handler is assigned. Currently, the data is only written to the debug console. This will eventually be the routine used to persist the data to the SD memory card. Notice the data being passed to the event is of type “GpsPoint”.

The ability to persist data to SD cards is currently being baked into the Netduino firmware. There is an update expected soon.

 

public class GpsPoint
{
    public DateTime Timestamp { get; set; }
    public double Latitude { get; set; }
    public double Longitude { get; set; }
    public double SpeedInKnots { get; set; }
    public double BearingInDegrees { get; set; }
}

Instances of “GpsPoint” contain the location information parsed from the GPS serial port.

The reader class is shown below:

public class Reader
{
    private readonly object _lock = new object();
    private readonly SerialPort _serialPort;
    private readonly int _timeOut;
    private readonly double _minDistanceBetweenPoints;
    private bool _isStarted;
    private Thread _processor;

    public delegate void LineProcessor(string line);

    public delegate void GpsDataProcessor(GpsPoint gpsPoint);

    public event LineProcessor RawLine;
    public event GpsDataProcessor GpsData;

    public bool IsStarted { get { return _isStarted; } }

    public Reader(SerialPort serialPort)
        : this(serialPort, 100, 0.0)
    {

    }
    public Reader(SerialPort serialPort, int timeOutBetweenReadsInMilliseconds, double minDistanceInMilesBetweenPoints)
    {
        _serialPort = serialPort;
        _timeOut = timeOutBetweenReadsInMilliseconds;
        _minDistanceBetweenPoints = minDistanceInMilesBetweenPoints;
    }

    public bool Start()
    {
        lock (_lock)
        {
            if(_isStarted)
            {
                return false;
            }
            _isStarted = true;
            _processor = new Thread(ThreadProc);
            _processor.Start();
        }
        return true;
    }

    public bool Stop()
    {
        lock (_lock)
        {
            if(!_isStarted)
            {
                return false;
            }
            _isStarted = false;
            if(!_processor.Join(5000))
            {
                _processor.Abort();
            }
            return true;
        }
    }

    private void ThreadProc()
    {
        Debug.Print("GPS thread started...");
        if(!_serialPort.IsOpen)
        {
            _serialPort.Open();
        }
        while (_isStarted)
        {
            int bytesToRead = _serialPort.BytesToRead;
            if (bytesToRead > 0)
            {
                byte[] buffer = new byte[bytesToRead];
                _serialPort.Read(buffer, 0, buffer.Length);
                try
                {
                    string temp = new string(System.Text.Encoding.UTF8.GetChars(buffer));
                    ProcessBytes(temp);
                }
                catch (Exception ex)
                {
                    // only process lines we can parse.
                    Debug.Print(ex.ToString());
                }
            }

            Thread.Sleep(_timeOut);
        }
        Debug.Print("GPS thread stopped...");
    }

    private string _data = string.Empty;
    private GpsPoint _lastPoint;
    private void ProcessBytes(string temp)
    {
        while (temp.IndexOf('\n') != -1)
        {
            string[] parts = temp.Split('\n');
            _data += parts[0];
            _data = _data.Trim();
            if (_data != string.Empty)
            {
                if (_data.IndexOf("$GPRMC") == 0)
                {
                    if(GpsData!=null)
                    {
                        GpsPoint gpsPoint = GprmcParser.Parse(_data);
                        if (gpsPoint != null)
                        {
                            bool isOk = true;
                            if(_lastPoint!=null)
                            {
                                double distance = GeoDistanceCalculator.DistanceInMiles(gpsPoint.Latitude, gpsPoint.Longitude,
                                                                               _lastPoint.Latitude, _lastPoint.Longitude);
                                double distInFeet = distance*5280;
                                Debug.Print("distance = " + distance + " mi (" + distInFeet + " feet)");
                                if(distance<_minDistanceBetweenPoints)
                                {
                                    // Too close to the last point....don't raise the event
                                    isOk = false;
                                }
                            }
                            _lastPoint = gpsPoint;

                            // Raise the event
                            if(isOk)
                            {
                                GpsData(gpsPoint);
                            }
                        }
                    }
                }
                if (RawLine != null)
                {
                    RawLine(_data);
                }
            }
            temp = parts[1];
            _data = string.Empty;
        }
        _data += temp;
    }
}

The public facing features include the CTOR, ‘Start’, and ‘Stop’. We previously discussed the CTOR parameters. The ‘Start’ method spins up a thread to read and process the GPS serial port. The ‘Stop’ method signals the thread to end and waits for it to join the thread requesting the stop.

I am not as sure of how the threading is working on the Netduino. This code seems to work on my computer, but may have issues that I am not aware of. The additional thread could easily be removed from the above code. I was thinking the main thread may have other processing (think a responsive UI) and pushing the GPS to its own thread may be necessary.

 

The ‘ThreadProc’ method is the main processing routine running in the separate thread. It is a loop that continues until the ‘_isStarted’ variable is set to ‘false’ by the ‘Stop’ method. The guts of the while loop reads and processes data from the GPS serial port.

The ‘ProcessBytes’ method process the serial port data. The GPS unit provides a stream of ‘GPS sentences’ that have a specified format. This method puts together the incoming bytes and processes completed lines (or sentences) once they are formed. The code above looks for only the “GPRMC” sentence. If one is found it is parsed using the following parser:

public class GprmcParser
{
    // Parse the GPRMC line
    //
    public static GpsPoint Parse(string line)
    {
        // $GPRMC,040302.663,A,3939.7,N,10506.6,W,0.27,358.86,200804,,*1A

        if(!IsCheckSumGood(line))
        {
            return null;
        }

        try
        {
            string[] parts = line.Split(',');
            if (parts.Length != 12)
            {
                return null;
            }

            if (parts[2] != "A")
            {
                return null;
            }

            string date = parts[9]; // UTC Date DDMMYY
            if (date.Length != 6)
            {
                return null;
            }
            int year = 2000 + int.Parse(date.Substring(4, 2));
            int month = int.Parse(date.Substring(2, 2));
            int day = int.Parse(date.Substring(0, 2));
            string time = parts[1]; // HHMMSS.XXX
            if (time.Length != 10)
            {
                return null;
            }
            int hour = int.Parse(time.Substring(0, 2));
            int minute = int.Parse(time.Substring(2, 2));
            int second = int.Parse(time.Substring(4, 2));
            int milliseconds = int.Parse(time.Substring(7, 3));
            DateTime utcTime = new DateTime(year, month, day, hour, minute, second, milliseconds);

            string lat = parts[3];  // HHMM.MMMM
            if (lat.Length != 9)
            {
                return null;
            }
            double latHours = double.Parse(lat.Substring(0, 2));
            double latMins = double.Parse(lat.Substring(2));
            double latitude = latHours + latMins / 60.0;
            if (parts[4] == "S")       // N or S
            {
                latitude = -latitude;
            }

            string lng = parts[5];  // HHHMM.M
            if (lng.Length != 10)
            {
                return null;
            }
            double lngHours = double.Parse(lng.Substring(0, 3));
            double lngMins = double.Parse(lng.Substring(3));
            double longitude = lngHours + lngMins / 60.0;
            if (parts[6] == "W")
            {
                longitude = -longitude;
            }

            double speed = double.Parse(parts[7]);
            double bearing = double.Parse(parts[8]);

            // Should probably validate check sum

            GpsPoint gpsPoint = new GpsPoint
                                  {
                                      BearingInDegrees = bearing,
                                      Latitude = latitude,
                                      Longitude = longitude,
                                      SpeedInKnots = speed,
                                      Timestamp = utcTime
                                  };
            return gpsPoint;

        }
        catch (Exception)
        {
            // One of our parses failed...ignore.
        }
        return null;
    }

    private static bool IsCheckSumGood(string sentence)
    {
        int index1 = sentence.IndexOf("$");
        int index2 = sentence.LastIndexOf("*");

        if (index1 != 0 || index2 != sentence.Length - 3 )
        {
            return false;
        }

        string checkSumString = sentence.Substring(index2 + 1, 2);
        int checkSum1 = Convert.ToInt32(checkSumString, 16);

        string valToCheck = sentence.Substring(index1 + 1, index2 - 1);
        char c = valToCheck[0];
        for(int i = 1;i<valToCheck.Length;i++)
        {
            c ^= valToCheck[i];
        }

        return checkSum1 == c;
    }
}

There are many available GPS sentence parsers out there. The above parser extracts the encoded information from the sentence and returns a ‘GpsPoint’ object (or null if there was a parsing error).

The processing code then calculates the distance between the new point and the previous point. This is done using the Haversine formula implemented by the following class:

public static class GeoDistanceCalculator
{
    private const double _earthRadiusInMiles = 3956.0;
    private const double _earthRadiusInKilometers = 6367.0;
    public static double DistanceInMiles(double lat1, double lng1, double lat2, double lng2)
    {
        return Distance(lat1, lng1, lat2, lng2, _earthRadiusInMiles);
    }
    public static double DistanceInKilometers(double lat1, double lng1, double lat2, double lng2)
    {
        return Distance(lat1, lng1, lat2, lng2, _earthRadiusInKilometers);
    }
    private static double Distance(double lat1, double lng1, double lat2, double lng2, double radius)
    {
        // Implements the Haversine formulat http://en.wikipedia.org/wiki/Haversine_formula
        //
        var lat = MathMF.ToRadians(lat2 - lat1);
        var lng = MathMF.ToRadians(lng2 - lng1);
        var sinLat = MathMF.Sin(0.5*lat);
        var sinLng = MathMF.Sin(0.5*lng);
        var cosLat1 = MathMF.Cos(MathMF.ToRadians(lat1));
        var cosLat2 = MathMF.Cos(MathMF.ToRadians(lat2));
        var h1 = sinLat*sinLat + cosLat1*cosLat2*sinLng*sinLng;
        var h2 = MathMF.Sqrt(h1);
        var h3 = 2 * MathMF.Asin(MathMF.Min(1, h2));
        return radius * h3;
    }
}

This code relies heavily on a math library (MathMF namespace) developed by Elze Kool. I slightly modified this library to use the System.Math functions where ever they were available. The changes that I made are shown below:

public static readonly double PI = System.Math.PI;

public static readonly double E = System.Math.E;

public static double Pow(double x, double y)
{
    return System.Math.Pow(x, y);
}

public static double Sqrt(double x)
{
    return System.Math.Pow(x, 0.5);
}

Not all the .NET framework is available in the .NET micro framework. One example is the ‘System.Math’ namespace. As the .NET micro framework grows up, I suspect that some of these namespaces will become available. Until then, we must rely on implementation made by the community.

If the distance is larger than the specified (in the CTOR) minimum, then the ‘GpsData’ event is raised. In addition a ‘RawLine’ event is available for every GPS sentence to be available.

Summary

Using the Netduino with the GPS shield was very straight-forward. I especially enjoy that I can use Visual Studio as my IDE. When the Netduino folks post an updated firmware that includes SD card features, I will continue this development and begin saving the data. I encourage anyone with a bit of curiosity to go get your self a Netduino and begin experimenting.

Posted in .netmf, geolocation, hardware, netduino | 15 Comments

Truck Tracker Is Live

I have deployed the Truck Tracker application to here for now:

http://bobcravens.com/trucktracker/

The application is built using the following technologies:

  • ASP.NET MVC
  • Google Maps API v.3
  • jQuery
  • DotNetOpenAuth
  • MySQL
  • NHibernate
  • Ninject

The intent of the application is to create a “Nerd Dinner” like application that can be used as a reference to build your own application. I intend on making the source code available and will provide a link on the application site to access the source. I need to do review / cleanup the code added since the last spike and then I will post the code.

I will begin developing a service layer to allow you to push GPS data to the site programmatically. This will allow those of you who want to experiment with GPS to use the Truck Tracker application as a framework to display your data.

I will also be exploring how to get GPS data up to the site myself. The site already supports uploading GPS data files generated by the Arduino GPS Data Logger. I recently purchased a few Netduios and will try to get them working with the GPS module. The exciting thing is that the Netduinos are programmed using the Dot Net Micro Framework. I be looking to add a WiFi shield to the Netduino hardware. This should allow me to roam into a public or my home WiFi to push data automatically.

In addition, I have been wanting to create an iPhone application for some time and will be working on an application compatible with the Truck Tracker service layer soon after I publish the API. If would love having an experienced iPhone developer help with this a bit…any takers?

Adding your own truck (or vehicle) does require that you register via one of the OpenID or OAuth providers. Any trucks that you add can be marked as private.

Here is a screen shot of the home page. The list authentication providers that are available are shown at the top of the list. This screen shot is what you see before you log in.

image

The truck list on the left are all trucks that are marked as “public”. Once you log in you see the following screen:

image

Now the login area has been replaced with a menu bar that allows trucks to be managed. The list on the left now shows only trucks that you have added. Clicking on any of the trucks will display the current location of the truck and the last 24 hours of GPS points (note in the image below, this truck has not moved in the last 24 hours).

image

Once a truck has been selected a “Manage Truck” menu item appears. Clicking that item brings you to the following page:

image

The top part of this page allows you to update information about the truck. The bottom part allows you to upload the GPS data files generated by the Arduino Data Logger hardware.

Clicking the “Add Truck” menu item displays a page that allows you to add a new truck.

image

The bottom of the site includes a footer with links to the technologies used to build the site and tutorials on how to get started. This is where I will provide a link to the source code when it gets posted.

image

Summary

I would consider this release as an early “beta” release. I will be addressing issues as I become aware of them. If you find anything, please let me know.

Posted in arduino, asp.net, geolocation, jQuery, mvc, nhibernate, ninject | 10 Comments

Making The Web Growl Using jQuery

I really like how the Growl application for the Mac works. It provides a notification framework that all applications can use. I often find my self needing to display notifications to the user in my web applications. For instance, when the user incorrectly fills out a form. Here is a screen shot of a simple ‘growl notification’.

imageThis is not complicated to add to an application. In the vein of “Don’t Repeat Yourself” I have put created a ‘growl package’ that can be downloaded below. For a live example check out the demo.

Demo Download

Growl Code

The download for the growl code consists of a JavaScript file and a CSS file. The JavaScript file contains the following code:

// Can't growl until the document is ready
var isGrowlReady = false;
$(document).ready(function () {
    isGrowlReady = true;
});

var growlMask;
var growlWrap;
var growlTitle;
var growlContent;
var isGrowlVisible = false;
function growl(title, msg) {
    // Recursively call growl until doc is ready
    while (!isGrowlReady) {
        setTimeout("growl('" + title + "', '" + msg + "')", 100);
        return;
    }

    // Ensure the growl HTML is in place and the events
    //  are hooked up. This code executes once.
    initGrowl();

    // Size the mask and growl window.
    sizeGrowl(true);

    // Animate the growl.
    growlMask
        .fadeTo("fast", 0.75, function () {
            isGrowlVisible = true;
            var scrollTop = $(document).scrollTop();
            growlTitle.html(title);
            growlContent.html(msg);
            growlWrap.show().animate({ "marginTop": scrollTop + 10 + "px" }, 500);
        });
}

function initGrowl() {
    if ($("#growl-mask").length == 0) {
        // Append growl HTML to body
        var growl = "<div id='growl-mask'></div><div id='growl-wrap'><h6 id='growl-title'></h6><div id='growl-content'></div></div>";
        $("body").append(growl);

        // Initialize global variables
        growlMask = $("#growl-mask");
        growlWrap = $("#growl-wrap");
        growlContent = $("#growl-content");
        growlTitle = $("#growl-title");

        // Hide growl on click event to the mask
        growlMask.click(function () {
            isGrowlVisible = false;
            growlWrap.fadeOut();
            growlMask.fadeOut();
        });
        // Reposition the growl if window is sized or scrolled
        $(window).resize(function () {
            if (isGrowlVisible) {
                growlMask.stop();
                growlWrap.stop();
                sizeGrowl(false);
            }
        });
        $(window).scroll(function () {
            if (isGrowlVisible) {
                growlMask.stop();
                growlWrap.stop();
                sizeGrowl(false);
            }
        });
    }
}

function sizeGrowl(hide) {
    // Collect some measurements
    var scrollLeft = $(document).scrollLeft();
    var scrollTop = $(document).scrollTop();
    var growlWidth = growlWrap.outerWidth();
    var growlHeight = growlWrap.outerHeight();
    var winWidth = $(window).width();
    var docHeight = $(document).height();
    var docWidth = $(document).width();

    // Calculate the notification position.
    var growlTop = hide ? scrollTop - growlHeight : scrollTop + 10;
    var growlLeft = scrollLeft + (winWidth - growlWidth) / 2;

    // Size and position the mask and the notification
    growlMask.css({ "width": docWidth + "px", "height": docHeight + "px" });
    growlWrap.css({ "margin-top": growlTop + "px", "left": growlLeft + "px" });
}

The first bit of JavaScript leverages the jQuery document ‘ready’ event to set a flag indicating the application is ready to support growls. This hook is necessary to support growls that originate in server side code (see ASP.NET MVC below for example).

There are two supporting functions in the JavaScript: ‘initGrowl’ and ‘sizeGrowl’. The ‘initGrowl’ function injects the necessary HTML to support the growl into the document, collects some quick references to the elements for use by other functions, and hooks up events. The windows ‘resize’ and ‘scroll’ events are used to keep the notification window positioned. The ‘sizeGrowl’ function takes a few measurements of the document and then sizes and positions the growl mask and notification window.

/* Growl
----------------------------------------------------------*/
#growl-mask
{
    background-color: #000;
    position: absolute;
    display: block;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
    display: none;
}
#growl-wrap
{
    background-color: #fff;
    color: #000;
    min-width: 400px;
    margin: 0;
    display: none;
    position: absolute;
    top: 0;
    left: 0;
}
#growl-title
{
    text-align: center;
    color: #000;
}
#growl-content
{
    margin: 10px;
    border: 1px solid #333;
    padding: 30px;
}
#growl-content p
{
    margin-bottom: 10px;
}

The CSS above adds a bit of style. This will certainly need a touch up to blend into the application.

JavaScript Growls

To create a ‘growl’ notification using JavaScript simply include a link to the growl CSS and JavaScript then call the ‘growl’ function. Here is an example for validating a form:

<script type="text/javascript">
    $("#submit").click(function(){
        var msg = "";
        if($("#first").val()==""){
            msg += "<li><strong>First Name</strong> is required</li>"
        }
        if($("#last").val()==""){
            msg += "<li><strong>Last Name</strong> is required</li>"
        }
        if(msg != ""){
            msg = "<p>Please fix the following:</p><ul>" + msg + "</ul>";
            growl("Form Error", msg);
            return false;
        }
        return true;
    })
</script>

ASP.NET MVC Growls

Adding growl notifications to an ASP.NET MVC application involves a couple of steps. First add growl support to your controller base class (create one if you don’t have one).

public abstract class BaseController : Controller
{
    public void Growl(string title, string message)
    {
        TempData["Growl"] = title + "\t" + message;
    }
}

Notice that ‘TempData’ is used instead of ‘ViewData’. This allows growl notifications to live through redirects. Any controller that needs growl support should inherit from this base class.

public ActionResult Index()
{
    Growl("Test", "This is a test");

    return View();
}

Modify your Master Page to include links to the growl CSS and JavaScript. Finally add the following to your Master Page:

<% if(TempData.ContainsKey("Growl")) {
    string growl = (string)TempData["Growl"];
    string[] parts = growl.Split('\t');
%>
<script type="text/javascript">
    growl('<%= parts[0] %>', '<%= parts[1] %>');
</script>
<% } %>

This will add a JavaScript call to the ‘growl’ function if a growl is present.

Summary

This is a pretty simple library. There are more features that can be added. If you give it a test drive, let me know how you like it.

Posted in Uncategorized | 3 Comments

Create a GPS Data Logger Using The Arduino

Recently I have been developing an application that leverages GPS tracking. The high-level concept is to track mobile assets via GPS tracking. Each asset will have a GPS unit installed that logs its location. With the availability of low cost GPS this is becoming an every day reality. Many companies already use GPS to track and monitor their assets. In this post, we explore one option for the GPS tracking hardware.

There are really a two options for GPS tracking hardware: dedicated or shared GPS hardware. There are more and more devices (especially phones) that have GPS hardware. One solution is to write software that can be deployed to these devices and share the common GPS hardware. This is a great solution and I hope to explore this in later blog posts.

The other option is to develop your own dedicated hardware. Staring from scratch can be very daunting and expensive. However, there are a number of developer kits / boards that can spring board your development. In this post, we explore using the Arduino development kit to provide a quick and easy solution to our own dedicated hardware.

Meet The Arduino

After doing some investigation on the internet I selected the Arduino along with a GPS shield as the development hardware. The Arduino is a tool for the design and development of embedded computer systems. It consists of a simple open hardware design for a single-board microcontroller. The Duemilanove Arduino board is shown below:

image

There are two main reasons I chose the Arduino over other options:

  • The main board (shown above) is expanded by plugging in addition hardware called “shields”. There is an abundant number of shield options including a GPS Shield.
  • There is an existing ecosystem (suppliers, shields, libraries) and a strong developer community for the Arduino board and shields.

There is an embedded board that is compatible with the Arduino shields but is programmed using the .NET Micro Framework called the Netduino. The community is growing for this board, but I was not able to find the support that I (an embedded newbie) needed to get going. After I get experience with the Arduino and the GPS shield, I will try to convert it to use the Netduino.

The Arduino IDE

The IDE for Arduino development can be downloaded and come with many examples. Here is a screenshot of the IDE including example code to blink and LED (light emitting diode).

imageAt a basic level,  there are two main functions that a developer needs to “fill in” to get the Arduino working. The ‘setup’ function runs once. The ‘loop’ function repeats as long as the Arduino has power. The ‘setup’ / ‘loop’ combination creates a program called a ‘sketch’. Sketches are uploaded to the Arduino hardware via a USB cable. There are Windows and Mac versions of the IDE.

A developer creates a sketch, uploads it to the Arduino, and debugs the program using the USB as an umbilical cord. Once the program is ready to be deployed, the final version is uploaded and the Arduino can be run off of a 9 volt battery. This workflow is developer friendly and promotes experimentation.

GPS Shield

The GPS shield that I selected not only integrates with a GPS module but also includes data logging to a SD card. One surprise that I had was that the GPS shield looked like this when it came:

image Don’t let this scare you. The soldering is really easy and the instructions are extremely clear. After assembly, the shield looks like the following:

imageThe assembled shield is on the left and the GPS module is on the right. The GPS module plugs into the board and sits on the non-conductive double-sided taped four white pads.

image

On the bottom side of this board (not shown) is the SD card slot. This is used by the embedded system to persist the GPS data streamed from the GPS module.

Programming the Arduino / GPS Shield

The GPS shield site provides all the libraries and step-by-step instructions on programming the GPS shield / Arduino combination. Following these instructions, will have the hardware up and logging GPS data points in very little time. I did not run into any issues and will leave the details to the above site.

Testing

Once I assembled and programmed, I took the Arduino hardware on a test drive. I did not alter the provided Arduino sketch at all. By default, GPS points are logged to the SD card every second. There are suggestions to extend battery life by logging less often and shutting down diagnostic systems. The data is logged in text files. Opening one of these files you will find something like the following:

image

Each “GPRMC” line is the recommended minimum data set and is transmitted by most GPS devices. Each line can be decoded into: timestamp, latitude, longitude, speed, bearing, and status information.

At the GPS Visualizer site you can upload the file and have the data displayed on Google Maps. Here is a screen shot from my short trip:

image

Summary

I found the GPS unit was able to get a fix on the satellites even inside my house.  Overall I am very pleased with this hardware. I will be exploring a bit with this hardware and learning more about the software.

The ultimate goal is to have GPS hardware to collect data for the Truck Tracker application. There is a wireless shield that I think I can add to the board to allow the data logged to the SD card to be wirelessly posted to a web service. For now, I am okay manually uploading the text files.

I am extremely pleased with how easy it was to get started with the Arduino. If you are looking for a simple embedded solution, check out the many examples.

Posted in arduino, geolocation, hardware | 9 Comments

OpenID and OAuth using DotNetOpenAuth in ASP.NET MVC

I have an ASP.NET MVC application that I would like to have both public and private features. Typically this is done by implementing an authentication / authorization gateway to gain access to the private features. Previously I blogged on an implementation using the ASP.NET membership / role providers with an XML-based membership. This blog post will detail how to use OpenID and OAuth to provide an authentication layer.

  • Authentication – You are who you say you are. The application knows your identity.
  • Authorization – Based upon your identity (via Authentication), the application provides access to features. Public access is provided to base features. Private access to enhanced features.

Here is a screencast showing the implementation in action.

For more information on OpenID and OAuth check out these links:

About OAuth

About OpenID

OAuth-OpenID: You’re barking up the wrong tree if you think they’re the same thing

OpenID / OAuth Workflow

The web application starts by presenting an area that allows the user to select between various OpenID / OAuth providers. The following screenshot shows this area.

imageThis provides a mechanism for the user to select one of the OpenId (OpenID, myOpenID, Google, Yahoo) or OAuth (Twitter) providers. Clicking on one of the providers starts the authentication process. Both OpenID and OAuth use a series of redirects to get the user authenticated. The key is that the authentication occurs on the provider’s site and that’s where the passwords are stored. Clicking one of the above providers results in a post to our application’s server. Our server then redirects to the provider’s server (after possible adding information to the post data). Here is a screenshot of the Twitter authentication page after the redirect to the Twitter provider.

imageClicking the “Allow” button causes post to the Twitter servers and another redirect. This time back to our application’s server. This redirect includes information about you that is supplied by the OpenID / OAuth providers. At minimum the redirect supplies a ‘username’ back to the application.

Our application can then look up the ‘username’ in the database to determine if the user is allowed access. Users that are allowed access will have the above login area swapped out for a panel that provides access to features only available to authenticated users. The following screenshot is an example.

imageNow that we have covered the workflow, let’s take a look at some code. Since we have just looked at the presentation layer, let’s start with the ASP.NET MVC views.

Views, CSS and JavaScript

The logic to display either the login screen or the panel with features for authenticated users is in the Master Page. The following code simply looks to determine if the user is authenticated. If not, it inserts the login partial view. Otherwise, it inserts in the panel partial view.

<div id="login">
    <% if (Request.IsAuthenticated) { %>
        <% Html.RenderPartial("_UserPanel"); %>
    <% } else { %>
        <% Html.RenderPartial("_Login"); %>
    <% } %>
</div>

The panel partial view is provided by the following markup.

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<dynamic>" %>

<div id="user-panel-wrap">
    <span class="left"><%= Html.Encode( Session["FullName"] ) %></span>
    <span class="right">
        <ul>
            <li><%= Html.ActionLink("Add Truck", "Add", "Home") %></li>
            <li><%= Html.ActionLink("Log Off", "LogOff", "Account") %></li>
        </ul>
    </span>
</div>

The above code inserts a ‘div’ containing two ‘spans’. The first ‘span’ is ‘floated left’ (via the CSS class left) and contains the user’s full name. The full name is stored in the ‘Session’ dictionary by the Controller (more later). The second ‘span’ is ‘floated right’ (via the CSS class right) and contains an unordered list of links that provide access to features available to authenticated users only. Be sure to mark these action methods with the ‘Authorize’ attribute otherwise users could directly navigate to the URL and access the feature.

The following CSS styles the panel partial view.

.left   { float: left; }
.right  { float: right;}

#user-panel-wrap
{
    background-color: #000;
    margin: 10px 0;
    padding: 10px;
    color: #fff;
    text-align: right;
    overflow: auto;
}
#user-panel-wrap ul
{
    display: inline-block;
    list-style: none;
}
#user-panel-wrap ul li
{
    float: left;
    margin: 3px 10px;
}

The login partial view markup is shown below.

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<dynamic>" %>

<div id="openid-wrap">
    <form id="openid-form" method="post" action="<%= Url.Action("OpenId", "Account") %>">
        <p>Registered users can <strong>view and add private trucks</strong>. Otherwise feel free to browse
        the <strong>public</strong> trucks in the list below.</p>
        <p>Sign in using one of the providers below.</p>
        <div id="openid-providers">
            <ul>
                <li id="openid"></li>
                <li id="myopenid"></li>
                <li id="twitter"></li>
                <li id="google"></li>
                <li id="yahoo"></li>
            </ul>
        </div>
        <div id="other">
            <h3>Your OpendID Provider</h3>
            <input name="openIdUrl" id="openIdUrl" type="text" />
            <a id="signin">Sign In »</a>
        </div>
    </form>
</div>

The outer ‘div’ wraps a ‘form’ area that contains two child ‘div’ elements. The first child ‘div’ contains an unordered list of providers. This will be styled up using CSS and an image sprite to render the button images. The second child ‘div’ provides an ‘input’ text element that allows the user to enter the URL to any OpenID provider. The following CSS styles this partial view.

#openid-wrap
{
    background-color: #000;
    padding: 10px;
    color: #fff;
    margin-bottom: 10px;
}
#openid-wrap p
{
    font-size: 18px;
    text-align: center;
    margin: 5px 140px 14px;
    line-height: 30px;
}
#openid-wrap form
{
    margin: 3px;
}
#openid-wrap div#other
{
    display: none;
    text-align: center;
    margin: 10px 40px;
    padding: 10px;
    color: #000;
    background-color: #ddd;
    border: 1px solid #888;
    font-size: 18px;
}
#openid-wrap div#other h3
{
    color: #333;
    font-weight: bold;
    margin: 0 0 3px 0;
}
#openid-wrap input
{
    border: 2px solid #fba424;
    height: 36px;
    width: 500px;
}
#openid-wrap div#other a
{
    background-color: #333;
    color: #eee;
    border: 1px solid #666;
    padding: 10px 15px;
    display: inline-block;
}
#openid-wrap div#other a:hover
{
    background-color: #222;
    color: #fff;
    text-decoration: none;
    cursor: pointer;
}
#openid-providers
{
    overflow: auto;
    text-align: center;
}
#openid-providers ul
{
    display: inline-block;
    list-style: none;
}
#openid-providers li
{
    margin: 10px;
    padding: 0;
    float: left;
    width: 150px;
    height: 50px;
    background: transparent url('../images/openid_sprite.png') no-repeat 0 0;
}
li#openid       { background-position: 0 0; }
li#myopenid     { background-position: 0 -50px; }
li#twitter      { background-position: 0 -100px; }
li#facebook     { background-position: 0 -150px; }
li#google       { background-position: 0 -200px; }
li#yahoo        { background-position: 0 -250px; }
li#openid:hover       { background-position: -150px 0; cursor: pointer; }
li#myopenid:hover     { background-position: -150px -50px; cursor: pointer; }
li#twitter:hover      { background-position: -150px -100px; cursor: pointer; }
li#facebook:hover     { background-position: -150px -150px; cursor: pointer; }
li#google:hover       { background-position: -150px -200px; cursor: pointer; }
li#yahoo:hover        { background-position: -150px -250px; cursor: pointer; }

Towards the bottom the background image sprite for the provider buttons is set and individual offsets / hover effects are configured. Here is the image sprite that I am using.

openid_spriteThe left column is the normal button faces and the right column provides a subtly different (maybe too subtle) hover image.

The glue that makes this view work is the following JavaScript (using jQuery of course).

<script type="text/javascript">
    var providers = {
        myopenid: { action: '<%= Url.Action("OpenId", "Account") %>', url: 'http://myopenid.com' },
        twitter: { action: '<%= Url.Action("OAuth", "Account") %>' },
        facebook: { action: '<%= Url.Action("OpenId", "Account") %>', url: 'http://facebook.com' },
        google: { action: '<%= Url.Action("OpenId", "Account") %>', url: 'http://www.google.com/accounts/o8/id' },
        yahoo: { action: '<%= Url.Action("OpenId", "Account") %>', url: 'http://yahoo.com' }
    };
    $("#openid").click(function () {
        toggleOther();
    });
    $("#signin").click(function () {
        $("#openid-form").submit();
    });

    $("li").not("#openid").click(function () {
        $("#other").hide(500);
        isHidden = true;
        var id = $(this).attr("id");
        var provider = providers[id];
        if (provider.action != undefined) {
            $("#openid-form").attr("action", provider.action);
        }
        if (provider.url != undefined) {
            $("#openIdUrl").val(provider.url);
        }
        $("#openid-form").submit();
    });

    var isHidden = true;
    function toggleOther() {
        if (isHidden) {
            $("#other").slideDown(500);
        } else {
            $("#other").slideUp(500);
        }
        isHidden = !isHidden;
    }

</script>

The first bit of JavaScript creates a JSON object containing provider information. Each provider can have an ‘action’ and/or a ‘url’ member. The ‘action’ member defines the URL that the ‘form’ should post to when submitted. Notice there are different URLs for OpenID and OAuth. The ‘url’ member provides the URL to the OpenID provider.

The ‘toggleOther’ method (at the bottom) hides or shows the ‘div’ with the ID ‘other’ by using a slide up/down animation. The essence of the above JavaScript is to set the ‘input’ text box to contain the appropriate URL to the OpenID provider and then submit the form to the desired action method. This is done in the click handler for the ‘li’ elements and uses the JSON object.

Controller

Before discussing the action methods of the controller, you will need to get the DotNetOpenAuth library. Once you download it add a reference to it from your web application project. If you want to get twitter connected up be sure to also download the ‘TwitterConsumer’ and ‘InMemoryTokenManager’ implementations. These implementations are C# code files that you will need to add to your project as well.

I have named the controller ‘AccountController’ and the following code shows the constructor and private fields.

static private readonly OpenIdRelyingParty Openid = new OpenIdRelyingParty();
static private readonly InMemoryTokenManager TokenManager
        = new InMemoryTokenManager("consumerKey", "consumerSecret");

private readonly IFormsAuthentication _formsAuth;
private readonly IIntKeyedRepository<User> _userRepository;
private readonly IUnitOfWork _unitOfWork;
private readonly ILogger _logger;

public AccountController(
    IFormsAuthentication formsAuthentication,
    IIntKeyedRepository<User> userRepository,
    IUnitOfWork unitOfWork,
    ILogger logger)
{
    _formsAuth = formsAuthentication;
    _userRepository = userRepository;
    _unitOfWork = unitOfWork;
    _logger = logger;
}

The application uses Ninject as a dependency injection container (thus the missing parameterless controller constructor). Ninject will provide implementations of all the constructor parameters. References to these parameters are then tucked away into the ‘readonly’ fields.

The ‘OpenIdRelyingParty’ instance is an object implemented by the DotNetOpenAuth library that is used for the OpenID authentication. The ‘InMemoryTokenManager’ is used for OAuth authentication with Twitter. Before you can use Twitter as an OAuth provider, you must register your app with Twitter. As a result of this registration Twitter will issue a ‘consumerKey’ and a ‘consumerSecret’ to substitute as the ‘InMemoryTokenManager’ parameters.

From our JavaScript discussions remember that OpenID and OAuth are submitted to two separate action methods. First let’s look at the action method that handles OpenID authentication.

public ActionResult OpenId(string openIdUrl)
{
    var response = Openid.GetResponse();
    if (response == null)
    {
        // User submitting Identifier
        Identifier id;
        if (Identifier.TryParse(openIdUrl, out id))
        {
            try
            {
                var request = Openid.CreateRequest(openIdUrl);
                var fetch = new FetchRequest();
                fetch.Attributes.AddRequired(WellKnownAttributes.Contact.Email);
                fetch.Attributes.AddRequired(WellKnownAttributes.Name.First);
                fetch.Attributes.AddRequired(WellKnownAttributes.Name.Last);
                request.AddExtension(fetch);
                return request.RedirectingResponse.AsActionResult();
            }
            catch (ProtocolException ex)
            {
                _logger.Error("OpenID Exception...", ex);
                return RedirectToAction("Login");
            }
        }
        _logger.Info("OpenID Error...invalid url. url='" + openIdUrl + "'");
        return RedirectToAction("Login");
    }

    // OpenID Provider sending assertion response
    switch (response.Status)
    {
        case AuthenticationStatus.Authenticated:
            var fetch = response.GetExtension<FetchResponse>();
            string firstName = "unknown";
            string lastName = "unknown";
            string email = "unknown";
            if(fetch!=null)
            {
                firstName = fetch.GetAttributeValue(WellKnownAttributes.Name.First);
                lastName = fetch.GetAttributeValue(WellKnownAttributes.Name.Last);
                email = fetch.GetAttributeValue(WellKnownAttributes.Contact.Email);
            }
            return CreateUser(response.ClaimedIdentifier, firstName, lastName, email);
        case AuthenticationStatus.Canceled:
            _logger.Info("OpenID: Cancelled at provider.");
            return RedirectToAction("Login");
        case AuthenticationStatus.Failed:
            _logger.Error("OpenID Exception...", response.Exception);
            return RedirectToAction("Login");
    }
    return RedirectToAction("Login");
}

This action method is called twice. The first time by our form being submitted by the user. The second time is a call back (redirect) from the OpenID provider. The first two lines of the method determine which stage we are in. The code inside the ‘if’ statement is executed when the user submits the form. This code creates an OpenID request and redirects to the OpenID provider. Notice that we are requesting first and last names along with an email address. If the user has configured their OpenID provider to share this info it will be available to us.

The OpenID provider then redirects their response back to our action method. This time, there will be a value for the ‘response’ The code inside the ‘switch’ statement processes that response. If the user is authenticated, the username, first & last name and email are send to the following ‘CreateUser’ action method.

private ActionResult CreateUser(string userName, string firstName, string lastName, string email)
{
    User user = _userRepository.FindBy(x => x.UserName == userName);
    if(user==null)
    {
        user = new User
                   {
                       UserName = userName,
                       FirstName = firstName,
                       LastName = lastName,
                       Email = email
                   };
        return View("Create", user);
    }
    Session["UserName"] = userName;
    string fullName = user.FirstName + " " + user.LastName;
    Session["FullName"] = fullName;
    _formsAuth.SignIn(fullName, false);
    return RedirectToAction("Index", "Home");
}

This code checks to see if this user exists in the local database. If the user is not found, the ‘Create’ view is sent to the browser. This gives our application an opportunity to collect and validate the first & last name and email values. I will not show that view because it becomes application specific as to what additional information you collect from each user. I will also not show the action method that the ‘Create’ view posts back to.

If after the OpenID authentication the user was found in the database, the ‘username’ and ‘fullname’ are stored in the ‘Session’ cache, the user is signed in (cookie set) and a final redirect back to the ‘Index’ action method of the ‘Home’ page. This results in showing the panel that provides access to features only available to authenticated users.

The OAuth action methods are shown below. The ‘OAuth’ action method is called when the user submits the form. This uses the DotNetOpenAuth library to redirect (on the Channel.Send method) to the OAuth provider. Notice this code explicitly configures the callback URL.

public ActionResult OAuth(string returnUrl)
{
    var twitter = new WebConsumer(TwitterConsumer.ServiceDescription, TokenManager);
    var callBackUrl = new Uri(Request.Url.Scheme + "://" + Request.Url.Authority + "/Account/OAuthCallback");
    twitter.Channel.Send(twitter.PrepareRequestUserAuthorization(callBackUrl, null, null));

    return RedirectToAction("Login");
}

public ActionResult OAuthCallback()
{
    var twitter = new WebConsumer(TwitterConsumer.ServiceDescription, TokenManager);
    var accessTokenResponse = twitter.ProcessUserAuthorization();
    if(accessTokenResponse!=null)
    {
        string userName = accessTokenResponse.ExtraData["screen_name"];
        return CreateUser(userName, null, null, null);
    }
    _logger.Error("OAuth: No access token response!");
    return RedirectToAction("Login");
}

The OAuth provider then redirects to the specified callback URL (‘OAuthCallback’ in this case) where the response is processed. A similar process is followed as in the OpenID case. Authenticated responses use the ‘CreateUser’ action method (same as for OpenID and shown above).

Summary

Integrating OpenID and OAuth into your application is made very easy by using the DotNetOpenAuth library. There are a number of services popping up that provide a clean implementation of OpenID / OAuth authentication that you can pay to include in your project. The advantage is that they will maintain the compatibility with OpenID / OAuth as it evolves and are able to provide you statistics on access to your site. Otherwise, using the DotNetOpenAuth library and wiring things up your self is not that bad. If you find the DotNetOpenAuth library beneficial and if you feel so inclined to give back, they provide a way to donate on their page.

Posted in asp.net, mvc, security | 25 Comments

A Rubber Band Selection Highlight Box For The Web

I recently released a web presentation framework that includes a handy highlighting feature. Below is a video of the highlighting feature in action.

I also provided a ‘bookmarklet’ that you can save to enable this feature on any web page. Let’s examine how this effect was created using HTML, CSS, and magic. Okay not really magic, I have used jQuery but sometimes that is close enough.

Concept

To created the highlight effect we use four transparent overlays that cover the areas that surround the area we want to highlight.

image

The area to highlight is set using the mouse to click and drag a ‘rubber banding box’. The overlays are then dynamically positioned.

HTML

The HTML elements that are needed to create this effect are provided by the following markup.

<div id="topmask" class="highlight-mask"></div>
<div id="leftmask" class="highlight-mask"></div>
<div id="rightmask" class="highlight-mask"></div>
<div id="bottommask" class="highlight-mask"></div>
<div id="dragmask" class="highlight-drag"></div>

The top four elements in the above markup define the four masks (top, right, bottom, left) and the last element is used to create the ‘rubber banding box’.

CSS

The above markup is styled using the following:

.highlight-mask
{
    background: transparent url('../images/theme/transBlack75.png') repeat 0 0;
    display: none;
    position: absolute;
}
.highlight-drag
{
    background-color: transparent;
    border: dashed #ff3333 3px;
    position: absolute;
    display: none;
}

All the elements are initially hidden and will be absolutely positioned using jQuery (see below). The mask areas use an image to create the transparent effect. The image is simply a 10×10 pixel square filled with black (#000000) with a 25% transparency (mostly opaque). The ‘rubber banding box’ has a transparent background and a 3 pixel wide dashed red (#ff3333) border.

JavaScript / jQuery

This effect is dynamically created using JavaScript. There are many times that a user may click and drag on a web page. We want to have a specific key combination to enable the highlighter. I have selected the SHIFT key as the enabler. So holding the SHIFT key while click and dragging is the mechanism of creating a highlight region. The highlight region is removed by pressing the ESC key. The following code enables enables the highlighter by monitoring the SHIFT key (keyCode = 16).

var isHighlightEnabled = false;
$(document).keydown(function(event){
    if(event.keyCode==16){
        // enable the highlighter
        isHighlightEnabled = true;
    }
});
$(document).keyup(function(event){
    if(event.keyCode==16){
        // disaable the highlighter
        isHighlightEnabled = false;
    }
    else if(event.keyCode==27){
        // hide the highlighter divs
        $(".highlight-mask").hide();
        $("#dragmask").hide();
    }
});

When the SHIFT key is pressed, the highlighter is enabled and when the SHIFT key is released the highlighter is disabled. The above code also monitors the ESC key (keyCode = 27) and hides the highlighter elements if the key is released.

The mouse events are used to define the highlighter region. The ‘mousedown’, ‘mousemove’, and ‘mouseup’ events are all used. The ‘mousedown’ event begins the highlight process.

var startX, startY;
var isDragging = false;
$(document).mousedown(function(event){
    if(isHighlightEnabled){
        startX = event.pageX;
        startY = event.pageY;
        isDragging = true;
        $("#dragmask").css(
            {
                'left'   :    startX,
                'top'    :    startY,
                'width'  :    0,
                'height' :    0
            }

        ).show();
        // prevent default behavior of text selection
        return false;
    }
});

If the SHIFT key is pressed a ‘mousedown’ saves the current mouse position (event.pageX and event.pageY), sets the ‘isDragging’ flag, shows the ‘rubber banding div’ and finally prevents the default behavior. The default behavior includes selecting text on the page and this degrades the highlighter experience.

$(document).mousemove(function(event){
    if(isDragging){
        var left, top, width, height;
        if(event.pageX>startX){
            left = startX;
            width = event.pageX - startX;
        }
        else {
            left = event.pageX;
            width = startX - event.pageX;
        }
        if(event.pageY>startY){
            top = startY;
            height = event.pageY - startY;
        }
        else {
            top = event.pageY;
            height = startY - event.pageY;
        }
        $("#dragmask").css(
            {
                'left'   :    left,
                'top'    :    top,
                'width'  :    width,
                'height' :    height
            }
        );
    }
});

The ‘mousemove’ code updates the ‘rubber banding’ div position and size to track the current mouse position. The above code will keep one corner pinned at the position where the ‘mousedown’ event occurred, and dynamically position the opposite corner to the current position.

$(document).mouseup(function(event){
    if(isDragging){
        isDragging = false;
        $("#dragmask").hide();
        var screenWidth = $(document).width();
        var screenHeight = $(document).height();
        var topOfHighlight, bottomOfHighlight;
        if(event.pageY>startY){
            topOfHighlight = startY;
            bottomOfHighlight = event.pageY;
        }
        else{
            topOfHighlight = event.pageY;
            bottomOfHighlight = startY;
        }
        var leftOfHighlight, rightOfHighlight;
        if(event.pageX>startX){
            leftOfHighlight = startX;
            rightOfHighlight = event.pageX;
        } else {
            leftOfHighlight = event.pageX;
            rightOfHighlight = startX;
        }
        //position the top mask
        $("#topmask").css(
            {
                'left'    :    0,
                'width'   :    screenWidth,
                'top'     :    0,
                'height'  :    topOfHighlight
            }
        ).show();
        // position the bottom mask
        $("#bottommask").css(
            {
                'left'    :    0,
                'width'   :    screenWidth,
                'top'     :    bottomOfHighlight,
                'height'  :    screenHeight - bottomOfHighlight
            }
        ).show();
        // position the left mask
        $("#leftmask").css(
            {
                'left'    :    0,
                'width'   :    leftOfHighlight,
                'top'     :    topOfHighlight,
                'height'  :    bottomOfHighlight - topOfHighlight
            }
        ).show();
        // position the right mask
        $("#rightmask").css(
            {
                'left'    :    rightOfHighlight,
                'width'   :    screenWidth - rightOfHighlight,
                'top'     :    topOfHighlight,
                'height'  :    bottomOfHighlight - topOfHighlight
            }
        ).show();
    }
});

When the mouse is released the ‘mouseup’ event hides the ‘rubber banding’ box and position/shows each of the transparent overlay masks.

Summary

The code above creates a nice web-based highlighter tool. However, the ability to display a ‘rubber banding selection box’ is useful in many scenarios. For instance, you could use this technique to select a region on an image that would define a zoom.

Posted in css, html, jQuery, javascript | Leave a comment