Zip Archives Become a First class citizen in .NET 4.5

Compression in the .NET framework has been supported via different libraries in the past (via Open File Conventions) but the support for .zip archives hasn’t quite been complete. With .NET 4.5 we get a dedicated zip compression library that allows us to manipulate zip libraries fully.

Introduction

Up until now, compression in .NET was supported only to the extent of supporting Open File Convention and centered on need to adhere to the convention. As a result the archives created we never fully compliant with the zip archive specs. Introducing the System.IO.Compression.ZipArchive type that now covers all our archive compression and decompression needs. In this post we will see the available features and how we can use them to create various types of archiving solutions.

Features of System.IO.Compression.ZipArchive Type

Single step extraction of existing zip libraries
A zip archive can be deflated in a single step as follows

ZipFile.ExtractToDirectory(@”D:\devcurry.zip”, @”D:\devcurry\”);

This above code extracts the dnc.zip file into the D:\dnc folder.
Single step compression of entire folder
A zip archive can be created from a folder in a single step

ZipFile.CreateFromDirectory(@”D:\devcurry”, @”D:\devcurry.zip”);

This compresses the entire contents of devcurry folder into devcurry.zip
Selected compression of a list of files
Single step compression is fine but often we need to be able to create an archive of a set of files in a particular folder. For example, if you blog often with code samples you need your source code packaged without the bin and obj folders as well as exclude the *.user and *.suo files to prevent user cache information from being distributed. The zip library in .NET 4.5 allows us to create a zip archive of selected files as well.

As we will see in the example below it is a very easy to use and powerful library.
Streaming Access to compressed files
Large zip libraries become a limitation in some archiving tools because attempt to open a big file chokes on lack of system memory and crashes. The Zip library in .NET 4.5 provides streaming access to the compressed files and hence the archive need not be loaded into memory before an operation. For example

using (ZipArchive zipArchive = 
  ZipFile.Open(@"C:\Archive.zip", ZipArchiveMode.Read))
{
  foreach (ZipArchiveEntry entry in zipArchive.Entries)
  {
    using (Stream stream = entry.Open())
    {
      //Do something with the stream
    }
  }     
}

A typical use for this could be while building a web server where you could zip and unzip data on the fly. Another use could be collecting data from Internet streams like Twitter or Github statuses and compressing them directly into an archived file.

Example: Compress a Visual Studio Solution file without binaries and personalization information

Visual Studio 2010 has a nice extension called SolZip. What it does is, it adds right click menu to Visual Studio and on right-clicking the Solution in Solution Explorer is creates a zip file without the bin/obj folders. It also excludes the personalization info in the .user and the .suo file. If you bundle these files along with your project and give it to someone they may just end up with conflicts or folder reference issues.
Coming back to the topic, while doing my previous article on CallerInfoAttributes I was in Visual Studio 2012 and went looking for SolZip. I couldn’t find it. Now while writing this article I realized I could create a command line version of it and demonstrate the power of the Zip library in .NET 4.5

Step 1: Create a new Console Application Project in VS 2012

Step 2: Add Reference to the System.IO.Compression and System.IO.FileSystem

add-reference-to-system-io-compression

Step 3: Setup defaults.

We setup the default parameters for the zip file to exclude the files we don’t want by specifying the extensions and/or the folder names that need to be excluded. Note the folders start with a ‘\’.

initial-setup

CreateArchive is the function that actually does the Archiving and returns number of files archived. Once returned we show the number of files returned and wait for the users to hit enter, when we quit the app.

By default if no parameters are specified, this utility will try to zip the contents of it’s current folder while excluding the files with ‘.user’ or ‘.suo’ extension or files in the either of the bin, obj or packages folders.

Step 4a: Filtering and archiving the files

The CreateArchive method takes in the root folder name from where the archiving is supposed to start, the list of extensions and folders that should be excluded and the name of the final archive.

The Excluded method takes the current file in the list of all files being enumerated, and check if it is in a folder that’s excluded or if it has an extension that’s excluded.

create-exclude-method-signatures

Step 4b: The CreateArchive method

The CreateArchive method takes the source folder path and the provided archive name and checks if the archive already exists. If it does it asks the user if it should be overwritten. If user selects y, then the file is overwritten else the process is aborted.

