Click here to Skip to main content
Click here to Skip to main content
Go to top

Exploring Opportunities for the Cloud: Part 2

, 20 Jan 2011
Rate this:
Please Sign up or sign in to vote.
A series of articles exploring Azure development featuring Bing Maps and phone.

Introduction

This is the second article in a series describing my experience exploring the new realm of cloud development. It's predicted that within just a couple of years, over a third of all development will be cloud based. So it makes sense that we should become familiar with that environment if we don't want to be left behind. My approach to learning new technologies is to envision their application. Specifically, I try to look at how they might be applied to solving business problems. I think there is a tremendous number of opportunities for business ventures utilizing the cloud. For the sake of providing some concrete examples and to provide some focus to the discussion, I've decided to make Bing Maps services a central theme of the business scenarios discussed in these articles. And to make things a little more interesting, I'm really focusing on business scenarios that would make use of Bing Maps services and phone as part of the solution. The reason being that, in my opinion, phone will be a major player in business solutions developed for the cloud.

The previous article provided information on getting started with Bing Maps services as well as setting up the application structure that we wanted to follow. In this article, we get down to the nitty-gritty and demonstrate how we can add functionality to the basic map control. At the same time, we discuss some typical business scenarios that could benefit from the functionality being presented.

To the Cloud

Let's start by first changing the current solution so that it is hosted on Azure. You'll need to download and install the Windows Azure SDK if you have not done it already. You can find everything you need for Azure here. Once you've installed the SDK, you'll have access to a new 'cloud' project template in Visual Studio. On the Solution Explorer tab, right click to add a new project. And on the new project dialog, select 'cloud' and name it "SLAzureMapTest". Then in the subsequent role selection dialog, simply click OK without selecting any roles. This will create the project without any roles and we can use the existing Web project.

You'll see the newly created project in Solution Explorer but with an empty Role folder. Right click on the folder to add a new role, as shown below:

AzureWebRoleAssignment.png

In the subsequent dialog, you should see the existing SLMapTest.Web project, so select it to make the association. That is all that's needed to take an existing Web project and modify it for hosting on Azure.

If you re-compile and try to run the application, you'll get a message that says that you need to start Visual Studio as Administrator in order to run the application. So from now on, always start Visual Studio as Administrator for this project.

I've made some minor structural changes to the project which we started in the previous article. Nothing major, just factored out the map view which we had on the main page into a separate control. This means that there are also new entries for the View:ViewModel association. But that's all the change that I've made. In the download, I've included a revised version which you can use as the starting point if you want to follow along with the code or see the revised code.

The First Baby Step

OK, so let's start by adding some user interaction with the map. The first thing we'll do is allow the user to click on the map and we'll provide some feedback in the form of data associated with the clicked location. The map services can only relate to geo coordinates (latitude/longitude), but our view mouse clicks are in screen coordinates, so we have to translate between the two. Luckily for us, the map control exposes a method that provides just that translation!

Start by creating a mouse click event handler in the code-behind. Since we have to have access to the map control for the translation and we are going to be doing some UI rendering, it fits there.

So, to be able to draw on the map, we make use of MapLayers. These are types exposed by the map control, and are essentially overlays on the map. We'll start with an overlay to identify where the user clicked, and we'll add additional layers later to segregate different types of information on the display. Here's the change for the XAML file that shows the SelectionLayer.

... 
<m:Map x:Name="bingMap" CredentialsProvider="YourKey">
<m:MapLayer x:Name="SelectionLayer"/>
...

And the change to the code-behind file for the click event handler is as follows:

public SLMapView()
{
    InitializeComponent();
    //An event handler for the mouse clicks...
    bingMap.MouseClick += 
      new EventHandler<MapMouseEventArgs>(bingMap_MouseClick);
    //Subscribe to message, we know what to do with user input
    Messenger.Default.Register<SetMapViewMsg>(this, SetViewHandler);
}

