Friday, December 7, 2012

My experiments with Windows Azure Mobile Services- Part II

The first post on this topic was written in October here. Though I wanted to follow it up quickly with Part II, I got distracted, but here I am with the second part of Azure Mobile Services.

One of the things that wasn’t detailed in the first post was the Ratings class. So I will start from there. The ratings class is simply an instance of the ratings table in the database. It hence inherits the AzureMobileTable class that we saw in the previous post.

The table has the columns listed below

image

The scenario that we will deal with in this post, is to calculate the Average ratings for any given movie. This can be  done in two ways

  • Get all the movies to the service and calculate the average in the service. The downside of this is that if I have a lot of ratings for a movie I have to fetch all the records which is inefficient.
  • The second option is to calculate the Average in Azure Mobile Services and return the records. The question though is, how to do this with Azure Mobile Services.

Azure Mobile Services has support for scripting. Every table has a tab called script and when you click on it, you will see that you can write your script for 4 operations; Insert, Update, Delete and Read. This is what we will use for calculating averages. But there is a catch. Each operation just supports one implementation of the script. The read, for example by default executes read all, which we have already used. So you cannot write another read script to do Averages.

One way to get around this limitation is to create another Azure Mobile Service table called Averages and script the read operation of this table to calculate averages for the ratings table. Some code snippet is in order. So here goes

   1: function read(query, user, request) {
   2:     mssql.query("SELECT AVG(Value) as Average from Ratings WHERE MovieID = ?", [query.id], {
   3:         success:function(results) {
   4:             request.respond(200, results[0]);    
   5:         }
   6:     });
   7:     //console.log(query);
   8:     //console.log(query.getComponents());
   9: }

The script calculates the average for a given movie id and returns the status of 200 along with the results. The commented code just show you how to use logging.


Now, what is left to do is to call this from our service described in Part I. There is a method in the Ratings class that calls this script.



   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Web;
   5:  
   6: namespace TMDBHelperService.AzureMobileServices
   7: {
   8:     public class Ratings: AzureMobileTable
   9:     {
  10:         public Ratings():base("ratings")
  11:         {
  12:             
  13:         }
  14:  
  15:         public AzureMobileQuery getAverage(int movieId)
  16:         {
  17:             return new AzureMobileQuery("tables/averages/" + movieId.ToString());
  18:         }
  19:     }
  20: }

Note the getAverage method queries against the Averages table and not the ratings table. The only other thing left to do is to call this method from our broker.



   1: public string getAverageRatings(int movieId)
   2:         {
   3:             var _ratingsTable = new Ratings();
   4:             AzureMobileQuery _query = _ratingsTable.getAverage(movieId);
   5:             if (_query!=null)
   6:             {
   7:                 return _helperClass.Execute(_query);    
   8:             }
   9:             return String.Empty;
  10:         }


This solution works very well if you just have one or two operations. But it quickly becomes unmanageable if you have write a bunch of custom operations on a table.


The better way of doing this is to use custom parameters. You can pass custom parameters by appending them as query strings to the table uri. Something like below


tables/ratings?ops=avg&movieid=<movieid>


Then change the ratings read query to do different operations based on these parameters.



   1: function read(query, user, request) {
   2:     if(request.parameters.ops == "avg")
   3:     {
   4:         console.log(request.parameters.ops);
   5:         console.log(request.parameters.movieid);
   6:         mssql.query("SELECT AVG(Value) as Average from Ratings WHERE MovieID = ?", [request.parameters.movieid], {
   7:             success:function(results) {
   8:                 request.respond(200, results[0]);    
   9:             }
  10:         });
  11:     }
  12:     else
  13:     {
  14:         request.execute();
  15:     }
  16: }

This is a bit more elegant way of “overloading” the read operation without the overhead of additional tables.


I find myself using Azure Mobile Services more and more. I love the simplicity of it for small applications and the speed with which I can get it up and running. They are not perfect but if you are on the fence, I highly encourage you to try them.

Wednesday, October 10, 2012

My experiments with Windows Azure Mobile Services – Part I

 