After confirmation, Directory.EnumerateFiles(…) enumerator opens an enumeration over all files in the source folder including sub-folders. The enumerator returns each file’s relative-path. Once it is determined by the Excluded method that the file has not been excluded we add it to the archive.

create-method

Syntax for opening the Archive and adding the file is highlighted. Couple of notes

The CreateEntryFromFile(…, …) method takes two parameters, first one is the source file path, the second one is the path starting from the folder where the archive is located. For example, Let’s assume we have the following structure.

add-file-parameter

We want all contents of the highlighted ‘SolutionZip’ folder in an archive called ‘Archive.zip’. Now as we loop through all the files and come to the AssemblyInfo.cs in the (highlighted) Properties folder. To add this file to the zip value of

file = .\SolutionZip\Properties\AssemblyInfo.cs
addFile = SolutionZip\Properties\AssemblyInfo.cs

Point to note is the value for addFile HAS to start at the folder in which the zip file is, without that the zip file is unable to show the sub-folder structure in Explorer (even though the zip file is valid).

Step 4c: The Excluded method

- The excluded method first creates a collection of folders in the exception list.

- Next it checks if the file’s extension is in the exceptions list. If present it returns true meaning the current file is excluded.

- If it doesn’t find the extension in the excluded list it goes ahead and loops through the folderNames and check if the current file is in the excluded folder or any of it’s subfolders. If yes, it returns true to exclude the file, else returns false.

exclude-method

That’s it, we have a handy little utility to zip up our solution files without any personalization information. Syntax for it is

C:\> SolutionZip.exe mySolution\ solutionName.zip

Conclusion

With .NET Framework 4.5 we have a powerful and robust Zip archiving utility that can be used in our applications so we don’t need to rely on any third party zip providers.

You can Fork the code on Github or Download the source code here

Using Caller Info Attributes in C# 5.0 to Improve Logging

The problem of passing current method details haunted my team and me when we were asked to add logging to every available business layer method in a two year old project, that had no logging and empty try { } catch { } blocks. We eventually worked around it by using a mix of reflection and string literals to get the current method name. But in my guts I hated the fact that I had to use reflection to do logging. This was 5 years ago using C# 2.0.

Come VS 2012 and C# 5, we will have access to three attributes that do specifically the task that we had hacked around then. These attributes are

  • CallerFilePathAttribute
  • CallerLineNumberAttribute
  • CallerMemberNameAttribute

These can be used in any logging method to retrieve the calling method and log it. In this post, we will see how we can use Log4Net’s rolling file Appender* and the Caller Info Attributes to log errors in an application

Note: Appenders for log4Net are like Providers and serve as an extension point for Log4Net. The RollingFileAppender logs errors to a file and rolls over to a new file if the current file passes certain criteria like a date based roll over or size of file based roll over. You also have SQL Appenders and Xml Appenders and host of log outputs possible using Log4Net.

Starting off with a Console Application

Create a new Console Application in Visual Studio 2012 (aka VS 11)

main

We will simply log key-strokes as input at the Console window and depending on type of keys pressed throw exceptions with different methods. We end the execution when users press the Escape key. The code for this is in the LoopInfintely() method shown below.

loop-infinitely-method

To show that the Caller Info Attributes work at the method level we are logging Errors from a method called LogError as shown below

log-error-method

Logger class above is a Singleton wrapper around Log4Net. Before we look at the code for it, let us see the steps to install and configure Log4Net.

Setting up Log4Net

If there was ever anything to complain about Log4Net it was setting up a basic workable Appender in one go. Thanks to Nuget and the Community that has been rectified. Install Log4Net using the following command in the Package Manager Console

PM> install-package log4net

Next install a Rolling File Appender configuration using the following package

PM> log4net.samples.rollingfileappender

The above inserts the following configuration section in the App.config

log4net-config-declaration

The configuration section is as follows

log4net-config

With this as a default, Rolling File Appender has been setup that rolls over daily. We have updated the file location and the converstionPattern as highlighted above. The conversion Pattern ensures the fields are Pipe ( | ) separated, making them easy to import into excel and monitor.

With Log4Net in place let’s implement our Wrapper class Logger

Implementing the Log wrapper – Logger