void bingMap_MouseClick(object sender, MapMouseEventArgs e)
{
    Location pointLocation = 
      bingMap.ViewportPointToLocation(e.ViewportPoint);
    Rectangle r = new Rectangle();
    r.Fill = new SolidColorBrush(Colors.Red);
    r.Stroke = new SolidColorBrush(Colors.Yellow);
    r.StrokeThickness = 1;
    r.Width = 8;
    r.Height = 8;

    SelectionLayer.Children.Clear();
    SelectionLayer.AddChild(r, pointLocation);
    //Pass the translated point to request reverse geocoding
    Messenger.Default.Send<MapPointClickMsg>(
       new MapPointClickMsg() { ClickLocation = pointLocation });
}

You can add UI elements to the MapLayer just like any other rendering surface. If you compile and run, you'll see the results below. You'll note that the user can scroll the view and change zoom levels and the selected location remains displayed correctly. Of course, you can change the rendering to be whatever is appropriate. How about a push-pin? And of course, it doesn't have to be as a result of a click. You may have a collection of items that you want to display at known locations. The point is that you can draw anything on the map and associate it with a physical location.

ClickPointRendering.png

The code above provides a hint as to what we want to do next. In the event handler, we are sending a message (to whomever subscribed, nobody yet) and passing the geo coordinates of the clicked location. What we want to do next is display the street address that corresponds to the location that the user clicked, if one exists. Of course, we have to determine what that address is. But before we embark on that, let's add an important feedback feature to the user interface.

Patience Young Grasshopper

When dealing with network communication, there is one thing that is guaranteed, and that is that the response time is unpredictable. In our application, we are making asynchronous calls to services which will undoubtedly have varying response times due to various network issues. In order to control the state of the application and also to provide feedback to the user, we need to provide some indication to the user that some lengthy activity is taking place. In searching to see what might be available, I came across this control which David Poll developed and has shared with the community. The control behaves as an activity indicator for an application. It is very flexible and pretty intuitive to use. You can download the source and all related information from here. To use it, simply wrap the desired UI area with the control and then just toggle a flag to display/hide the busy indicator and enable/disable user interaction. In the code shown below, the whole MainPage is wrapped with the control.

...
  xmlns:activity="clr-namespace:System.Windows.Controls;assembly=ActivityControl"

  xmlns:ctl="clr-namespace:SLMapTest.View"
  mc:Ignorable="d"
  MinHeight="300" MinWidth="300"
  DataContext="{Binding Source={StaticResource Locator}, Path=ViewModelMain}">

Now anytime we are making a call to the service, we set the flag to show that we are busy, and clear the flag when a response is received from the service.

Where Are You At?

OK, so now, let's show some information to the user associated with the location of the click. The information will be the address closest to the clicked location. To do that, we'll need to add some fields to the view to display the address. The revised MainPage showing the resulting functionality is shown below:

ClickResponseData.png

So in the click message handler shown previously, we are sending out a message containing the coordinates of the clicked location. But there is no one listening, so let's add a listener. SLMapViewModel is the one that knows how to call the Bing service so that's where we will add a subscription to the message. When we get the results back, we'll publish a corresponding message with the results. And since we are binding the controls on the MainPage to the MainViewModel, that's where we will add the subscription to the response message. So let's start with the call to the service as a response to MapPointClickMsg. First, we register for the message and provide a handler:

public SLMapViewModel()
{
   ...
   //Register to receive message when user clicks on the map
   Messenger.Default.Register<MapPointClickMsg>(this, MapClickHandler);
}

void MapClickHandler(MapPointClickMsg msgData)
{
    ReverseGeocode(msgData.ClickLocation);
}

The Bing Maps service that we used last time exposes an additional method that provides the reverse to the geocode method. It is appropriately called ReverseGeocodeAsync, and it returns an address (if one exists) for a given location coordinate. So it does the exact opposite of what we did previously. Again, as before, since it's an asynchronous call, we need to provide a callback handler where we can process the results of the call. Here's the rest of the code along with a definition of a message used to publish the result from the call:

