NOTE: Learn how to do convenient Two-way data binding to an enumerated property in a Windows
Phone app! (See below after the system architecture diagram).
(Windows Azure Contest Entry)
Table of Contents
Phase 1 - Project Overview
Why
Azure?
Azure has both software, platform, and infrastructure as a service features, making it the ultimate solution for creating high
performance, reliable, ubiquitous client/server solutions. The Azure platform eliminates the vast amount of time and cost normally
involved in distributed database application development, allowing a developer like myself to concentrate my time on creating features
& value for my users instead of wasting it on support code and infrastructure.
(Note: I already have an Azure account via
MSDN)
Introduction
Azure is the perfect platform for coordinating the search and notification services vital to the creation of a pet adoption agent that connects
potential pet owners with the countless adorable kittens & puppies just waiting to give love. By providing cloud based, easy to configure SQL
storage Azure is perfect for storing the search criteria specified by eager pet parents-to-be via the FindAPet client app running on their
Windows Phone. Then Azure Mobile Services is leveraged to send out push notifications to them when pets that meet their stored
preferences become available at animal shelters throughout the USA. The PetFinder API provides ready access to an inventory of adoptable pets of nearly every type and breed and direct access to
the animal shelters that house them. It also provides the necessary animal and shelter search facilities necessary to complete the system, a system
that will save the lives of countless innocent loving animals when it's finished.
An auxiliary feature of the system will be a Lost & Found
service. Owners of lost pets can enter a description of the pet they lost. In a manner similar to Google Alerts, the system will run periodic
sweeps of shelters within a 50 mile radius of the owner's home location. If a pet matching the owner's description is found, a push notification
will be sent to the owner with a link to the shelter that is holding the pet. (Thank you Simon Jackson for the Lost & Found idea!
)
Overview
The entry point into the system will be the FindAPet app (client) running on
the Windows Phone platform using the MVVM Light
framework. It will provide a simple search interface that helps them find the kind of pet they are interested in adopting. The screens below
show a sample session where the user is looking to adopt a Calico kitten:
The
system then shows them a list of animal shelters nearby them. Using the phone's Geolocation services the user's
current location is used as the center point for a proximity search, as shown in the screenshot below where Boise, Idaho
was identified as the the user's current location. The user checks off the shelters that they are willing to travel to:
The user's pet and shelter preferences are stored in an Azure hosted SQL table. As pets at the
designated shelters become available, a push notification is sent to the user with the prospective pet's details and photo for easy
viewing. If they like the pet and are considering adopting it, they can add the pet to their wishlist, as shown in the screen shot
below (note an adult cat is shown too since the user selected it in a search where the specified age was adult):
Push notifications will also act as reminders to notify the user
when one of the candidate pets is close to their termination date, to make sure they don't miss the opportunity to save a life while finding a lifelong
companion. Finally, the system will leverage the Nokia Here Maps service to give
them directions to the shelter where the chosen pet is at, so they can pick up their new loved one and return home together to share many happy
memories.