The Log wrapper is a singleton class that creates one instance of the Log4Net logger and exposes methods for logging different levels of messages. For example it has methods Error, Warning and Debug to log corresponding levels in Log4Net.

It is initialized as follows

initialize-log4net-viewer

The GetLogger factory method initialized the LogManager.

The log4net.Config.XmlConfigurator.Configure() uses the configuration defined in the App.config

The Initialize method is called the first time _log is used. We have a guard clause to check if _log has been initialized. If not, the Initialize() method is called.

Using the Caller Info Attributes and Logging

So far we have a sample application that waits for key-strokes at the console and throws exception with different messages depending on what type of key is hit. Numeric keys result in Debug level logs, Function keys result in Warning level errors and all others result in Error level logs.

Now we look at the wrapper functions in our Logger class and see how we are obtaining trace information. As seen below we have three attribute decorated optional parameters called memberName, sourceFilePath and sourceLineNumber. These are decorated with the Caller* attributes. We can now very easily use these input params in our logs as shown below. The beauty of the implementation is ONLY your logger wants this information so it is specified only in the logger not in every method call to the logger. This by my standards is Magic!

logging-code

Digging Deeper Into Caller Info Attributes

Actually there is not much of magic here, if you notice the three pieces of information they are static once the code is compiled. So the compiler simply replaces the optional parameters with the static values of MethodName, FilePath and SourceLineNumber in the method call at runtime. Basically the compiler is writing a bit of code/text for us at compile time.

Looking at the Logs

I had initially specified the log format to be pipe ( | ) separated. So we can open the file in Excel and specify custom separator as ( | ). Part of the log looks as follows

log-messages

As we can see in Column D we have the details of the Method (where the error occurred), the File in which it occurred and the line number at which the error occurred. The Debug and Warn logs were from the LoopInfinitely whereas Error logs are from the LogError method. In column E we have the exception message and as we can see we have thrown messages based on type of keys typed.

Conclusion

The caller info attributes have primarily been added to aid runtime debugging and error handling. This is a very robust low-level language support.

As seen above it greatly helps writing better trace routines for runtime issue debugging. Also they are simply optional parameters, so you can at any point override the default values and pass in custom values in the parameters.

The Caller Info values are emitted as actual strings into IL at compile time and are not affected by obfuscation.

Another use for the CallerMemberName attribute is implementation of the INotifyPropertyChange interface. Without the CallerMemberName we would need to pass in the property name as a mandatory parameter.

Fork this on Github or Download the entire source code

Reference

http://msdn.microsoft.com/en-us/library/hh534540%28v=vs.110%29.aspx

Retrieving Gravatar using jQuery

If you have an account with Wordpress or Github, you might have seen them requesting you to setup your Gravatar image so that they can associate it with your account. You can easily set one up and it gets associated to your email address. Now multiple services can choose to simply choose to use your email address to show your Gravatar when you specify your email address, for example when you are providing your email address to submit comments. In this example we will see how we can retrieve the Gravatar for a given email address and use it in our custom applications.

Retrieving a Gravatar

Given an email address, retrieving a Gravatar is quite simple. You have to calculate the MD5 hash of the lowercase and trimmed email address. Once you have the hash, you append it to the URL - http://www.gravatar.com/avatar/<the calculated hash>.

Now you can use this URL in an image tag to show the image.

The default image size returned is 80x80 px. You can specify sizes from 1px to 512px. Depending on original resolution of the image, bigger sizes may get pixelated. To specify size, you pass the query string s=<size> e.g. s=100. So a request URL would be http://www.gravatar.com/avatar/<the calculated hash>?s=100

By default gravatar.com will return the default image hxxp://www.gravatar.com/avatar/00000000000000000000000000000000

If we want we can specify our own image using the query parameter d=<escaped http url of default image>

Creating a Simple Contact List and Retrieving Gravatar

We will create a simple Contact List sample and see how we can use the Gravatar feature.

Step 1: We start off with a default ASP.NET MVC basic template application. If you are not an ASP.NET developer, you can ignore the ASP.NET part and do all of this in an HTML page itself. There is no server side code involved.

Step 2: We add a button that will invoke a input dialog to take a new contact detail

add-contact

Step 3: We add the contact details markup in the Index.cshtml as follows

add-contact-popup