private void ReverseGeocode(Location pointLocation)
{
    //Pack up a request
    BingGeocodeService.ReverseGeocodeRequest request = 
                 new BingGeocodeService.ReverseGeocodeRequest();
    // Don't raise exceptions.
    request.ExecutionOptions = new BingGeocodeService.ExecutionOptions();
    request.ExecutionOptions.SuppressFaults = true;

    request.Location = pointLocation;

    request.Credentials = new Credentials();
    request.Credentials.ApplicationId = 
       (string)App.Current.Resources["BingCredentialsKey"];

    // Make asynchronous call to fetch the data
    GeocodeClient.ReverseGeocodeAsync(request);
}
void geocodeClient_ReverseGeocodeCompleted(object sender, 
     BingGeocodeService.ReverseGeocodeCompletedEventArgs e)
{
    string callResult = "";
    try
    {
        if (e.Result.ResponseSummary.StatusCode != 
                     BingGeocodeService.ResponseStatusCode.Success ||
            e.Result.Results.Count == 0)
        {
            callResult = "Can't find it!";
        }
        else
        {
            //Publish results, somebody will know what to do with it
            ReverseGeocodeResultMsg resultMsg = new ReverseGeocodeResultMsg()
            {
                StreetAddress = e.Result.Results[0].Address.AddressLine,
                City = e.Result.Results[0].Address.Locality,
                State = e.Result.Results[0].Address.AdminDistrict
            };
            Messenger.Default.Send<ReverseGeocodeResultMsg>(resultMsg);
        }
    }
    catch
    {
        callResult = "Error processing request.";
    }

    resultString = callResult;
    this.RaisePropertyChanged("ResultString");
}
public struct ReverseGeocodeResultMsg
{
    public string StreetAddress;
    public string City;
    public string State;
}

Now in the MainViewModel, we subscribe to the ReverseGeocodeResultMsg message so we can update the display with the data that was returned from the call to the service.

public MainViewModel()
{
    //Subscribe to the message, we know what to do
    Messenger.Default.Register<ReverseGeocodeResultMsg>(
                      this, ReverseGeocodeMessageHandler);
}
#region messenger message handler
void ReverseGeocodeMessageHandler(ReverseGeocodeResultMsg msgData)
{
    currentSelection = msgData;
    this.RaisePropertyChanged("Address");
    this.RaisePropertyChanged("City");
    this.RaisePropertyChanged("State");
}
#endregion

And that's it. If you compile and run the application, you'll see the results shown above. I've included a second project in the download that contains all the source for this version. Still, nothing terribly impressive so far. But we already know how to process user interaction with the map, we can translate a user mouse click position to latitude/longitude coordinates, we can render figures on the map at specific latitude/longitude coordinates, and now we can retrieve address information associated with these coordinates. So that's already quite a bit of functionality. However, the really interesting aspects (at least for me) come when you create a unique solution to a common business problem. Let's continue by taking the core functionality we've learned and add some additional functionality that could then be applied to real world business scenarios.

Route Delivery Business Scenarios

I think there are numerous opportunities for cloud based solutions that can benefit from the functionality we've been describing. One such category of businesses centers around product distribution. The milk that gets delivered to your corner grocery store or convenience store is delivered by a company in this category. The magazines and candy at the checkout aisles are typically managed by outside companies that service the racks. The soda machines that you see around campus, at the rest areas, and many other locations, are serviced by companies in this category. You'll often see Pepsi or Budweiser trucks parked at a store, they are making their delivery rounds. I can continue, but you can see that there are plenty of examples of these types of businesses. All of these companies have processes that are similar in nature. For one thing, they all have one or more products that are being delivered to locations. The delivery is being made by a driver that normally follows a specific route on a periodic schedule. The stops (locations) on the route are arranged in order to minimize the time required to complete the deliveries.