Two-way data binding to an enumerated property without creating new value converters or creating auxiliary properties (MVVM
Light)!
Code Project is about source code and so is this contest so I am including the source code for a helpful utility class that I
created while working on the FindAPet Windows Phone client. I became tired of creating auxiliary properties to provide types that were easy to data
bind to, just to expose an enumerated property for binding. Just as tedious was creating a new value converter for each enumeration type. The
attached source file gives you a class you can drop into your MVVM Light C# project. The code provides a generic value converter for
enumerated types so you can create the binding completely through the use of the Create New Data Binding dialog options without having to add any support
code to make it happen.
With this code you now have a value converter for any ViewModel enumerated property that does two-way conversion between the
Description attribute strings for the enumerated values and the enumeration constants they represent. This allows you to do two-way data binds to an
enumerated property without having to do any plumbing code. The only thing you have to do is set the Converter field to
EnumToDescAttrConverter and put the fully qualified type name for the Enumeration type of the bound property in the
ConverterParameter field (see picture below for an example). If you have trouble determining the correct fully
qualified Enum type name, just set a break point in the ConvertBack() method where an Exception will be thrown. Then
call System.Reflection.Assembly.GetExecutingAssembly().DefinedTypes.ToList() in the Immediate Window to get a list of all
currently defined System types in that execution context. Find the correct fully qualified type name and paste it into the
ConverterParameter field.
Here's how it works. Whenever the view accesses the bound enumerated
property, EnumToDescAttrConverter gets the description attribute for the enum when its Convert() method is
called:
public object Convert(
object value,
Type targetType,
object parameter,
CultureInfo culture)
{
if (value == null)
throw new ArgumentNullException(
"(EnumToDescAttrConverter:Convert) The value is unassigned.");
Enum e = (Enum)value;
return e.GetDescription();
}
This gives list boxes and other view elements a nice human readable string to work with. Now what happens when the view wants to
update an enumerated property with a new value? For example, the user makes a List Box selection thus triggering a property set
call because the List Box's SelectedItem property is bound to the enumerated property. This is where the
fully qualified type name entered as the ConverterParameter comes into play.
The EnumToDescAttrConverter.ConvertBack() method uses
the fully qualified type name passed via the Parameter parameter to create the correctly typed concrete enum value using Reflection.
It then searches the description attributes for that enum type to find the enum value associated with the description
given in the value parameter, and returns that enum value.
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
throw new ArgumentNullException(
"(EnumToDescAttrConverter:ConvertBack) The value is unassigned.");
string strValue = (string)value;
if (parameter == null)
throw new ArgumentNullException(
"(EnumToDescAttrConverter:ConvertBack) The Parameter parameter is unassigned.");
string theEnumClassName = parameter.ToString();
Enum e = (Enum)System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(theEnumClassName);
if (e == null)
throw new ArgumentException(
"(EnumToDescAttrConverter:ConvertBack) Invalid enumeration class name: "
+ theEnumClassName
+ ". Set a break point here and call "
+ "System.Reflection.Assembly.GetExecutingAssembly().DefinedTypes.ToList()"
+ " in the immediate window to find the right type. Put that type into "
+ "the Converter parameter for the data bound element you are working with."
);
System.Type theEnumType = e.GetType();
Enum eRet = null;
foreach (MemberInfo memInfo in theEnumType.GetMembers())
{
object[] attrs = memInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attrs != null && attrs.Length > 0)
{
if (((DescriptionAttribute)attrs[0]).Description == strValue)
{
eRet = (Enum)Enum.Parse(theEnumType, memInfo.Name, true);
break; }
}
}
if (eRet == null)
throw new ArgumentException(
String.Format("{0} can not be converted to an enum value: ", strValue));
return eRet;
}
Note: Use the ToDescriptionsList<>() method to conveniently grab the description attributes from an
Enum type to fill a List Box or other similar element. Put the call to it in the property that returns a list of human
friendly strings to the UI element bound to the enumerated property. (For example, the ItemsSource property of a list box):
public static List<string> ToDescriptionsList<t>()
{
List<string> listRet = new List<string>();
foreach (var x in typeof(T).GetFields())
{
Enum e;
if (x.IsLiteral)
{
e = (Enum)x.GetValue(typeof(Enum));
listRet.Add(e.GetDescription());
} }
return listRet;
}
Below is the enumerated type that represents the different kinds of animals the
PetFinder API can search for. This is an example of using the Description attribute to tie a human friendly string to an enum value:
public enum EnumAnimalType
{
[Description("Barnyard")]
barnyard,
[Description("Birds")]
bird,
[Description("Cats & Kittens")]
cat,
[Description("Dogs & Puppies")]
dog,
[Description("Horses & Ponies")]
horse,
[Description("Pigs")]
pig,
[Description("Reptiles")]
reptile,
[Description("Other Small & Furry")]
smallfurry
}
Example of a Two-way data binding using the generic converter class, with the fully qualified type name I discovered via the Immediate
Windows:

Phase 2 - Build and Deploy an Azure Web Site Fast with WebMatrix 3
Speed! I built and deployed this entire Lost & Found web site that can detect a cat's face in a photo in only one day! Even better, with WebMatrix 3's Azure support you don't have to use TFS, GitHub, or any other repository to deploy your site. Just edit your site locally and when you are ready, hit the Publish key! You can even edit a remote site on Azure directly if you want!
Also, the
web site described in this article owes much to the wonderful KittyDar project, which is
the source of the cat face detection technology used by the web site to ensure the quality of uploaded Lost & Found
photos. The web site has been live for a week now. You can experiment with the web site and the cat face detection technology using the link below. You do not need to register to use the web site, only to upload cat photos of your own:
FindAPet Lost & Found Web Site
One of Azure's biggest benefits is the ability to create and deploy professional web sites at breakneck speed. With WebMatrix 3's seamless integration with Azure, in most cases all you have to do to publish your web site to Azure or update it is to press the Publish button in WebMatrix 3! In this section of my Code Project article for the Azure Developer Challenge, I will show you how I built a web site that accepts photos of a lost
cat from worried pet owners, and then checks the quality of the photo to make sure it is suitable for use by others to identifying their cat easily. You will find
the WebMatrix 3 project replacement files attached as a download to this article. The instructions for using them follow below.
IMPORTANT:
Remember to update the ReCAPTCHA keys in the source with the keys that belong to you, otherwise you will get strange errors on the account registration
page! I have removed my keys and restored the placeholder strings PUBLIC_KEY and PRIVATE_KEY as per the Photo Gallery tutorial (covered later in the article). Follow that tutorial's instructions carefully regarding the ReCAPTCHA keys and you will not have any problems using CAPTCHA on your site.
Detecting Cat Faces and The Lost & Found Web Site
As mentioned in the project overview, the Azure Animal Adoption Agent will have a Lost & Found component that allows worried owners of missing pets to upload pictures of their loved ones, to help others find them. The site will also be available to pet shelters so they can scan pictures of pets whose owners live close to the shelter, to see if they have picked up a stray that belongs to one of those owners. The shelter employee can then contact the pet owner to give them the happy news.
Thanks to the KittyDar Cat Detector project, cat owners will have an advantage. Since KittyDar only detects cat faces if the cat is looking at the camera in a portrait orientation, it can be used to assist cat owners in submitting a photo that is as helpful as possible in identifying their pet. This stops the owner from uploading a photo that may have sentimental value but isn't very useful for identifying the cat. In addition, KittyDar can detect if there are multiple cat faces in the photo. In that case the owner will be instructed to use a different photo that only has their cat in the shot.
Here are some example photos from the FindAPet web site that illustrate the benefits of the KittyDar cat face detector. The red bounding rectangle shown in photos where a cat's face was detected successfully shows the location of the cat's face as determined by the detection engine:
Photo 1 - Single cat face detected. Photo is suitable for Lost & Found purposes