In August, Microsoft released a new Azure service called Windows Azure Mobile Services. These services, make developing windows store apps easier. If you haven’t started taking a look at it, you can start here.  If you are thinking about using them in your app, you have to be aware of the fact that the javascript client and the server side client versions have some differences.

While most of the fundamentals are the same, I believe the C# version of the Mobile Services Client is a bit more comprehensive than the Javascript version. This being the first version, I am hoping they are going to have the same features across both the clients.

This post deals with using the client in javascript apps. I am not going to go into the details of how to get it working. There is a lot of literature out there that covers this. In short, you download the extension for javascript, get your app key from the portal and use the client library to make calls to the service.

This works very well. With a couple of lines of code, you get your data to the app. But, I was wary of leaving the app key in the client machine. I also want all my business rules in the service not in the client app.

So I was looking to access the Mobile Services from a service.Also, my app already talks to a service that I host on azure, so I wanted all logic to be on the service not on the client. Unfortunately, you can’t use the client library in a WCF Service project.  So I decided to figure out how to call the Mobile Services from a service.

At the backend, the Mobile Services client library just calls a REST API. You can see this by stepping through the code in MobileServices.js. The code that actually makes the call is

   1: Platform.webRequest(options, handler);

Once I figured that out, I decided to write code in my service that does the same.


Let me give you some context  about what my app does. The app allows users to rate movies. It talks to an external webservice to get the list of movies and stores the ratings in Azure Mobile Web Services table. My Azure Mobile Service table structure is shown below


image


The MovieId stores the movie id from the external service and the Value column stores the ratings of the movie. This is the table I am going to query from my service.


image


I created the classes above to do this. A brief description of the classes before we delve into the code within each of them


AzureMobileTable – This loosely represents an Azure Mobile Services Table. I say loosely because,  the methods here are not present in Azure Mobile Services. These will be translated into REST URIs  as you will shortly see.


AzureMovieBroker – This acts as the broker between the WCF service and Azure Mobile Services. This will implement the methods that are needed by the app.


AzureMobileHelper – This is the helper class that runs the methods on Azure Mobile Services. i.e. Makes the REST call. The helper class always executes a query on a table, so it needs a handle to both these objects.


AzureMobileQuery – This class makes up the queries. Queries like where, order by and so on.


Ratings – This is the implementation of the ratings table we saw earlier. This class extends the functionality of the Azure table by providing custom operations. Average is an example. All tables might not need an Average operation. For the app, the ratings table returns the average rating for a movie.


Now that we have looked at the classes, let us see how the code works. First the MobileHelper



   1: public class AzureMobileHelper
   2:     {
   3:         string _baseurl;
   4:         string _appKey;
   5:         string _installationId;
   6:  
   7:         public AzureMobileHelper(string url, string appKey, string installationId)
   8:         {
   9:             _baseurl = url;
  10:             _appKey = appKey;
  11:             _installationId = installationId;
  12:         }
  13:  
  14:         public AzureMobileTable getTable(string tableName)
  15:         {
  16:             return new AzureMobileTable(tableName);
  17:         }
  18:  
  19:         public string Execute(AzureMobileQuery query)
  20:         {
  21:             string fullUri = _baseurl + query.Uri;
  22:             HttpWebRequest _azureRequest = WebRequest.Create(fullUri) as HttpWebRequest;
  23:             _azureRequest.Headers.Add("X-ZUMO-APPLICATION", _appKey);
  24:             
  25:             _azureRequest.Headers.Add("X-ZUMO-INSTALLATION-ID", _installationId);
  26:             using (HttpWebResponse restResponse = _azureRequest.GetResponse() as HttpWebResponse)
  27:             {
  28:                 Encoding enc = System.Text.Encoding.GetEncoding(1252);
  29:                 StreamReader _jsonStream = new StreamReader(restResponse.GetResponseStream(),enc);
  30:                 return _jsonStream.ReadToEnd();
  31:             }
  32:         }
  33:  
  34:     }