Now, it goes without saying that simply providing driving directions does not make a business solution. Any solution needs to encompass more of the business processes in order to provide a benefit to the business enterprise. And that benefit is usually in the form of cost reductions, it's always about the bottom line. If a solution can make the business more profitable by optimizing their operations and reducing their cost (less wrong deliveries, less product damage, etc.), you've got a sale. And I'll add that using phone as part of the solution facilitates a whole new world of cost reducing opportunities.

So one component of any solution targeted at these business entities has to include a route editor. A utility that will allow the business the ability to define their area of service. A route is the path that a particular driver will traverse to deliver a product. A route, in turn, is a collection of one or more route segments. And a route segment is a continuous stretch of the same road or street. When you get back driving directions from Bing, it is in the form of a bunch of route segments. However, those segments have finer granularity because they are used as driving instructions to humans. For our consideration, we won't require as much detail.

As we said above, one requirement that is common for all of these applications is to allow the business entity to define a set of routes that comprises the territory of service. And that's what we want to accomplish now. First, we'll create an entity definition for a route segment. Then we'll provide the user interface to allow the user to define new segments that form a route. We'll add route management later.

X Marks the Spot

The following screen shows the user interface as modified for our demo project. You can see the complete source code for the project in the final version of the project included in the download.

XMarksTheSpot1.png

So we want to be able to provide the user with the ability to define a route which is a collection of route segments. And a route segment is simply a contiguous portion of a street or road. We define a route segment to have the following properties:

public class RouteSegment
{
    public int ID { get { return id; } }
    public int RouteID { get; set; }
    public string StreetName { get; set; }
    public int StartNumber { get; set; }
    public int EndNumber { get; set; }
    public Location StartXStreet { get; set; }
    public Location EndXStreet { get; set; }
    public List<Location> PlotPoints { get { return plotPoints; } }
    List<Location> plotPoints;
    int id;
    public RouteSegment(int id)
    {
        this.id = id;
        plotPoints = new List<Location>();
    }
    public override string ToString()
    {
        return StreetName + "(" + StartNumber + "-" + EndNumber + ")";
    }
}

In our demo project (shown above), the user can define segments simply by selecting a street on the map which specifies the segment (name). Then the 'boundaries' of the segment are specified by selecting the start and end intersecting streets. We've seen how to get the coordinates of addresses by using the GeocodeAsync method of the map service. To get the coordinates of an intersection, all that is needed is to adjust the format of the query that we present to the map service. In place of the street address, we'll pass in the names of the intersecting streets. For example, "38th St & Hudson Ave" will return the coordinates for the intersection of 38th Street and Hudson Avenue. Here's how we handle the user pressing the StartX button to set the current selection as the start intersection.

void SetStartXStreetClick()
{
    //Cross street name can't be same as segment street
    string streetName = GetCurrentSelectionStreet();
    if (streetName != currentSegment.StreetName)
    {
        //Get intersection, if exists
        Messenger.Default.Send<GetStreetIntersectionMsg>(
                  new GetStreetIntersectionMsg()
        {
            SegmentStreet = currentSegment.StreetName,
            XStreetName = streetName,
            XCity = currentSelection.City,
            XState = currentSelection.State
        });
    }
    else
    {
        Messenger.Default.Send<UserActionAlertMsg>(
              new UserActionAlertMsg() { AlertText="Streets are same!"});
    }
}

Because we want only the street name, we make use of a helper method, GetCurrentSelectionStreet, which strips out the address number. We then compose a message since the service is being hosted by SLMapViewModel. Since we are making a request from two different sources, and the calls to the service are asynchronous, we pass a token along with the call to enable us to determine what to do when we get the response. That's the purpose for the RequestType indicated below and in the callback.

