Monthly Archives: November 2013

Uploading image to the web service in WinJS application

Published November 27, 2013 1:07 pm

It is very likely that you need to have functionality to pick single or multiple image(s) and upload to your web service in your winjs windows store application. First, we will go through single image case. I have seen image pick & upload experience very often in facebook and google plus web client. Both of the web clients have ‘native’ experience for picking & uploading image(s). What I mean by native is that they have custom built experience that fits into their overall user experience. You will need to build a custom image select control that will do some or all of these:

  1. Launch picker – On click, launch windows file picker initialized to pick image file.
  2. Display preview – of the selected image. If no image is selected, display a placeholder image.
  3. Store file object – keep the file object picked by the user until it is submitted to the web service.
  4. View – you may need to show the preview of the image that already exists at the web service.
  5. delete command – context menu or other way to let user delete the uploaded image.
  6. download progress – related to (4), show progress while the image is downloading from the web service.
  7. show error – related to (4), show error if the image download fails.
  8. send command to service – to delete or upload the image
  9. show progress of command sent to the service
  10. reduce the size of the picked image before upload to the service.

The above is top down view of all the things related to uploading image in your winjs client. Building a custom control in winjs is a good topic on its own. We will not go over it in this post. This msdn blog post is a good start for building custom winjs control in your project.

Let’s get started.
html:

<img class="select-image" src="images/placeholder.png" />

