Up Silverlight

Code sample: TourneyJett

Last modified on October 28, 2011 11:25

In November 2010, TourneyJett broke ground on its game changing fishing tournament management system. You might think fishing and software is an unlikely match, however, the need to register, manage and then finally document fishing events requires highly sophisticated software. This story explains what TourneyJett is about, what their goals were and what makes TourneyJett.com of special interest to anyone using IdeaBlade or Intersoft.

Watch this short video to better understand their vision.



Coming in to the project, TourneyJett developers already had some experience in Silverlight 3 and IdeaBlade. Since Silverlight 4 had been recently released, they decided to focus on using it for the core of their software along with IdeaBlade’s DevForce Silverlight 2010 application.  

Early on, they created some prototypes using Telerik Silverlight controls and MVVM Lite. Neither proved suitable for the direction that they wanted to go, so they opted to try the Intersoft Client UI controls and create their own lightweight MVVM architecture.

The combination of Silverlight 4 (using C#), IdeaBlade, and Intersoft proved to be an awesome decision as their speed of development was unbelievable compared with other combinations of software tools. TourneyJett.com is comprised of only two developers and one business driver. To meet an April 2011 deadline, the selection of these tools proved to be the deciding factor in achieving their goals.  

Components

Backend

  • MS Azure
  • MS Azure SQL
  • MS Azure Storage
  • Amazon S3
  • IdeaBlade DevForce
  • MEF (Microsoft Extensibility Framework)
  • MS AppFabric
  • MS Entity Framework 4
  • MS ASP.NET MVC 2
  • ASP.NET Membership Provider
  • Supporting HTTP, HTTPS, WCF, REST

User Experience (UX)

  • Silverlight 4 (XAML)
  • .Net CLR 4
  • MS Entity Framework 4
  • Intersoft control suite for Silverlight
  • IdeaBlade DevForce
  • MVVM
  • Offline workspace management for syncing from machine to web
  • Support for both in-browser and out-of-browser (OOB)
  • Bing maps Silverlight control and web services
  • jQuery
  • HTML

Application details

Let’s now get to some details of the application.

Figure (1) shows the main view of the application. This is more or less the dashboard for the user, he/she will have a watch list of upcoming events, events that have been registered for, the last 12 (rolling) months tournament finishes for the user and the annual ranking of a series (a group of events where the totals dictate who moves on to the final event).

fig1.png
Figure 1

Coroutines

All data access is done via DevForce using coroutines. Coroutines are amazing and save hundreds of hours and lines of code. For example, TourneyJett adopted a methodology to call the coroutines by an intervening method in response to a property change notification.

Property change

C#
        EventResult _CurrentEventResult;
       public EventResult CurrentEventResult
        {
           get { return _CurrentEventResult; }
           set
            {
                UpdateField<EventResult>(ref _CurrentEventResult, value, "CurrentEventResult");

               if (value != null)
                {
                    GetEventResultFullData();
                }

               this.ViewCompleteResultsCommand.RaiseCanExecuteChanged();
            }
        }

Method call to coroutine

C#
       private void GetEventResultFullData()
        {
            var batch = Coroutine.Start(GetDataEventResultFullCoRoutine);
            batch.Completed += (sender, args) =>
            {
               if (args.CompletedSuccessfully)
                {
                }
            };
        }

The coroutine

C#
       private IEnumerable<INotifyCompleted> GetDataEventResultFullCoRoutine()
        {
            OCEventResultFull.Clear();

            var eventResultLSOp =
                App.EntityManager.EventResults.Include("Participant")
                .Where(x => x.EventMasterID == EventMasterID &&
                        x.EventMaster.IsAOYApplied == 1 &&
                        x.ResultDayNumber == -1 &&
                        x.EventResultID > 0 &&
                        x.IsHighSide == 0)
                .OrderBy(x => x.ResultRank)
                .ExecuteAsync();

           yield return eventResultLSOp;

           foreach (var r in eventResultLSOp.Results)
            {
                OCEventResultFull.Add(new TournamentHelper.AOY.AOYResult() { Angler = r.Participant, HighLowSide = "Low-Side", Rank = r.ResultRank, TotalWeight = r.ResultLBTotal, TotalWeightBack = r.ResultLBBack, TotalWeightPenalty = r.ResultPenalty, TotalCaught = r.ResultCount, NoShow = r.IsNoShow == 0 ? "N" : "Y", DQ = r.IsDQ == 0 ? "N" : "Y", BigWeight = r.ResultLBHigh  });
            }

           yield return Coroutine.Return(eventResultLSOp.Results);
        }

If you haven’t learned how to use coroutines, it is quite simple to use and it’s an elegant way to handle lots of query conditions in a single call. For example, say that you want to get all Anglers that meet a specific condition, after the ExecuteAsync() method is called, you yield the result of the QueryOperation and then your code will resume once the result has been returned. You can then further execute more queries that rely upon the data in the first query and so on. TourneyJett highly recommends coroutines for their utilitarian functionality.

The main menu system is using the Intersoft UXDeskTopDoc architecture that provides a Mac-like menu system. From this menu system, UXWindow’s are opened (not web pages) as seen in figure 2.

fig2.png
Figure 2

So, for all intents and purposes, this web application is similar to a Windows or Mac UX, something that most everyone knows how to navigate.  

Registration

As you know, a web application of any substance requires some way to identify the user.  TourneyJett.com is no different in this respect. TourneyJett's registration system feels commonplace for the most part, though they have added some really nice touches.

The registration process is a pretty typical ASP.NET membership registration sans initial password.  On the initial registration, the user is only asked for User Name, Email, First and Last names. Since the system requires a unique user name and email address, they use a RESTful service to verify both data items and in the case of a user name conflict, they suggest an available user name based on the one given.

TourneyJett then sends an email to the user with a temporary password and a link back to confirm their email. Once confirmed, the user uses the temporary password to complete registration and become a full fledged member. For the registration process they decided not to use DevForce services although they do login the user with the Entity Manager’s LoginAsync() method.

After a user is registered, he/she will hopefully flesh out the “My Profile” section.  If not, no harm, no foul. However, to have the richest user experience, filling out the “My Profile” helps TourneyJett.com to serve their users best (see figure 3).

fig3.png
Figure 3

The “My Profile” view contains general user information (and a profile picture), Addresses (Geo-coded and verified using the Bing Maps Web services), Phones (will receive e-mail via the phone carrier if SMS is turned on), Boater Gear, Membership and Location watch list criteria (this controls what is seen on the main page under “Upcoming Events”), invitation settings, clubs, teams and optionally (if the user is also a Tournament Director) Director Settings.  All in all, this is a very rich user profile. Additionally, the user may change his/her password and security question at any time.
In the event that Verification errors occur, we developed a toast mechanism that contains a stylized ErrorSummary control (see figure 4):

fig4.png
Figure 4

We felt this was the nicest way to be unobtrusive and yet deliver critical information back to the user as soon as possible. Our toast mechanism is also used for general notifications to the user throughout the entire system (say goodbye to dialog boxes).

Series and events

For those of you that are unfamiliar with fishing tournaments, there are basically a few types of tournaments. There is Draw (blind draw like out of a hat), Buddy (you and your friend) and Team (usually a team is two people that fish together the entire season). Events might be unrelated or grouped into a series. A series is usually related to some organization (B.A.S.S., FLW, PAA, TBF, etc.,) where each event’s totals are totaled. These totals represent a ranking within the series/organization and entitle the anglers above the cut-off number to fish the last and final event, usually known as the “Classic”. Therefore, a series will contain many events. You may now be getting the picture that there are quite a few database relationships, pre-requisites and dependencies.

As seen in figure 5 below, these relationships begin to manifest themselves. This is the main view for a Tournament Director. In addition to Series and Event, you will see a button for “My Officials” (other users that can manage a director’s events) as well as “Pack” and “Un-Pack” buttons.

fig5.png
Figure 5

Offline capabilities

Let’s focus on Pack and Un-Pack for a moment. As you might expect, many tournaments are held in remote locations where even 3G/ 4G phones don’t have decent reception or any reception at all. Due to this situation, TourneyJett.com had to support off-line use so that a weigh-in (the process that happens at the end of the tournament) could happen with or without an Internet connection. A tournament director will (for safety sake) always “Pack” for the tournament as close to the date of the event as possible. The “Pack” process will create an off-line storage file using the IdeaBlade off-line storage facilities. Under normal circumstances, the tournament director will perform the weigh-in process and as soon as an Internet connection is available will connect and synchronize automatically with the Azure SQL database. The tournament director is quite unaware when this happens as his weigh-in data is auto-magically synchronized and appears as if it was there all along.  

Implementing offline mode was much less traumatic than we could ever have hoped. In fact DevForce removed the trauma out of this piece of work altogether. Preparing for offline mode of course entailed identifying what data the user might need in order to perform the weigh-in task in the field. Saving offline is just a matter of handling the Save event and writing changes to disk.

When the user does login on-line again the offline changes are loaded into the Entity Manager and processed. Of course a Director may have added an Angler who may already exist in the system so this condition must be checked and handled as needed.

TourneyJett developed a sophisticated connection checking system that would serve us well in areas where there is intermittent connections. Just checking the state of the local machine’s connection to the internet is not sufficient. What if the hosting server is not available? We decided to send a request to the server expecting a specific response, but watch out for caching issues.

If there is a need to “Un-Pack” for some reason, we have provided the “Un-Pack” button. This Un-Pack process simply deletes the off-line file created in the “Pack” process. Under normal circumstances, the “Un-Pack” feature is not required, it was provided simply just in case it was needed. 

An event represents a physical location; a lake, river or some sort of watershed. As seen in figure 6, the tournament director selects the location and potentially the ramp location as well and the resulting Bing Map displays this information on the map’s surface.

fig6.png
Figure 6

There is plenty more detail to discuss but we have to move on.

Reel-time weigh in

One of the most important parts of any sporting event are the fans; those that support and follow the contestants. In order to provide a strong connection between contestant and fan, we have created a real-time “Reel-Time” view of events currently in progress. This view is available in both the Silverlight application as well as in HTML format from TourneyJett.com for iPhone and Android users.  Figure 7 illustrates the Silverlight view which is updated once per minute.

fig7.png
Figure 7

Video

Most fishermen are not avid computer users. TourneyJett decided to forego conventional means of product documentation and instead, their documentation is done via short videos that are stored and streamed from Azure storage as seen in figure 8.

fig8.png
Figure 8

TourneyJett is hosting Windows Azure instances, but at a later date they might decide to move to Amazon EC2, or some other virtual cloud-based hosting. We don’t want to store our assets with the applications for a variety of reasons but most importantly - managing media on multiple servers. Some of the reasons why we want to use cloud storage are high availability, redundancy, and content delivery, not to mention keeping the application un-cluttered with a bunch of media.

Praise for DevForce

Specifically, DevForce helped with:

  • Speed of development
    By leveraging DevForce, TourneyJett was able to significantly speed-up development and was able to go from concept to product launch in approximately six months ... with a development team of two! 
  • Coroutines
    TourneyJett used coroutines to make asynchronous calls process sequentially without having to chain dozens of methods or nest callbacks inside of callbacks (inside of callbacks). DevForce has a coroutine class that works out of the box.
  • Offline mode
    DevForce’s client-side cache enables applications to operate in a partially connected or fully disconnected environment. You can query, modify, and even create new entities while offline, and you can save the cache to the file system to preserve the state of the entities if the application or computer needs to be shut down.
  • Azure
    The Windows Azure Platform promises to radically reduce the costs and risks of managing the IT infrastructure that supports your application. Hardware, networking, foundational software, staffing, security, availability, capacity, redundancy... these become Microsoft’s problems, not yours.
Created by DevForce on May 03, 2011 10:31

This wiki is licensed under a Creative Commons 2.0 license. XWiki Enterprise 3.2 - Documentation. Copyright © 2015 IdeaBlade