void StreetIntersectionHandler(GetStreetIntersectionMsg msgData)
{
    GeocodeAddress(msgData.XStreetName + " & " + msgData.SegmentStreet + 
       "," + msgData.XCity + "," + msgData.XState, RequestType.XRequest);
}
...
private void GeocodeCompleted(object sender, 
             BingGeocodeService.GeocodeCompletedEventArgs e)
{
    //Clear busy flag...
    showBusy = false;
    this.RaisePropertyChanged("IsBusy");

    string callResult = "";
    Location xLocation = new Location();
    string xStreets = "";
    bool foundIntersection = false;

    try
    {
        //Was the service able to parse it? And did it return anything?
        if (e.Result.ResponseSummary.StatusCode != 
                      BingGeocodeService.ResponseStatusCode.Success ||
            e.Result.Results.Count == 0)
        {
            if ((RequestType)e.UserState == RequestType.FindRequest)
                callResult = "Can't find it!";
            else
                Messenger.Default.Send<StreetIntersectionResultMsg>(
                                     new StreetIntersectionResultMsg());
        }
        else
        {
            //What are we getting back?
            if ((RequestType)e.UserState == RequestType.FindRequest)
            {
                Location geoLocation = new Location(
                  e.Result.Results[0].Locations[0].Latitude, 
                  e.Result.Results[0].Locations[0].Longitude);
                // Zoom the map to the desired location
                Messenger.Default.Send<SetMapViewMsg>(
                  new SetMapViewMsg() { CenterLocation = geoLocation });
            }
            else
            {
                xLocation = e.Result.Results[0].Locations[0];
                xStreets = e.Result.Results[0].Address.AddressLine;
                foundIntersection = true;

                StreetIntersectionResultMsg result = 
                          new StreetIntersectionResultMsg();
                result.IntersectionLocation = xLocation;
                result.Intersection = xStreets;
                result.StreetsIntersect = foundIntersection;
                Messenger.Default.Send<StreetIntersectionResultMsg>(result);
            }
        }
    }
    catch
    {
        callResult = "Error processing request.";
    }

    resultString = callResult;
    this.RaisePropertyChanged("ResultString");
}

Once we have the coordinates for the intersection, we save the information and draw an 'X' at the intersection as feedback to the user. And we already know how to draw things on the map.

void GetIntersectionMessageHandler(StreetIntersectionResultMsg msgData)
{
    //Start or end intersection?
    if (definitionState == SegmentDefinitionStates.StartXStreet)
    {
        if (msgData.StreetsIntersect)
        {
            currentSegment.StartXStreet = msgData.IntersectionLocation;
            //Plot an 'X' at the intersection
            Messenger.Default.Send<PlotIntersectionMsg>(
              new PlotIntersectionMsg(){ IntersectionLocation = 
              msgData.IntersectionLocation});
            definitionState = SegmentDefinitionStates.EndXStreet;
        }
        else
        {
            //Tell user that the selected street does not intersect segment street
            Messenger.Default.Send<UserActionAlertMsg>(
              new UserActionAlertMsg() { AlertText = "Streets do not intersect!" });
        }
    }
    else
    ...
}

The Way

There is one last piece to figure out and we'll have the basic functionality for a route editor. Once the user has selected the start and end intersections, we need to draw the route on the map. Yes, we know how to draw anything on the map, which means we can easily draw a line. But we need to show 'navigable' paths. In other words, we can't show a path that cuts through buildings or crosses rivers where there are no roads. So we need to draw a path along a route that can be walked or driven. One possible way to do this is to force the user to specify all intersections along the path. Then we could simply draw lines connecting those points. This doesn't work because streets are normally not always built as straight lines. The solution, fortunately, comes from using another Bing Maps service: Route Service. Once we know the start and end coordinates, we can simply pass them to the route service and we'll get back a collection of coordinates that corresponds to the path to follow. These will correspond to center street coordinates and can be used to draw the path. As many points as necessary will be returned to ensure that we can draw lines that lie on the center of the street that is being followed.

Continuing with our demo project, right click on Service References to add a service proxy as we did for the geocode service. For the WSDL address, type in: http://staging.dev.virtualearth.net/webservices/v1/routeservice/routeservice.svc?wsdl. And for the namespace, change the default to BingRouteService and don't forget about the Advanced button to eliminate the name clashes. Since we'll be using this service in MainViewModel, we'll add a member property there.

