Windows 8 Metro Applications and the Azure

I wanted to start a short series of posts, describing my experience in building simple Windows 8 Metro application using XAML, C#, and a service in Azure. 

You can find my second post at http://dotnetspeak.com/index.php/2012/05/windows-8-metro-applications-and-the-azure-cont/

The application is very simple, it is a going to be a famous quote app, where the user can get an on demand random famous quote.  I am going to use a web service to generate an application.  On top of that, I am going to add a live tile to my Metro app that will periodically refresh with a new quote.  I will at the end publish all source code as well.

Here is the technology stack I am going to use

  • Window 8 Metro app
  • WCF (REST)
  • Entity Framework Code First
  • SQL Azure
  • Windows Azure

One note is that you can easily substitute Azure for your own hosting provider.  You can check out my previous blogs on that subject.

With the main premise out of the way, let’s get started.

I am going to login to my Azure portal, sign in and create new database.  I would like to support authentication, not wanting to make my service visible to whole internet unprotected, so I am going to add two tables: users and quotes.

I used Azure table designer to create tables, and it is very simple to use:

image

 

image

My data was in a resource (resx) file.  I wrote a quite little utility to pump the data into Azure SQL Server database:

 

using System;
using System.Data;
using System.Data.SqlClient;
using System.Resources;

namespace QuoteParser
{
    class Program
    {
        static void Main(string[] args)
        {

            var connString =
                "Server=tcp:myServer.database.windows.net,1433;Database=Quotes;User ID=myUser;Password=myPasword;Trusted_Connection=False;Encrypt=True;";


            using (var conn = new SqlConnection(connString))
            {
                conn.Open();


                ResourceManager manager = new ResourceManager(typeof(QuoteResource));
                for (int quoteNumber = 1; quoteNumber <= 1142; quoteNumber++)
                {
                    var property = typeof(QuoteResource).GetProperty("Q" + quoteNumber.ToString(),
                        System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);

                    string text = property.GetValue(null, null).ToString();
                    text = text.Replace(Environment.NewLine, "").Replace("'", "''");

                    using (var command = conn.CreateCommand())
                    {
                        command.CommandText = 
                            string.Format("Insert into quotes ([QuoteText], [IsDeleted]) values ('{0}', 0)", text);
                        command.CommandType = CommandType.Text;
                        command.ExecuteNonQuery();
                    }
                }
            }
        }
    }
}

I know this could be cleaned up, but I am not concerned about that right this minute.

Now, the service.  I am going to use VS 2010 for this since I have Azure SDK already installed on my machine.  I create brand new project

image

Then I use QCF service template.

image

Now click OK to create base project along with standard WCF project.  The WCF template is pretty standard.  I am going to clean it up and create two methods I am going to need – one to generate a quote, one to create a tile output.

Now, I am going to create my EF classes.  Since I have local copy of the same database, I am going to use Power Tools to reverse engineer my EF classes.

I am not going to concentrate on that task, it is pretty basic and just reflects table structure you saw above.

Now, the service.  I am going to write two methods – one to get a quote, the other to get a tile:

using System.ServiceModel;
using System.ServiceModel.Web;

namespace QuotesWCFServiceWebRole
{

    [ServiceContract]
    public interface IQuoteService
    {

        [OperationContract]
        [WebGet(UriTemplate = "/GetQuote", 
            ResponseFormat = WebMessageFormat.Json, 
            RequestFormat = WebMessageFormat.Json)]
        string GetQuote();

        [OperationContract]
        [WebGet(UriTemplate = "/GetQuoteTile", 
            ResponseFormat = WebMessageFormat.Json, 
            RequestFormat = WebMessageFormat.Json)]
        string GetQuoteTile();
    }


}

 

Please easy so far.  The implementation is just as trivial.

using System;
using System.IO;
using System.Linq;
using QuotesWCFServiceWebRole.Models;
using System.Xml.Linq;

namespace QuotesWCFServiceWebRole
{

    public class QuoteService : IQuoteService
    {