js:

 
    var page = WinJS.UI.Pages.define('/pages/page1/page.html', 
    {
        ready: function onready(element, options)
        {
             ...
             var img = element.querySelector('.select-image');
             img.addEventListener('click', this.onclick.bind(this));
        }),
        onclick: function onclick()
        {
            var self = this;
            var img = this.element.querySelector('.select-image');
            this.pickSingleImage().then(function onpicksinglefile(file)
            {
                if (!file)
                    return;

                // set the blob to img.src for preview
                var imageUrl = URL.createObjectURL(file, { oneTimeOnly: true });
                img.src = imageUrl;
                // keep file object for upload later
                self.selectedFile = file;
            });
        },
        // launches file open picker initialized to pick an image
        pickSingleImage: function pickSingleImage()
        {
            // Verify that we are currently not snapped, or that we can unsnap to open the picker
            var currentState = Windows.UI.ViewManagement.ApplicationView.value;
            if (currentState === Windows.UI.ViewManagement.ApplicationViewState.snapped &&
                !Windows.UI.ViewManagement.ApplicationView.tryUnsnap())
            {
                // Fail silently if we can't unsnap
                return WinJS.Promise.timeout();
            }

            // Create the picker object and set options
            var openPicker = new Windows.Storage.Pickers.FileOpenPicker();
            openPicker.viewMode = Windows.Storage.Pickers.PickerViewMode.thumbnail;
            openPicker.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.picturesLibrary;
            // Users expect to have a filtered view of their folders depending on the scenario.
            // show file types that are accepted by your service 
            openPicker.fileTypeFilter.replaceAll([".gif", ".jpg", ".jpeg"]);

            // Open the picker for the user to pick a file
            return openPicker.pickSingleFileAsync();
        },
        // returns a promise that completes on upload of the file to the url.
        uploadBlob: function uploadBlob(url, file)
        {
            var data = MSApp.createFileFromStorageFile(file);
            var xhrOptions = {
                type: 'put', // this may be post if your web service expects http post
                url: url,    // url for the web service
                headers: {
                    'Content-Type': 'image/jpeg',
                    'Content-Length': data.size,
                    // TODO - add any other headers that service may expect
                },
                data: data,
            };

            return WinJS.xhr(xhrOptions);
        },

The code above is more or less self explanatory. Few notes:

  1. uploadBlob needs to be invoked by other function when image is to be uploaded.
  2. For uploading image to azure blob, upload code will look similar. you can refer this post.

There we are. Current code will allow to pick, preview and upload an image file to your web service.

It does not cover all the 1-10 things listed above yet. Did your app need it?

Backup and recovery of the azure table storage of the service

Published November 23, 2013 4:12 pm

It is very likely that you come across the problem – How do I ensure safety of my azure service from data-loss? Our service development is in progress. Before we onboard any customer for trial, we need to ensure that his data can’t be lost. In that context, I started with the problem definition as how do I backup & recover azure table storage? The service has maximum data in the table storage.

Very soon, I realized that data reliability of azure table storage is very high. It makes multiple local copies and if geo-rep is enabled, additional copies in another data center. it must be order of 99.9%. I tried to find documented link in msdn for this. Documented SLA of 99.9% is only for availability. Hence, do we need to do nothing for data loss? Actually, we need to handle the data loss protection in following cases:

  1. No data loss during service administration and maintenance. For example: do not execute delete table api in any administration task. This can only be done through very tight control and strict guidelines for the production environment.
  2. Data loss caused by end user in the application. Take for example: email application. user can accidentally delete a mail or folder.

After striking out (1) by following strict documented guidelines – problem can be redefined as – Backup and recovery of the application data of the service. This is typically very specific for the application. For example: email application has very rich experience built into the client application . End user can help himself/herself for any loss of data by recovery the item from ‘deleted items’ folder. He needs to approach the service administrator only if whole mailbox is lost, deleted items folder is deleted, etc. rarely. In our service case, accidental deletions will be rare and can be handled by user raising a request to the service administrator. Hence, service client (app) will not have rich recovery experience built in like it is required in an email client.

How do we backup application data in table storage? It will likely very specific for each service. In our case, current thinking is – to backup each user data separately – to a set of excel (xls) files – providing daily backup. Why excel?

  1. Excel not only provides excellent data access and manipulation, it is de facto standard.
  2. If user wishes to do manual recovery – it can be shared as is with user.
  3. The service needs to be seeded with user existing data. For that also, recovery flow can be used.

Regarding backing each user data separately, it partitions the problem of backing up table storage that will grow in size with number of service users.

Backup format is specific for the service. It is not likely relevant for other services. I need to think about building incremental daily backup yet. Design needs to be implemented. It may likely go through changes as I implement – as in regular cycle of software development.

How do you handle backup and recovery of your application data in service?

Saving and restoring page state in a WinJS application

Published November 15, 2013 1:39 pm

When building a winjs application with multiple pages, there is high chance that you need to save and restore page state of some of the page(s).

First – what is page state and why it needs to be saved & restored? Let’s take few example cases.

  1. User inputs some data provided in a form page. When the form page is navigated back, form page needs to be filled with the same data; not lose data.
  2. Page contains a list view with multiple items; user scrolls to reach an item and clicks it to traverse to the item detail page. When user navigates back, list view’s scroll position should not be reset.
  3. Add another case for case (2). application is suspended when on the item detail page, restored during next activation and start on item details page. In such case also, the listview scroll position should not be lost when navigating back to the list view page.

How to handle this?

In a WinJS application, each page is re-initialized when navigated back. ready event handler is called each time a page is navigated. Hence, to keep the page in the same state – it’s state needs to be saved and restored. WinJS library provides WinJS.Application.SessionState object. It is serialized and de-serialized across application suspension by the library. The page state needs to be saved and restored to/from session state object.

What the code looks like? Let take the case (2).
Initializing, and restoring the scrollPosition state on the list view

 
    var sessionState = WinJS.Application.sessionState;
    ready: function onready(element, options)
    {
        ...
        if (!sessionState.itemList)
            sessionState.itemList = {};
        else if (sessionState.itemList.scrollPosition)
        {
            WinJS.Promise.timeout().then(function ()
            {
                listView.winControl.scrollPosition = sessionState.itemList.scrollPosition;
            });
        }
    },

Saving the scrollPosition state when navigating to the item detail page. The code below is doing that in the iteminvoked handler.

 
    listView.winControl.addEventListener('iteminvoked', function (event)
    {
        var item = this.viewModel.items.getAt(event.detail.itemIndex);
        sessionState.itemList.scrollPosition = textListView.winControl.scrollPosition;
        WinJS.Navigation.navigate('/pages/itemDetail/page.html', { item: item });
    }.bind(this));

That’s it. Few comments before closing.

  1. It will be good practice to keep separation between the state for each page. Hence, the code above saves the scrollPosition state for the itemList page under itemList property in session state object.
  2. The state is restored typically in the ready handler.
  3. The state needs to be saved prior to the navigation to the next page.
  4. scrollPosition is restored under a setImmediate call. otherwise, it does not get restored.

HTH.