private BingRouteService.RouteServiceClient RouteClient
{
    get
    {
        if (null == routeClient)
        {
            BasicHttpBinding binding = 
              new BasicHttpBinding(BasicHttpSecurityMode.None);
            UriBuilder serviceUri = new UriBuilder("http://dev.virtualearth.net/" + 
                       "webservices/v1/routeservice/routeservice.svc");

            //Create the Service Client
            routeClient = new BingRouteService.RouteServiceClient(binding, 
                              new EndpointAddress(serviceUri.Uri));
            routeClient.CalculateRouteCompleted += 
              new EventHandler<BingRouteService.CalculateRouteCompletedEventArgs>(
              routeClient_CalculateRouteCompleted);
        }
        return routeClient;
    }
}

As you can see, we also defined the callback method for the asynchronous call. Here's the code for the helper method that packages the request for the call to the service:

private void GetRouteSegmentPlot(Location startLocation, 
             Location endLocation, int segmentID)
{
    BingRouteService.RouteRequest request = 
              new BingRouteService.RouteRequest();

    request.Waypoints = new ObservableCollection<BingRouteService.Waypoint>();
    BingRouteService.Waypoint start = new BingRouteService.Waypoint();
    start.Location = new Location();
    start.Location.Latitude = startLocation.Latitude;
    start.Location.Longitude = startLocation.Longitude;
    start.Location.Altitude = startLocation.Altitude;
    request.Waypoints.Add(start);
    BingRouteService.Waypoint end = new BingRouteService.Waypoint();
    end.Location = new Location();
    end.Location.Altitude = endLocation.Altitude;
    end.Location.Latitude = endLocation.Latitude;
    end.Location.Longitude = endLocation.Longitude;
    request.Waypoints.Add(end);

    request.Options = new BingRouteService.RouteOptions();
    request.Options.RoutePathType = BingRouteService.RoutePathType.Points;
    request.Options.TrafficUsage = BingRouteService.TrafficUsage.None;
    request.Options.Optimization = 
             BingRouteService.RouteOptimization.MinimizeDistance;
    request.Options.Mode = BingRouteService.TravelMode.Walking;

    // Don't raise exceptions.
    request.ExecutionOptions = new BingRouteService.ExecutionOptions();
    request.ExecutionOptions.SuppressFaults = true;

    request.Credentials = new Credentials();
    request.Credentials.ApplicationId = 
      (string)App.Current.Resources["BingCredentialsKey"];

    // Make asynchronous call to fetch the data. Set busy indicator...
    RouteClient.CalculateRouteAsync(request, segmentID);
}

From the code above, you can see the service provides options for a lot more than what we are using it for in this application. It is primarily intended for traveling directions, which usually involves optimization for distance or time, traffic effects, etc. So we are not really using it for its intended purpose, but serves our needs. As with the geocode service, we can pass a token with the call that allows us to identify the result. In this case, we are passing the segmentID to keep track of what we asked. We are not making use of it at this point, but will be necessary if we want to persist the data. The callback processing is shown next.

void routeClient_CalculateRouteCompleted(object sender, 
       BingRouteService.CalculateRouteCompletedEventArgs e)
{
    try
    {
        if (e.Result.ResponseSummary.StatusCode != 
                BingRouteService.ResponseStatusCode.Success)
        {
            Messenger.Default.Send<UserActionAlertMsg>(
              new UserActionAlertMsg() { 
                  AlertText = "Could not determine route segment." });
        }
        else
        {
            BingRouteService.RoutePath routePath = e.Result.Result.RoutePath;
            currentSegment.PlotPoints.AddRange(routePath.Points);

            //Plot the segment
            PlotRouteSegmentMsg msg = new PlotRouteSegmentMsg();
            msg.segmentPoints = new List<Location>(routePath.Points);

            Messenger.Default.Send<PlotRouteSegmentMsg>(msg);
        }
    }
    catch
    {
        Messenger.Default.Send<UserActionAlertMsg>(
          new UserActionAlertMsg(){ AlertText="Got an exception calling route service."});
    }
}