The MobileHelper constructor takes three arguments. The url, the appKey and the installation id. The appKey and the Installation Id are used by Azure Mobile Services to authenticate a request. This is based on a setting in the management portal (You can also choose to authenticate using LIVE Id). You will get the appKey and the url from the management portal. I got the installation id from MobileServices.js (this will be in the request header). At the moment, I don’t know of another way to get it.


The getTable method returns a handle to the AzureMobileTable object. We will take a look at the MobileTable constructor momentarily.


The execute method is the method that does the job. It creates a web request, adds the necessary headers and reads the response returning it as a string. Any response received from Mobile Services is in the JSON format. Pretty simple.



   1: public class AzureMobileTable    
   2: {
   3:     string _tableName = string.Empty;
   4:     private  string tableUrl { 
   5:         get{
   6:             return "tables/" + _tableName;
   7:         }
   8:     }
   9:  
  10:     public AzureMobileTable(string tableName)
  11:     {
  12:         _tableName = tableName;
  13:     }
  14:  
  15:     
  16:     
  17:     public AzureMobileQuery Where(string whereExpression)
  18:     {
  19:         Expression convertedExpression = Expression.Constant(whereExpression);
  20:         if (convertedExpression is MethodCallExpression)
  21:         {
  22:             return null;
  23:             throw new Exception("Invalid Expression");
  24:         }
  25:         return new AzureMobileQuery(tableUrl + "?$filter=" + whereExpression);
  26:     }
  27: }

The AzureMobileTable class in a way, is the glue that sort of holds everything together. It does this very simply, by building the URIs. The constructor takes in the table name and builds the URI for a table by prefixing  tables/.


At the moment, the class only has one filter operation which is Where. It first validates if this is a valid LINQ Expression and if it is, constructs the appropriate URI. I will be adding more operations, but you get the idea. The last class we will see in this post is the AzureMobileQuery



   1: public class AzureMobileQuery
   2: {
   3:     public string Uri { 
   4:         get{
   5:             return _uri;
   6:         }
   7:     }
   8:     private string _uri;
   9:     public AzureMobileQuery(string uri)
  10:     {
  11:         _uri = uri;
  12:     }
  13: }

The class is pretty much self explanatory. The last piece of the jigsaw is the Broker class that initiates the call.



   1: public string getRatingsbyId(int movieId)
   2:         {
   3:             AzureMobileHelper _helperClass = new AzureMobileHelper("<url>", "<appKey>", "<installationid>");
   4:             AzureMobileTable _moviesCollection = _helperClass.getTable("ratings");
   5:             AzureMobileQuery _query = _moviesCollection.Where("MovieId eq '" + movieId + "'");
   6:             if (_query != null)
   7:             {
   8:                 return _helperClass.Execute(_query);
   9:             }
  10:             return String.Empty;
  11:         }

The method instantiates the helper class with app specific url, app key and installation id. As explained before, it then gets a handle to the table that the query needs to be executed on and the actual query that gets executed. The query in this case just filters all entries for a given movie id.


I have consciously not touched on the ratings class because it solves another problem area that I will deal with in the next post. The above code is just an illustration of how services can call Azure Mobile Services.


The fact that Azure Mobile Services is based on REST gives the developers great flexibility on how to access it and what to do with it. I am not sure when the Mobile Services team plan to release a client library for services or if they even plan to, but if you need to access the services from a service, this has hopefully given you a starting point. Happy Coding!!!


Monday, July 2, 2012

Javascript Metro App Search with Web Services

If you are here, it probably means you are not contented with the default search implementation in javascript metro apps. The default search method when you add a search contract is as below

   1: // This function populates a WinJS.Binding.List with search results for the
   2:         // provided query.
   3:         searchData: function (queryText) {
   4:             var originalResults;
   5:             var regex;
   6:             // TODO: Perform the appropriate search on your data.
   7:             if (window.Data) {
   8:                 originalResults = Data.items.createFiltered(function (item) {
   9:                     regex = new RegExp(queryText, "gi");
  10:                     return (item.title.match(regex) || item.subtitle.match(regex) || item.description.match(regex));
  11:                 });
  12:             } else {
  13:                 originalResults = new WinJS.Binding.List();
  14:             }
  15:             return originalResults;
  16:         },