This has three fields that take the Name, Address and Email. In a real life application, we could ask for more parameters.

Step 4: This will be a popup that will be triggered from the ‘Click to Add Contact’ button. We will use jquery-ui’s Dialog plugin to render the inputs in a dialog. The outmost div acts as the dialog container.

We add a javascript file – gravatar-sample.js to the project and setup the dialog as follows

$(function () {
    $("#addContactPopup").hide();
    $(document).on("click", "#addNew", function () {   
        $("#addContactPopup").dialog({
            minWidth: 400,
            width: 500,
            maxWidth: 600,
            title: "Add New Contact",
            buttons: [
                {
                    text: "Add",
                    click: function () {
                        var user = {
                            "Name": $("#nameText").val(),
                            "Address": $("#addressText").val(),
                            "Email": $("#emailText").val()
                        };
                        contactAdd(user);
                        $("#nameText").val('');
                        $("#addressText").val('');
                        $("#emailText").val('')
                        $(this).dialog("close");
                    }
                },
                {
                    text: "Cancel",
                    click: function () {
                        $(this).dialog("close");
                    }
                }]
        });
});

The $(function () {}); is the jQuery shortcut for document.ready.

- Once the document is ready, we hide the ‘add container’ div (id=addContactPopup).

- Next we hook up the ‘click’ event of the ‘addNew’ button.

- In the handler function, we setup the ‘addContactPopup’ div to be used in a jQuery dialog. We specify a bunch of parameters for the height, width, title and buttons. For the buttons we also define a click event handler.

o Add click: When the user provides the contact information and hits Add, the click event handler fires.

  • It creates a user object with three properties Name, Address and Email.
  • Calls the contactAdd method to render the new contact
  • Clears out the input boxes
  • Closes the dialog

o The Cancel click event handler simply closes the dialog

contact-as-method

Step 5: We implement the contactAdd method that takes the newly added User and adds it to the Contact List on screen.

- We first pick out the <ul> element inside which we will be adding the list items.

- Next we call the calculateGravatar method to generate the Gravatar url for use from the email address.

- Finally we use the prepend method to add a list item to the contact list. We format the element inline. Ideally we could use a templating engine like Knockout or jsRender.

Step 6: Calculating the MD5 hash for the Gravatar URL

Calculation of the MD5 hash, is achieved via the excellent Crypto library by Jeff Mott at http://code.google.com/p/crypto-js/

calculate-gravatar

It is an extensive JavaScript library for hashing and encryption. You can download the entire library and from the rollup folder just pick the md5.js. It is a self-contained MD5 hashing implementation.

In the above code, we make sure the email address passed is all lower case and has no leading or trailing spaces. We use the toLowerCase() and trim() methods.

Generating the hash is just a single line call that takes the email as input and returns the hash. The Gravatar url is then create by appending the hash to the URL and ending it off with .jpg so that we can use it in the image tag directly.

Putting it all together

With all in place, we can now build our contact list with Gravatar.

- Click on the ‘Click to Add Contact’ button to bring up the New Dialog.

- Provide the details and click on Add

contact-list-add-new

- The Gravatar takes a second or two to come through and the new contact is added before the existing name in the list.

contact-list-two-people

- We add one more contact and the list wraps around.

contact-list-final

There we go, the who’s-who of .NET community (okay, okay I am kidding myself about that third dude at the bottom ;-)…)

Conclusion

When creating a contacts app or a blog app with comments, it is cool to have the Gravatar of the person show up. In small ways it verifies the person and if they are using a real picture gives a face to a name. With this little utility you can now add this extra polish to your overall Web Application.

The code is on github for your reference, here. You can download the zip, here.

Reference

http://en.gravatar.com/site/implement/

Note: Gravatars of Ayende Rahien and Scott Hanselman used with permission.

ASP.NET MVC: Handling Exceptions and 404 Errors

In a previous article, we saw how to use ELMAH for managing unhandled errors in MVC applications. If for some unique scenario, ELMAH does not handle your needs, you can fallback on the default HandleError Attribute in MVC. In this article, we will see how we can use the HandleError attribute to quickly put together an exception handling mechanism that helps hide the ‘dark’ underbelly of your application but helps you debug with the same configuration. We will also look at a solution to handle 404 errors gracefully.

Overall we try to achieve the following on IIS 7+

Goal 1 - Use MVCs HandleError action filter to take care of Unhandled/Unexpected errors
Goal 2- See only user friendly messages at Runtime
Goal 3 - See exception stack traces at debug time
Goal 4- Manage 404 error with a proper error message
Goal 5 - Keep a 404 Response status

The HandleError Attribute

The HandleError attribute helps mark controller classes for ‘Unhandled Error’ exceptions. The HandleErrorAttribute() attribute filter will pipe the Unhandled exceptions to this attribute filter enabling you to take appropriate exception. The attribute filter is put in place by the default MVC template in the Global.asax (or for MVC4 in the App_Start\FilterConfig.cs) by adding the Action filter as follows:

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
  
{
      filters.Add(new HandleErrorAttribute());
  
}

By default, if you turn on CustomErrors, the behavior of the HandleErrorAttribute is to redirect you to the default Error page.
Setting up the Custom Errors page
Setup of the Custom Errors page is easy. We simply turn on the CustomErrors in the web.config.

custom-errors-on

To Test the setting we throw an exception in the ‘About’ action method of the Home Controller


public ActionResult About()
  
{
  
   ViewBag.Message = "Your app description page.";
  
  throw new ApplicationException("Testing default ErrorHandler attribute");
  
    //return View();
  
}
Now when we run the application and click on ‘About’ we see the following
exception-default-500

This is the default output from Errors.cshtml in the Shared folder of a default MVC project. As we can see, it returns a correct 500 status message.

At this stage, we have achieved the first and second goals we set out to achieve. However we have lost the stack trace.

Let us fix that without loosing out on the current behavior.

Updating Error Page to show stack trace

- Open the Error.cshtml and update it as follows

error-page-update-1

This change will ensure we see a stack trace. But as of now, this is no better than the Yellow Screen of Death because End Users are going to see it as well. We have lost our second goal of presenting User Friendly error messages.

To fix that problem, we use the Request.IsLocal property that tells us if the Request is coming from the Local machine or a Remote machine.

error-local-and-remote

With this change we have our goals, 1,2 and 3 covered. On to 404 Handling!


Handling 404 Errors

404 Errors are a little trickier to handle in ASP.NET MVC. We will walk through the following steps to nail all kinds of 404 errors in our application

Step 1: To start off with, we will update our Web.config to route 404 errors to a different view called ‘FailWhale’

web-config-404

Step 2: Add an empty View in the Shared folder and call it FailWhale.cshtml

Step 3: Add an empty Controller called ErrorController and update it with an action method as follows

error-controller

We are updating the Response.StatusCode to 404 so that robots scanning the URL get the 404.
  • We are setting the TrySkipIisCustomErrors = true so that IIS doesn’t try to hijack the 404 and show it’s own error page. Without this, when remote users try to navigate to an invalid URL they will see the IIS 404 error page instead of your custom FailWhale page.
  • Finally we are returning the default “FailWhale” view.
Step 4: Update the Routes (RouteConfig.cs in MVC4) to send the 404 error view to the Error Controller

global-asax-fail-whale-route

Logging the 404 error

The 404 error is not available in the above ErrorController because ASP.NET has already handled the error, bubbled it up to the routing framework that is using the web.config setting to route the request to the ‘redirected page’. Essentially it is a 302 redirection. To log the error, we have to handle the global Application_Error event and update the Global.asax as follows

global-application-exception

Logging other Errors

To log all other errors centrally, we have two options

Option 1: Overriding the ErrorAttribute can create a custom ErrorAttribute class like HandleAndLogErrorAttribute and registering it as the Error Attribute Filter as shown below

handle-and-log-error-attribute

register-custom-error-attribute

Option 2: Create a base Controller type and override the OnException method and Log there. Then make sure all your controllers derive from this custom controller type. This is probably a roundabout way of doing things. Managing a Loggable ErrorAttribute keeps the responsibility of logging with the dedicated ErrorLogging filter.

Putting it together and testing it out

To test it out we need the following errors

1. A generic unhandled exception to test out the ErrorHandler attribute filter

2. A 404 because of an invalid controller

3. A 404 because of an invalid action on a valid controller

4. A 404 thrown because of a server side result like Id not found

For each of these, we setup the Index.cshtml with additional Action links as follows

invalid-action-links

As seen above, the First link points to a non existent Controller called ‘UnHandledError’

The Second link points to a valid controller Home but invalid action called ‘InvalidAction’

The Third link point to a valid controller and Action method called ServerSide404 to which it passes the Id value 99.

Finally we have the About link, for which we will manipulate the Action method to throw an exception that we will not handle and let it propagate all through the stack.

The Controller code looks as follows

server-side-404

Now if we I publish the site on IIS, the Home Page looks as follows

home-on-iis

Clicking on any of the ‘Invalid Controller’, ‘Invalid Action’ and ‘Invalid Values’ node will take us to the ‘Fail Whale Page’ like below:

fail-whale-local

Navigating to the same page from a remote machine will show us the same error

fail-whale-remote

More interestingly if we click ‘About’ we get different content based on where we are calling it. The local page shows the stack trace whereas the remote file only shows a message.

error-remote

Unhandled exception as seen on a browser in a remote machine.

error-local

Same unhandled error as seen on the browser in local/development machine.

Conclusion

Managing unhandled exceptions in Web Applications gracefully adds a level of polish to any app. ASP.NET MVC comes with a barebones setup out of the box via the HandleError action filter. In this article, we explored how to leverage this filter as well as one (of many) technique to handle HTTP 404 (not found) errors gracefully.

Even better, the configuration is seamless and we need to do any setting change from Dev to Production.

Download the code here

Using Infragistics jQuery Mobile Controls to Create a Mobile App

This post is written by guest blogger Damyan Petev

With the jQuery product, Infragistics envisioned business intelligence and data visualization across a range of platforms, not just one – more like every single one of them. Built on popular and largely supported HTML5 and jQuery UI and striving to provide a comprehensive toolset for development of performing and stylish applications that are to run on every device regardless of the OS. On top of that ‘mobile' was a subtle, yet dominant theme across our product line with the latest release. Touch support and metro themes everywhere!

But there’s more to it – the jQuery UI is awesome and will run on just about any modern browser, yet it was not specifically designed for mobile devices, not until recently anyway! jQuery’s Mobile framework is- still relatively fresh, but it is just what you might need – it’s touch optimized, it’s compatible with with most smartphones and tablets and other frameworks(like PhoneGap). It is designed to be lightweight and its UI controls designed for pocket-size pages and touch, but it’s not limited to that, as mobile pages will scale to the screen so it would work and look just as good on a bigger tablet and even a desktop(check out their demos using nothing but the framework). As with JQuery UI, it’s a strong cross-platform solution with a different perspective but the same goal – beautiful, powerful, universal solutions to your app problems. It sounds too good to miss, right? We thought so too…

Enter the Infragistics jQuery Mobile controls

With this release besides all controls taking on a touch-friendly nature, our NetAdvantage for jQuery family grew with specialized mobile controls leveraging the jQuery Mobile framework – the Mobile List View and a mobile version of the Rating. As explained, with them the focus is on mobile-centric and gesture-friendly UI. That means optimizations for mobile devices for stuff like better content placement and some specific interactions along with touch support – larger UI elements to interact with and specialized events like tap hold, swipes, etc.

The List view

Sometimes for small screen devices like smartphone, a full-fledged grid control would be somewhat hard to imagine and hardly optimal in terms of productivity. It’s why mobile design, while trying to fit as much functionality in a limited space as possible, must not clutter or expect to fit everything in one page. This is why the mobile framework provides AJAX based navigation between pages (and by pages I mean their mobile version and multiples can very well exist in one html file). This is also where a control such as the list comes in play – think of it as the mobile version of the grid type control – it fits the environment well, it’s easy to interact with, it can hold a lot of data and it can be hierarchical! The igListView is a widget that implements a hierarchical (nested) mobile list. Defining can be done in both in the well-known JavaScript/jQuery or using our ASP.NET (MVC) helpers. There’s also a third method that is also the default method for the mobile framework – a pure markup definition that also has some plus sides. Settings are made via the HTML “data-*” attributes that are mostly for data storage and ignored by browsers when interpreting UI. So for a list you can simple define the standard UL and LI elements and if for some reason jQuery scripts fail to load or execute the browser would still have valid UI to render.

Now that approach wouldn’t be very appropriate if you need some serious amount of data and the Infragistics Mobile ListView comes with a major data support enhancements, one of which is templating. That means not just controlling the markup of each record but also defining a single UL-LI element and point the widget to data and it will template it appropriately. The other major additions to data handling:

  • Search filtering with the added option of presets
  • Using the Infragistics Data Source means the controls can bind to a variety of sources
  • Sorting, sorting presets and groups separated with list deviders.
  • Load on Demand capabilities

iglistview_grouping_ios_default_1

The Rating

The mobile version of the rating control designed for touch means accuracy levels are restricted to whole numbers (or alternatively rounded to halves when the control is in read-only mode). The widget offers settings to control its layout along with getting and setting value, vote count and a changed value event along with the framework’s touch-oriented ones. And as expected you can always tweak the items the rating is using to some other shape or color.

igrating_ios_2

Style

As you can tell by the screenshots above we’ve designed a beautiful iOS style theme for our mobile controls. And for any of you familiar with jQuery UI you’d expect a common and powerful themeing framework to be in play for mobile as well – and there is! Our theme will style all default UI components as well and it can be replaced with one of your own. And yes, there’s a ThemeRoller for jQuery Mobile! It’s very easy to use – all mobile themes have 3 swatches that are usually used for default layouts and actions. Just like that our iOS theme has 3 swatches – a light C (default) swatch seen above with the list, darker B and the A swatch (the one with the exquisite fabric background above). I’ve made a theme myself for what was like 10 min in a metro-style attempt and I’ve included it in the demo just in case someone likes it:

iglistview_grouping_metro_3

 

A Mobile App

Let’s see how easy it can be to create a mobile app that is functional and stylish. We’ll stay on the wave of new technology for the demo and create this app using the new mobile template in ASP.NET MVC 4! What would that do is it would lay all the basic layout of the app for you – referencing all jQuery scripts (mobile included) and styles, bundling and minifying them. It would also render your Views in the mobile version of a page by marking the content DIV with data-role="page". So all left to do is add the Infragistics Mobile Loader ask for the control you need and define it. For this demo I’ll use Northwind again with two actions in the controller returning JSON serialized parts of it for an somewhat odd-styled manual load on demand scenario for the details of each list item (again this is different from the load on demand feature the igListView has which allows the end-user to request another portion of data to be loaded for his current list). Here’s the snippet for the list:

  1. <script>
  2.     $.ig.loader({
  3.         scriptPath: "../../Scripts/Infragistics-mobile/js/",
  4.         cssPath: "../../Content/Infragistics-mobile/css/",
  5.         resources: "igmList.Filtering.Sorting",
  6.         theme: "@ViewBag.Theme"
  7.     });
  8.  
  9. </script>
  10.  
  11. <ul id="actionFedList"
  12.     data-role="iglistview"
  13.  
  14.     data-auto-generate-layouts="false"
  15.     data-data-source="/Home/Customers"
  16.     data-bindings-header-key="ContactName"
  17.     data-bindings-primary-key="CustomerID"
  18.     data-bindings-text-key="Country"
  19.  
  20.     data-auto-generate-layouts="false"
  21.     data-initial-data-bind-depth="0"
  22.     data-bindings-details-title-key="CustomerID"
  23.  
  24.     data-sorting="true"
  25.     data-sorting-type="local"
  26.     data-sorting-auto-generate-sort-presets="false"
  27.     data-sorting-presets='[ {"text":"Customer ID","sortedFields":[ {"fieldName":"CustomerID","direction":"asc"} ]}, {"text":"Contact Name","sortedFields":[ {"fieldName":"ContactName","direction":"asc"} ]}, {"text":"Country","showGrouping":"true","sortedFields":[ {"fieldName":"Country","direction":"asc"} ]} ]'
  28.     
  29.     data-filtering="true"
  30.     data-filtering-type="local"
  31.     data-filtering-search-bar-field-name="ContactName,Country">
  32.     <li>              
  33.                     <ul data-role="childLayout"
  34.  
  35.                         data-auto-generate-layouts="false"
  36.                         data-data-source="/Home/Orders"
  37.                         data-bindings='{"customerId":"CustomerID"}'
  38.                         data-inset="true"
  39.                         data-generate-compact-jsonresponse="false"
  40.                         data-bindings-count-key="Freight"
  41.                         data-key="CustomerID"
  42.                         data-bindings-header-key="OrderID"
  43.                         data-bindings-text-key="ShipName"
  44.                         >
  45.                     </ul>
  46.                 </li>          
  47. </ul>

 

Note i have my theme set using the MVC dynamic ViewBag and I choose (and let users choose) a theme and call the controller action with that theme. Since I can’t put comments I’ve grouped code to be easier to see which part does what. The magic combo here is data-role="iglistview”. Also note the data source can be a link (it’s the igDataSource after all) so local JSON, actions results, services, XML, oData and so on – check! Defining header and text key are the properties in your data to be displayed for each record, the initial bind depth set to 0 will let the list know we have provided just the data for the main list (otherwise the list will ignore those layouts since child data is not loaded). Sorting and filtering are truly easy to enable with just a property and you can also customize them with presets and in them setting "showGrouping":"true causes the list to group the sorted results just like the screeenshots above. And yes you can define custom sorting functions and group comparers if you so desire, but for our basic demo there’s no need. In the child layout we again set the source to a actiong link and the data-bindings='{"customerId":"CustomerID"}' property instructs the list to include this as part of the links query so we can send the data for the right customer and the result:

iglistview_ios_details_4

This sub-page is all auto-generated for you, navigated to using AJAX, back button and history maintained!

Adding the rating is just as easy, again either through markup, helpers or initializing with script. Also as we mentioned you have the ability to now develop against specialized touch events so you can provide that little extra interaction to mobile users – we would use the long tap gesture to reset the rating and also handle the changed event:

  1. @using Infragistics.Web.Mvc
  2.  
  3. <script>
  4.     //load the resources:
  5.     $.ig.loader({
  6.         scriptPath: "../../Scripts/Infragistics-mobile/js/",
  7.         cssPath: "../../Content/Infragistics-mobile/css/",
  8.         resources: "igmRating"
  9.     });
  10.     // show the changed value
  11.     $(document).delegate("#rating", "igratingvaluechange", function (evt, ui) {
  12.         var voteCount = $(".selector").igRating("option", "voteCount");
  13.         $("#ratingValue").text("Rated: " + ui.value + " star(s)!");
  14.     });
  15.     // reset the rating on tap hol
  16.     $(document).bind("#rating", "taphold", function (evt, ui) {
  17.         if (!Modernizr.touch) {
  18.             return false;
  19.         }
  20.         $("#rating").igRating("value", 0);
  21.     });
  22. </script>
  23. <h2>
  24. some rating</h2>
  25. <P> Tap to set value, tap and hold to reset (zero). </P>
  26. <!-- Markup defined -->
  27. <div id="rating" data-role="igrating" data-value="3">
  28. </div>
  29.  
  30. <p id="ratingValue"></p>
  31.  
  32. <p> Read-only Rating defined with the MVC helper:</p>
  33.   @(Html.InfragisticsMobile().Rating()
  34.         .Value(4)
  35.         .ReadOnly(true)
  36.         .Render()
  37. )

You can get and set rating’s value and vote count at all times and the changed event offers both the new and old values along with regular references to owner and so on. Read-only mode rating converts to a smaller form (no longer need to be big enough to be touched):

igrating_readonly_ios_5

And, lastly, you can always override the default images or their locations to change the appearance of the control to match your theme. Below I’ve change the non-iOS default stars for the rating form yellow to blue to match my theme’s looks:

igrating_metro_6

Wrapping Up

If you want to build a mobile friendly app, the jQuery Mobile framework is an excellent choice and we are offering that extra functionality for you to take advantage of – hierarchical list with templating, advanced filtering, sorting, grouping and impressive load on demand features and support for a wide array of data sources and a beautiful mobile rating optimized for touch interactions to truly score you those five stars! And there’s a bonus – everything is optimized for mobile devices, but it looks and works perfectly good on a desktop as well!

I strongly recommend to take a closer look into jQuery Mobile and check out our awesome samples (there are codes in there for you to scan and try them on you mobile device too!). Also you can download a fully functional unlimited trial of NetAdvantage for jQuery and the Demo Project for this Blog – an APS.NET MVC 4 mobile application you’ve seen bits from above and should definitely try!