Photo 2 - Detection Failed. Cat's Face is not Oriented Properly. Unsuitable for Lost & Found Purposes
Photo 3 - Detection Succeeded but Too Many Cats. Unsuitable for Lost & Found Purposes
WebMatrix 3 - Power Tool for Rapid Web Site Deployment with Azure
WebMatrix 3 is the
latest release of Microsoft's tool for rapid web site development. The most powerful feature of this release is its close integration with Azure.
This allows you to create and deploy web sites effortlessly, even sites backed by databases like the FindAPet Lost & Found Cat web site. With the
right starting template WebMatrix 3 will handle all the tedious tasks involved in creating and configuring your site on Azure.
As the basis for my Lost & Found web site I used the WebMatrix 3 Photo
Gallery template. The attached download gives you everything you need to recreate the Lost & Found Cat web site on your Azure account. But do
read the sections below where I explain the various places I modified the code generated by the Photo Gallery Template. You will learn the important
locations of the code where you may want to make changes to adapt the project for your own needs. You will also learn about a few fixes I
needed to make to the default template code to make it work right. If these fixes are not part of the template code at the time you read this, you
can use this knowledge to save time implementing your own project based on the Photo Gallery Template. If you just want to create your own KittyDar Lost & Found web site and are not interested in the details, then skip the Long Form Explanation section below and jump to the Short Form Explanation.
Here are the detailed steps I took to create the web site.
Long Form Explanation
Detailed Steps To Reproduce the Lost &
Found Photo Gallery with Cat Face Detector
IMPORTANT: Remember to update the ReCAPTCHA keys in Register.cshtml located in the Account folder with the keys that belong to you! Replace the PUBLIC_KEY and PRIVATE_KEY string constants with your ReCAPTCHA keys as per the Photo Gallery tutorial. Follow that tutorial's instructions carefully on the keys and you will not have any problems using CAPTCHA on your site.
Step 1
Follow the instructions in this tutorial
to get the WebMatrix 3 Photo Gallery template up and running:
At the time this was written, the error message for an unsuccessful
CAPTCHA attempt displays before a CAPTCHA attempt is even made. To correct this, replace the line in Register.cshtml that says:
@Html.ValidationSummary("Account creation was not successful. Please correct the errors and try again.", excludeFieldErrors: true, htmlAttributes: null)
with
@if(IsPost == true )
{
@Html.ValidationSummary( "Account creation was not successful. Please correct the errors and try again.", excludeFieldErrors: true, htmlAttributes: null)
}
Step 2
At the time this was written, the Photo Gallery template was
referencing an old version of JQuery in the site layout file, _SiteLayout.cshtml. If this is still the case, open that file and
replace the line SCRIPT element in the HEAD element that references version 1.8.2 with the following snippet:
<!---->
<!---->
<!---->
<script src="~/Scripts/jquery-2.0.0.min.js"></script>
Step 3
Publish the Photo Gallery web site to your Azure account and inspect it. You should now be ready for the real
fun.
Step 3
Add the KittyDar Javascript files to
your WebMatrix 3 project Scripts folder. You can find these files in the Scripts folder found in the download
attached to this article:
- kittydar-0.1.0.min.js
- kittydar-0.1.6.js
- kittydar-demo.js
- kittydar-detection-worker.js
These files provide the code necessary to detect cat faces in photos and to draw the bounding
rectangles on the photo while detection is taking place and after a detection has succeeded.
Step 4
Open the
Upload.cshtml web page file in WebMatrix and replace this header element:
<h1> Upload Lost Cat Photo </h1>
with
<h1>Upload Lost Cat Photo</h1>
<p>
The photo or your lost cat that you upload will be placed in the
<a class ="italic" href ="~/View/ @galleryId " title ="@ gallery.Name"> @gallery.Name </a> gallery.
</p>
<p> The photo needs to be a picture of your cat looking at the camera, preferably straight ahead and not looking up, down, or to the side.</p>
Step
5
Add the following snippet to View.cshtml which is found in the
Photo folder, the web page that displays a single photo. It adds the KittyDar support scripts to this page:
@section Head {
<!-- KittyDar cat face detector script files: https: <script src ="~/Scripts/kittydar-demo.js"></script>
<script src ="~/Scripts/kittydar-0.1.6.js"></script>
<!-- CSS to format and align properly the elements used to show the KittyDar operation
annotations and result. -->
<link rel ="stylesheet" href ="kitydar.css"/>
}
Step 6
Find the image element for the large photo. Replace the existing
IMG tag element with the snippet below. This snippet is where the photo is displayed and also the bounding boxes and annotations
generated by the KittyDar detection engine. As KittyDar identifies the cat's face, you will see bounding boxes drawn on the image canvas until the
face is found and the final bounding box is drawn, or the operation fails and the canvas will be cleared of bounding boxes. These elements are
managed by the kittydar-demo.js and kittydar-detection-worker.js scripts. The inline HTML comments explain what each document element does:
<!---->
<div id ="viewer-container">
<!---->
<div class="kittydar-viewer" id ="kittydar-viewer"></div>
<div id="viewer">
<canvas id="preview">
</canvas>
<canvas id="annotations">
</canvas>
</div>
<!---->
<div class="kittydar-progress" id ="kittydar-progress">(none)</div>
</div>
<div id ="detection-result">
<!---->
<div class="kittydar-result" id ="kittydar-result">(none)</div>
</div>
Step 7
Add the following snippet to just before the ending closing
DIV tag. It will run the KittyDar cat face detector on the currently displayed photo:
<script>
detectFromUrl("@Href( "~/Photo/Thumbnail", photo.Id, new { size="large" })");
</script>
Step 8
Add the
following snippet to the _SiteLayout.cshtml file to make sure our custom HEAD elements in the view page are rendered:
<!---->
@RenderSection( "Head", required: false);
Step 9
Add kittydar.css to the
Content folder. It will make sure the KittyDar view elements are formatted propertly.
Step 10
Publish your web site to Azure using the WebMatrix 3 Publish button. You're done!
Short Form Explanation
NOTE: If you followed the Long Form Explanation steps to modify your site, you do not need to follow these steps and can skip this section.
Step 1
Follow the instructions in this tutorial to get the WebMatrix 3 Photo Gallery template up and running, but SKIP the CAPTCHA setup steps since the file containing the CAPTCHA codes is about to be overwritten in the next step:
Step 2
Make a backup of your WebMatrix 3 project files now. Then, download the KittyDar-Photo-Gallery.zip file. Open the compressed folder and select all the files and directories contained and copy them into the root directory of your web site that you created with the WebMatrix 3 Photo Gallery template. The destination directory should contain the file Web.config, that's how you know you have the right target directory for the copy operation.
Step 3
Go back to the Photo Gallery tutorial and return to the section titled "Enabling CAPTCHA in the registration page". Follow the instructions to setup CATPCHA properly on your site.
Step 4
Publish your web site to Azure using the WebMatrix 3 Publish button. That's it! Now test your web site and make any desired changes you need to make.
Test Your Web
Site
1. Run the
project.
2. Register for an account if you have not done so already.
This will be your test account.
3. Login to your test account.
4. Create a New Gallery called "Lost & Found"
5. Select the gallery and open it
6.
Click on "Upload a Photo" to begin the real test.
7. Use the
"Choose File" button to select a file that contains a picture of a cats face to upload. If you don't have any cat pictures of your own, you
can find plenty of public domain cat photos to test with at this link:
Public Domain Cat Photos
This in particular is a good test photo:
Contented Cat
Make sure you have the rights to any photos you upload or that they
are in the public domain since the photos will be publicly available on the Web!
Easter Egg
To see the Easter Egg on FindAPet, view any photo that contains more than one detected cat face on the main viewing page. Better yet, just visit the link below:
Spooky cats!
Resources
WebMatrix 3
Azure
KittyDar
Robert Oschler is a veteran artificial intelligence, robotics, natural language processing, and speech recognition programmer. His latest love is C#/.NET programming, especially on the Windows Phone platform. When not writing code you can find him playing guitar or watching the latest videos on MSDN's Channel 9. He is also a member of the incredible Nokia DVLUP program and owes much of his affection for Windows Phone programming to the wonderfully talented and enthusiastic Nokia Ambassadors.