Pay attention to line number 8. The way the search results are populated is by creating a filtered list of Data.items that match the query text. Which means, you should already have items loaded into the app to be able to search from them. But what if, I do not load all the items in the app but want to search for items in my database that I haven’t loaded?


If you haven’t guessed already, that is exactly what this post will show. Be aware that this is not the only implementation that is possible for this. This is just the way I did it. I really did not see any help or a post that shows this, so I thought I will blog about it, just in case somebody is looking for something similar. And just so you know, this was built using Windows 8 Release Preview, so it could be a bit different if you are on Windows 8 CP.


When you add a search contract to your project, there are two methods in searchResults.js that are of interest to us. They are  handleQuery and searchData. You will see that the handleQuery in turn calls searchData and a couple of other methods. The search data method is synchronous because it is only filtering items that have already been fetched. If you want to call a web service when the user searches, then this method has to be asynchronous since all web service calls made using WinJS.Xhr are asynchronous by default.


I am going to add a new method in data.js called searchEventHandler



   1: function searchEventHandler(data) {
   2:     var searchList = new WinJS.Binding.List();
   3:     return new WinJS.Promise(function (c, e, p) {
   4:         WinJS.xhr({ type: "POST", url: localSettings.values["webserviceUri"], headers: { "Content-type": "application/x-www-form-urlencoded" }, data: data }).done(
   5:             function (result) {
   6:                 if (result != null && result.responseText != "") {
   7:                     var jsonData = JSON.parse(result.responseText);
   8:                     for (var i = 0; i < jsonData.length; i++) {
   9:                         //process your results if need be
  10:                         searchList.push(jsonData[i]);
  11:                     }
  12:                     c(searchList);
  13:                 }
  14:             },
  15:             function error(result) {
  16:                 if (result.responseText != "") {
  17:                     var item = new Object();
  18:                     item.title = "Error occurred.";
  19:                     item.group = sampleGroups[0];
  20:                     item.backgroundImage = lightGray;
  21:                     searchList.push(item);
  22:                     e(searchList);
  23:                 }
  24:  
  25:             }
  26:         );
  27:     });



Will take a moment to explain what this method does. It calls the web service passing the query string as a parameter and adds the results to a WinJS binding list. To make this method asynchronous, I have used WinJS.Promise. The method then calls the success or the error call back with the search results as a parameter. With this, we now have an asynchronous method that calls a web service and returns the search results. We now have to call this method from searchResults.js. Add this method to the data namespace, so it can be called from searchResults.



   1: WinJS.Namespace.define("data", {
   2:     items: groupedItems,
   3:     products:productsList,
   4:     groups: groupedItems.groups,
   5:     getItemsFromGroup: getItemsFromGroup,
   6:     searchEventHandler: searchEventHandler
   7: });

The searchData function then needs to be modified as below



   1: // This function populates a WinJS.Binding.List with search results for the
   2:         // provided query.
   3:         searchData: function (queryText) {
   4:             var originalResults;
   5:             //set the criteria to en-us and on-demand
   6:             var criteria = "culture=en-us&eventType=3&kwdAny=" + queryText;
   7:             data.searchEventHandler(criteria).done(function (results) {
   8:                 originalResults = results;
   9:                 searchResults.generateFilters(originalResults);
  10:                 searchResults.populateFilterBar(currentElement, originalResults);
  11:             });
  12:         }



Apart from the obvious change of calling the searchEventHandler, also note that the generateFilters and the populateFilterBar functions are being called from here instead of handleQuery. This is because both those functions depend on the results. I am leaving out more obvious code changes here like making currentElement a class variable.


One last thing that is left to do is to generate the filters. If the filters are generated from the results, then the generateFilters method has to be changed to update your filters after the search is done rather than before. Since it depends on your implementation of the filters, I am not including that code here.


As I stated in the post earlier, there are innumerable variations through which this can be achieved. Please feel free to let me know if you have done this any differently.


Technorati Tags: ,,,