        public string GetQuote()
        {
            Quote quote = null;
            using (var context = new QuotesContext())
            {
                var max = context.Quotes.Max(one => one.QuoteID);

                while (quote == null)
                {
                    var random = (new Random(DateTime.Now.Millisecond)).Next(1, max);
                    quote = context.Quotes.FirstOrDefault(one => one.QuoteID == random);
                }
            }
            return quote.QuoteText;
        }
        /// <summary>
        /// Sample tile return value        
        /// standard XML header with utf-8 encoding 
        /// <tile>
        ///     <visual lang="en-US">
        ///         <binding template="TileWideText03">
        ///             <text id="1">Text Header Field 1</text>
        ///         </binding>  
        ///     </visual>
        ///</tile>
        /// </summary>
        /// <returns></returns>
        public string GetQuoteTile()
        {
            var quoteText = GetQuote();

            if (quoteText.LastIndexOf("-", System.StringComparison.Ordinal) > 0)
            {
                var start = quoteText.Substring(0, quoteText.LastIndexOf("-", System.StringComparison.Ordinal));
                var end = quoteText.Substring(quoteText.LastIndexOf("-", System.StringComparison.Ordinal));
                quoteText = start + Environment.NewLine + end;
            }
           

            var textElement = new XElement("text", quoteText);
            textElement.SetAttributeValue("id", "1");

            var bindingElement = new XElement("binding", textElement);
            bindingElement.SetAttributeValue("template", "TileWideText03");

            var visualElement = new XElement("visual", bindingElement);
            visualElement.SetAttributeValue("lang", "en-US");

            var tileElement = new XElement("tile", visualElement);

            var doc = new XDocument(new XDeclaration("1.0", "utf-8", "yes"), tileElement);
            var writer = new StringWriter();
            doc.Save(writer); 
            var returnValue =  writer.GetStringBuilder().ToString();
            return returnValue;
        }
    }
}

I decided not to hard code XML, but instead use XDocument class to ensure my XML is properly formatted and is valid.  At this point I can right-click on the WCF project (not Azure), then select Debug->Start  New Instance.  Now in your browser select svc file, then add my method name GetQuote.  Once that is done, I can easily test the service.  Do not worry, I want to test everything and do test deployment before adding authentication.  So, now I verified that my code is correct and I can get a quote or tile that is using property tile format based on specification found here.  Once important this I also want to show is web.config that I have to setup to make sure I expose correct binding – webBinding  Here is serviceModel portion of my web.config file

    <system.serviceModel>
        <protocolMapping>
            <add scheme="http" binding="webHttpBinding" />
        </protocolMapping>
        <bindings>
            <webHttpBinding>
                <binding name="webBinding">
                    <security mode="None" />
                </binding>
            </webHttpBinding>
        </bindings>
        <behaviors>
            <endpointBehaviors>
                <behavior name="webGetbehavior">
                    <webHttp helpEnabled="true" />
                </behavior>
                <behavior name="loginBehavior" />
            </endpointBehaviors>
            <serviceBehaviors>
                <behavior name="errorsInlcuded">
                    <serviceDebug includeExceptionDetailInFaults="true" />
                    <serviceMetadata httpGetEnabled="true" />
                    <serviceAuthorization principalPermissionMode="None" />
                </behavior>
                <behavior name="">
                    <serviceMetadata httpGetEnabled="true" />
                    <serviceDebug includeExceptionDetailInFaults="false" />
                </behavior>
            </serviceBehaviors>
        </behaviors>
        <services>
            <service name="QuotesWCFServiceWebRole.QuoteService" behaviorConfiguration="errorsInlcuded">
                <endpoint address="" contract="QuotesWCFServiceWebRole.IQuoteService" binding="webHttpBinding" bindingConfiguration="webBinding" behaviorConfiguration="webGetbehavior" />
            </service>
        </services>
        <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
    </system.serviceModel>

Now I need to publish to Azure.  I found a long time ago that the easiest way is to do that through Visual Studio Publish wizard instead of manually uploading package.  Just right click on Azure project, select publish and follow instructions.  You will have to sign in to your Azure account and download publish profile in the process, then import that profile in the wizard.  You may have to repeat the process if you get certificate error as initial run has to setup the certificate and storage account used for deployments.

Once that completes, use browser again, but use your Azure service address (URL).  Should be something like

http://mySpecialHostedServiceName.cloudapp.net/QuoteService.svc/GetQuoteTile

Everything worked great.  In the next post I will demonstrate how to secure the service and test that part through a small test hardness.

Enjoy.

Leave a Reply

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