Now that we have a collection of points, all we need to do is draw them on a layer on the map. The map control includes a number of types that facilitate rendering operations. We've already used MapLayer, there is also PushPin, MapPolygon, and the one which we'll make use of next is MapPolyline. This is exactly what we need to render our route segment. Here is how we process the PlotRouteSegmentMsg message:

void PlotSegmentHandler(PlotRouteSegmentMsg msgData)
{
    Color routeColor = Colors.Blue;
    SolidColorBrush routeBrush = new SolidColorBrush(routeColor);

    MapPolyline polyLine = new MapPolyline();
    polyLine.Locations = new LocationCollection();
    polyLine.Stroke = routeBrush;
    polyLine.Opacity = 0.65;
    polyLine.StrokeThickness = 5.0;

    foreach (Location pt in msgData.segmentPoints)
    {
        polyLine.Locations.Add(pt);
    }
    SegmentLayer.Children.Clear();
    SegmentLayer.Children.Add(polyLine);
}

RouteEditor.png

The above shows the editor in action. The start and end address numbers are not really required for the definition of a segment, but are included to show how solution entities (store address, soda machine location, etc.) could be related with a route.

Pizza Delivery

Suppose that a business enterprise did not follow a specific route as described above for the product distribution scenarios. Instead, this business type is one that has an area of coverage. The above editor could be easily modified to allow the user to select an arbitrary number of intersections as the defining boundary of their delivery area. The defined area could be drawn on a separate layer for identification and any number of areas could be supported. All the addresses that exist in the defined area would constitute their customers. To determine which area (if any) contained a specific address, we could use the coordinates and perform a simple inclusion check. Similar to checking if a point is within a rectangle or figure.

As an example, consider a national or regional pizza chain that may have several locations. Each of these would in turn serve a pre-defined area simply so that they can deliver the product within the allowable time. For this type of business, a route is required but is not pre-defined. This type of business would benefit from a solution that would dynamically determine the most efficient route for a given set of locations (deliveries). Given a set of delivery coordinates (addresses) and the restaurant as the starting point, an algorithm could easily determine the best delivery route(s). The solution could even be smart enough to evenly distribute the work load between available drivers. Of course, a phone app for the solution would direct the deliveries without any paper instruction, without the driver needing to know the area, and allows a manager to keep track of each delivery as it is taking place (the system knows where the phone is).

Dispatch Service

In most metropolitan cities, there are companies that offer same day delivery service. These companies have a fleet of messengers (usually on bike) that pick up packages at one location and deliver to another location within the city or close vicinity. Using the facilities we have been describing, such a company can be provided with a service that would make the business process completely automated. In other words, no office personnel. Customers could enter pick-up/drop-off information through a Web page. The system could then automatically determine the most efficient way to accomplish the delivery. This would involve an algorithm that would determine which messenger is the closest to the pick-up location, the orders that are still in the queue, the destination location compared to other pick-up orders, etc. The orders are then issued to each messenger through a phone app as well as all other pertinent business logic information. Some of the 'wiz-bang' features could be a page where customers could see their package in motion as well as a dynamically updated estimated delivery time. Brainstorming can be a lot of fun!

Next Up

One of the core pieces of the targeted applications we have been describing is the phone. So next up, I'm planning on taking a look at what it takes to bring the phone into the solution. At the same time, we'll brainstorm some more business solutions that could benefit from the functionality that we've been describing.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Al Alberto
Software Developer (Senior)
United States United States
No Biography provided

Comments and Discussions

 
GeneralMy vote of 5 PinmvpKanasz Robert28-Sep-12 5:41 
Interesting article

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140916.1 | Last Updated 20 Jan 2011
Article Copyright 2011 by Al Alberto
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid