Part 3/5: Push and display images in real-time from your windows phone media library using SignalR to an azure hosted website.

Creating and hosting a windows Azure website in ASP.NET MVC

In this part of the tutorial, we are aiming to create an ASP.NET MVC website which we would eventually host in Azure as a simple Azure website; no worker roles, no web roles. The website’s functionality is listed below

  1. Display a QR code that can be read by a QR reader (on the phone)
  2. Host a SignalR hub which can accept instructions from a client, this would eventually receive a url of the blob where the image is stored and the random string generated for the QR Code.
  3. Push the data (image) to the website with SignalR.

At this point it is important to explain the whole relationship between QR codes and SignalR. As discussed earlier, the SignalR framework enabled you to push content, real-time from a server to a client as soon as the data as available. This negates the need for a client to periodically call a server for new data, utilising precious CPU resources, you simply get a call from the server when the data is available (at least for modern browsers).

Typically, when you broadcast a message via SignalR, you send it to all clients that are listening for the message. For our specific requirement, we only want to send the message to a specific client, the user who has initiated the photo transfer. In order to achieve this, we need to create a specific group to broadcast to. The name of the group, as you guessed it, will be a random generated string of 5 characters. The QR code displayed on the webpage, embeds these characters in an image. When the phone reads the QR code and is able to decode these set of characters, the 5 letter string along with the uri of the image blob to display is sent to the server. The server is then able to broadcast the message to clients subscribed to that group.

Preparing the website

Create a new empty MVC 4 website. Name the project “PhoneToWeb.UI”.

New MVC website

Install the following packages via nugget

  1. PM> Install-Package ZXing.Net By (http://zxingnet.codeplex.com/)
  2. PM> Install-Package Microsoft.AspNet.SignalR By Microsoft
  3. PM> Install-Package Microsoft.AspNet.Web.Optimization By Microsoft

Create a new class underneath the “App_Start” folder called “Startup.cs” with the following line of code to ensure that SignalR is wired up properly.

using Owin;
using Microsoft.Owin;

[assembly: OwinStartup(typeof(PhoneToWeb.UI.App_Start.Startup))]
namespace PhoneToWeb.UI.App_Start
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.MapSignalR();
        }
    }
}

To create the default page, create a new empty MVC controller titled “HomeController” in the Controller folder. Create a new folder in the Views folder titled “Home” and within it, create a new View titled “Index.cshtml”.

Run the project to ensure everything works okay.

Page layouts, CSS and scripts inclusion

Create a new folder within the views folder called “Shared”. Add a new View to the folder called “_HomePage.cshtml”. Create a new view within the Views folder titled “_ViewStart.cshtml”.

_ViewStart Content

@{
    Layout = "~/Views/Shared/_HomePage.cshtml";
}

_HomePage Content

@using System.Web.Optimization
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>@ViewBag.Title</title>
    @Styles.Render("~/Content/Gallery.css")
    @Scripts.Render("~/Scripts/jquery-1.6.4.min")
    
    <!--Reference the SignalR library. -->
    <script src="/Scripts/jquery.signalR-2.0.1.min.js"></script>
    <script src="/signalr/hubs"></script>
</head>
<body>
    @RenderBody()
    @RenderSection("scripts", required: false)
</body>
</html> 

Create a new folder within the root of the project titled “Content”. Add a new style sheet titled “style.css” within it.

Style.css content

body {
    font-family: "Segoe UI Light",Open sans,sans-serif;
    font-size: 1.3rem;
    line-height: 1.3;
    background-color: #efefef;
}

#page-container
{
   width: 50%;
    margin: 0 auto;
    border: 0px solid red;
}

#qr-container
{
    height: auto;
}

#image-container
{
    height: 300px;
    display: none;
}

img
{
     display: block;
    margin-left: auto;
    margin-right: auto
}

h1
{
    text-align: center;
}

span
{
    color: purple;
    font-weight: bold;
}

Setting up the main page

Our basic page consists of two divs, one to display the QR image, the other to display an image once the QR code is read and a client to server connection is established for push content delivery.

To keep things simple, the model for the page is a simple string, right at the top of the page, define the models as

@model string

Back to our controller, to display the QR code, we need to use the ZXing.Net library that was included as a nugget package. Include the following namespaces in the HomeController.cs

using ZXing;
using ZXing.Common;

For the GET action on the controller, we simply want to generate a simple 5 letter random string. I will use a Guid, truncating the characters before it. You should simply use any of your random string generator extensions here if you wish.

public ActionResult Index()
{
    return View("Index", (object) Guid.NewGuid().ToString().Substring(0, 5));
}

For the QR Code, we define an action method that accepts a string and converts the string into a QR image.

The HomeController.cs should now look like

namespace PhoneToWeb.UI.Controllers
{
    using System;
    using System.Web.Mvc;
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.IO;

    using ZXing;
    using ZXing.Common;

    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            // Casting to object so that the overoad ("View name", "Master Name") does not kick in. 
            // Feel free to use a ViewBag if you prefer magic strings :).
            return View("Index", (object) Guid.NewGuid().ToString().Substring(0, 5));
        }

        [AcceptVerbs(HttpVerbs.Get)]
        public ActionResult ImageRender(string identifier)
        {
            IBarcodeWriter writer = new BarcodeWriter
            {
                Format = BarcodeFormat.QR_CODE,
                Options = new EncodingOptions
                {
                    Height = 480,
                    Width = 640
                }
            };

            using (Bitmap b = writer.Write(identifier))
            {
                return new FileContentResult(ToByteArray(b), "image/jpeg");
            }
        }

        private static byte[] ToByteArray(Bitmap image)
        {
            byte[] data;
            using (var memoryStream = new MemoryStream())
            {
                image.Save(memoryStream, ImageFormat.Bmp);
                data = memoryStream.ToArray();
            }
            return data;
        }
    }
}

Finally, from the View, we need to call the image render action, with the model’s assigned string, and voila, we have a QR Image.

SignalR Hub

To create the hub, Create a folder titled “SignalRHubs” and a Class within it titled ImageHub. SignalR requires that the class inherits from the Hub class. The class should have a simple method called “PushContent”, accepting two parameters as its signature, the QR code and the image blob URI. The complete hub code is listed below

namespace PhoneToWeb.UI.SignalRHubs
{
    using Microsoft.AspNet.SignalR;

    public class ImageHub : Hub
    {
        public void PushContent(string identifier, string blobUri)
        {
            this.Groups.Add(this.Context.ConnectionId, identifier);
            
            //Clients.All.broadcastMessage(blobUri);
            Clients.Group(identifier).broadcastMessage(blobUri);
        }
    }
}

JavaScript

Now the fun part, JavaScript! Essentially, in the view, create a script section, for initialising and subscribing to notifications from the hub at the client. The requirements here are simple

  1. Create a connection that listens to hub notifications
  2. When a notification comes in, check to see if the QR image div element is hidden, if not, hide it.
  3. Likewise, check to see if the image display pane is visible, if not, make it visible.
  4. Set the image from the Uri.
@model string

@{
    ViewBag.Title = "Phone To web";
    Layout = "~/Views/Shared/_HomePage.cshtml";
}

<div id="page-container">
    <div id="qr-container">
        <h1>
            QR Code:  <span>@Model</span>
        </h1>
        <img src="@Url.Action("ImageRender", new { identifier = Model })" alt="QR Code" />
    </div>
    <div id="image-container">
        <img id="imageBlob" src="/" alt="Image to render" title="Image to render" />
    </div>
</div>

<script type="text/javascript">

    var galleryInstance = {
        Initialized: false
    };

    $(function () {

        // Declare a proxy to reference the hub. 
        var gallery = $.connection.imageHub;

        // Create a function that the hub can call to broadcast messages.
        gallery.client.broadcastMessage = function(uri) {
            //Check to see if it has already been initialised
            if (galleryInstance.Initialized === false) {
                //Grab the QR Pane and hide it
                $("#qr-container").hide();
                
                //grab the gallery pane and show it.
                $("#image-container").show();
            }
            
            //Now set the image source.
            $("#imageBlob").attr("src", uri);
        };
        
        //Start the connection...
        $.connection.hub.start(function () {
            //console.log("Connection started");
        });
        
        // Bind any events when connection has started and is ready
        $.connection.hub.start().done(function () {
            //To Test this on the page, create a button with an id of "broadcast" and click.
            //$("#broadcast").click(function () {
                //console.log("server called");
                //gallery.server.pushContent("@*@Model*@", "http://static.bbci.co.uk/frameworks/barlesque/2.59.4/orb/4/img/bbc-blocks-dark.png");
            //});
        });
    });
</script>

Hosting the website in Azure

At present, Windows Azure websites enables you to create up to 10 free websites. There are restrictions, one of which is that you cannot run production websites on this package. This is OK for the purpose of this tutorial.

Create the Website

New Windows Azure website

  1. Go to manage.windowsazure.com
  2. Sign in with your windows azure credentials.
  3. Select the New button at the bottom of the portal
  4. Select Website > Quick Create
  5. Set the URL to whatever you wish, I’ve set mine to “phonetoweb” implying that my website URI will be http://phonetoweb.azurewebsites.net . I’ve opted to go for a western Europe primary data centre
  6. Select create Website, this should spin up a new website for you within minutes.

Publish the website

To publish our website to the newly created azure website,
New Windows Azure website

  1. Select your newly created website in the portal
  2. Download your publish profile, store it somewhere on your computer.
  3. Go to your visual studio MVC web project, Right click on the project Name “PhoneToWeb.UI” and select publish
  4. You should have a new publish window, within the profile tab, import your new azure publishing profile that you just downloaded. This should now take you to the connection tab, you may validate the connection if you wish.
  5. Select Publish, this should push the website into the cloud. When successfully published, the website should be launched in your default browser

New Windows Azure website

New Windows Azure website

New Windows Azure website

New Windows Azure website

This concludes part three of this series. In the next part of this set of tutorials, we would explore connecting to the SignalR hub we just created via a client such as windows phone.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>