Intro to Angular, Web API and Azure

Hello World,

So I thought it would be beneficial to discuss Angular, Web API and Azure in some form of depth as well as provide an entire set of functioning code.  I will start by addressing a few things, What is Angular, What is Web API, and what is Azure?  Followed by the code and explanation of the code.  The code itself provides a simple website, which has restful routing, requests for processing and lists out data from a database acquired from said processing.

What is Angular?

Angular is a client side Model, View, Controller or MVC framework.  A model being the data in which you wish to show, the view being the format in which you wish to show the data, and the controller facilitates the dynamic aspects of the page.  Angular is one of the most popular frameworks out there.  It has a bit of magic to it, but is much better to deal with than raw HTML and JavaScript.  It provides a framework for dependency management, html injection and dynamic pages.  This framework seems to be at the heart of the Single Page App movement.  It also works within the context of Cordova, making it a great client framework to learn and understand.  That said, in my experience it appears to perform very slowly on semi complex renders, but the speed of modern computers appears to more or less keep it within the bounds of an acceptable performance threshold.

What is Web API?

Web API is an ASP.Net (or .net) framework for providing restful services to clients.  These services are easily data mined and therefor very conducive to search engine optimization.  Not only that, but they are easily repackaged and sold.  Beyond THAT they are also cross platform and follow a standard that most client developers understand.  Finally it provides all of the security and goodliness that classic MVC provides.  So in short, Web API is just pure awesomeness for a server side developer who wishes to ship product to the world in a timely fashion.

What is Azure?

Azure is the Microsoft Cloud Platform.  I have tons of slide decks on my site regarding intro to Azure, Azure Architecture, How to – Azure etc.  Go to the Events section and just download nearly any events slide deck and you will find something regarding Azure.  In the instance of what we are discussing today, Azure provides the hosting platform for the website as well as the compute space for our web job which scrapes git hub, synchronizing the scale of both together.  Azure supports a plethora of technologies and languages on its “Web Apps” platform, which is what we primarily intend to take advantage of.  Beyond the Web Apps platform, this solution takes advantage of SQL Azure and Azure Storage.  You will notice that all three technologies are within the PaaS world.  This is purposeful as PaaS enables me as a developer to push out quality product faster.  If there is enough interest, I will post an article about PaaS vs SaaS vs IaaS.

ONTO THE CODE!

The code is located here: https://github.com/drcrook1/Nerds4Hire As of the time of this writing, it is 8:33pm EST on 4/27/2015.  Look through the check-in history for that specifically if you see significant changes, as this is a living demo/project.

You should notice in the Solution, three different projects.

  1. NerdsForHire.Services:  This is the C# Web API, AngularJS, HTML etc.  This comprises the primary components of the Client and Client-Server interaction of the App.  This essentially IS the app from a user’s perspective.
  2. NerdsForHire.SQL:  This is the SQL code that you need to deploy to your SQL Azure database for use in the Services Project.
  3. NerdsForHire-GitHubScraper:  This is the Web Job we deploy along side our app which scrapes GitHub for users data.  It uses one of my favorite languages, F# :).

To Start, We should Deploy this solution to your own Azure Account.

Always deploy your database first.  This is as simple as going to www.azure.com, signing into your account (or creating a new one) and finding the Databases tab on the left and choosing to create a new one.  After which, you can right click the NerdsForHire.SQL project and publish.  There will be a series of boxes that you must fill out for this.  I’m going to assume that you can figure this out.  If you struggle here, you should tweet me @DavidCrook1988 for assistance and I will not only assist you, but also update this blog with more specific steps.

You will also need to create a storage account with a queue.  The name of the queue will need to be all lowercase.  You will need to change the Web API code and the Scraper code to reflect the name change of this queue.

After the Database, let Deploy the App itself.  This is SUPER simple!  Right click the .Services project, click publish, and select “Azure Websites”.  It will prompt for you to login, do so, and then elect to create a new website with whatever name you feel like.  Note, you will need to modify the web.config within the project to point to your database specifically.  Change the connection string to point to YOUR SQL Database (mine might not still be around).

Finally, Deploy the Web Job.  Again, super simple, right click publish, select the previously created web site.  You are golden!  Note, on this, you may need to install several F# extensions or plugins.  Tweet me @DavidCrook1988 if you run into trouble, or see the following article: http://indiedevspot.azurewebsites.net/2015/02/18/deploying-f-web-job-to-azure/

Explaining the Code

We will only focus on NerdsForHire.Services as the other two are pure Web Job and SQL Script, which is not the core focus of this article.

AngularJS

Within the NerdsForHire.Services Project, you will see a folder called “Scripts”.  This is where all of our Angular magic happens.  Vendor contains all of the logic provided by third parties.  These are dependencies that our client takes on to provide the experience that it does.  App.module.js contains all of the core setup and initialization logic, including our routing.  You will notice as you click on links you get mywebsite.com/#/routeOne.  This is set up by the routing.  Controllers contain the logic which is injected into the views and Views contains the actual views for our code.

There is only one view, which is not a .html page, and this is a result of the current ASP.Net templates defaulting to requiring a HomeController and needing an index to route to.  This page is basically an html page, which provides the initial landing of our app and you can begin to experience how databinding occurs in Angular.

@*<!DOCTYPE html>
<html ng-app="app">

<head>
    <title>FSharp Web Kit</title>
</head>
<body>*@
<div ng-app="app">
    <div ng-controller="HomePageController as HomePage">

        <h1>{{HomePage.Title}}</h1>
        <ul>
            <li><a ui-sref="routeOne">Route One</a></li>
            <li><a ui-sref="routeTwo">Route Two</a></li>
            <li><a ui-sref="routeThree">Route Three</a></li>
        </ul>
        @*<ul>
                <li><a href="/#/login">Login</a></li>
                <li><a href="/#/register">Register</a></li>
            </ul>*@

        <!-- ANGULAR CONTENT-->
        <textarea id="btn_GitHubName"></textarea> <!--Create fnction in controller for displaying github user name-->
        <button id="btn_submit" ng-click="scrapeGitHub()">
            {{HomePage.GitHubID}}
        </button>
        <div ui-view>

        </div>
    </div>
</div>
@*</body>
</html>*@

Above follows John Papa’s Angular Style guide.  This particular HTML is considered the View in the MVC model.  To see the C or, controller, take a look at the code below from the controllers folder.

(function () {
    'use strict';

    angular.module('app')
        .controller('HomePageController', ['$scope', '$http', function ($scope, $http) {
            var vm = this;
            vm.Title = "FSharp Web Kit";
            vm.GitHubID = "GitHubID";

            $scope.scrapeGitHub = function () {
                alert("Attempting to Scrape!");
                var gitId = document.getElementById("btn_GitHubName").value;
                var data = {
                    "Id": 0,
                    "FirstName": "David",
                    "LastName": "Crook",
                    "Specialty": 0,
                    "TagList": null,
                    "githubId": gitId,
                    "Jobs": [],
                    "Specialty1": null,
                    "NerdSpecialtyRefs": []
                }
                $http.post("/api/Nerd/Scrape/", data);
            };
        }]);
})(); 

This page shows hooking up a function to a button press.  In this instance, on the push of the button with tag ng-click we fire off the scrapeGitHub function, which posts out this data to our Web API, which then in turn pushes an item on Azure Queue storage, which is picked up by our webjob, processed and pushed into SQL Azure.  Bad Ass!

Lets take a quick look at the code that does this…

        [ResponseType(typeof(bool))]
        [HttpPost]
        public async Task<IHttpActionResult> Scrape(Nerd nerd)
        {
            try
            {
                CloudStorageAccount storageAccount = CloudStorageAccount.Parse(@"DefaultEndpointsProtocol=https;AccountName=nerdsforhirestorage;AccountKey=iqFlEAh3ZkXbU6AMbbtgH11o0PHyNslMFWbNqRQ4jD7OqK7lVClZ7RLJgTaA1TL9v/t/w2W0FoeEIpUBUmHZVw==");
                CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient();
                // Retrieve a reference to a queue
                CloudQueue queue = queueClient.GetQueueReference("githubscrapeinput");
                // Create the queue if it doesn't already exist
                queue.CreateIfNotExists();
                // Create a message and add it to the queue.
                CloudQueueMessage message = new CloudQueueMessage(nerd.githubId);
                await queue.AddMessageAsync(message);
                //new
            }
            catch(Exception e)
            {
                return Ok(false);
            }
            return Ok(true);
        }

Pretty straightforward, we receive a moderate sized packet, and we really only need the githubId portion of that and push it onto the queue.  The web job actually then does something with that.  Lets go ahead and peek at that then.  Note that this code lives in the project: NerdsForHire-GitHubScraper.  I am only pasting the code regarding receiving the message and not the actual HTML parsing.  You can look at the rest of the program.fs file for that information if you wish, which is located here: https://github.com/drcrook1/Nerds4Hire/blob/master/NerdsForHire/NerdsForHire-GitHubScraper/Program.fs

let ScrapeGitHub([<QueueTrigger("githubScrapeInput")>]message : string) =
    let repositories = scrapePage(message)
    let dataContext = sqlContext.GetDataContext()
    repositories |> Seq.iter(fun r ->
                                dataContext.``[dbo].[GitRepository]``.Create(r.Description, r.Link, r.Stars, r.Title) |> ignore
                            )
    dataContext.SubmitUpdates()

[<EntryPoint>]
let main argv = 
    let _dashboardConn = @"DefaultEndpointsProtocol=https;AccountName=nerdsforhirestorage;AccountKey=iqFlEAh3ZkXbU6AMbbtgH11o0PHyNslMFWbNqRQ4jD7OqK7lVClZ7RLJgTaA1TL9v/t/w2W0FoeEIpUBUmHZVw=="
    let _storageConn = @"DefaultEndpointsProtocol=https;AccountName=nerdsforhirestorage;AccountKey=iqFlEAh3ZkXbU6AMbbtgH11o0PHyNslMFWbNqRQ4jD7OqK7lVClZ7RLJgTaA1TL9v/t/w2W0FoeEIpUBUmHZVw=="
    let config = new JobHostConfiguration()
    config.DashboardConnectionString <- _dashboardConn
    config.StorageConnectionString <- _storageConn
    printf "%s" config.DashboardConnectionString
    let host = new JobHost(config) 
    //let host = new JobHost()
    host.RunAndBlock()
    0 // return an integer exit code

So as you can see here, we make a little bit further use of our Azure Storage account for monitoring and storage of queued messages.  This is a requirement of queue storage.  Also notice the function with the annotation: [<QueueTrigger(“githubScrapeInput”)>].  This indicates we are listening to incoming messages on the queue “githubscrapeinput”.  It is camel cased here, but F# takes care of reducing this to lowercase for us.  Typically this should be all lower case.

Wow, we are making some serious progress here.  Lets talk a little further about displaying this data.  routeTwo is where we go to make the call for all github repositories we have stored in our database.  So once the webjob finishes, it puts the data into the SQL Database for us, and routeTwo makes a web api call out to go get the data from the database.  It has two way databinding to display that data on the routeTwo injected HTML.

Lets look at the HTML first.

    <div ng-controller="RouteTwoController as RouteTwo">
        RouteTWO! YAYAYAYAYAY!
        <ul>
            <li ng-repeat="repo in RouteTwo.Repositories">
                <h2>Repository</h2>
                <span>Title: {{repo.Title}}</span>
                <br />
                <span>Stars: {{repo.Stars}}</span>
                <br />
                <span>Location: {{repo.Location}}</span>
                <br />
                <p>Description: {{repo.Description}}</p>
                <h2>-----------------</h2>
            </li>
        </ul>
    </div>

You can see we define our controller as RouteTwoController.  This controller must be defined within the context of our app prior to this html being loaded.  Also we rename the controller to RouteTwo, so we can refer to objects within it.  We then have a “foreach” in which each repository is named repo and we list out the title, how many stars and the description of each repository.

Lets now look at the Controller powering this.

(function () {
    'use strict';

    angular.module('app')
        .controller('RouteTwoController', ['$scope', '$http', function ($scope, $http) {
            var vm = this;
            vm.Repositories = [{}, {}];
            $http.get("api/GitRepositories").success(function (data) {
                vm.Repositories = data;
            });
        }]);
})();

Wow, this is a nice short one.  We have a self executing function (per John Papa Styling), in which we define an empty repositories variable, and make a get call out to get ALL repositories from our API.  We then assign the resulting data from that api call to our repositories.  Due to the Angular two way data binding, we do not have to raise any events.  Its all taken care of for us.  On loading the page, give it about 10 seconds and it will load (due to being on free tier websites and free tier sql).

So what does the Web API for this look like?

    public class GitRepositoriesController : ApiController
    {
        private NForHire db = new NForHire();

        // GET: api/GitRepositories
        public IQueryable<GitRepository> GetGitRepositories()
        {
            return db.GitRepositories;
        }

My goodness do I like Entity Framework right about now.  Because that kicks so much ass!  That’s it folks, that gets all the repositories from our database.  Of course we can use OData options to restrict this back to a page by page result set, but that is for you to look up :).

Summary

We covered AngularJS basics, Web API basics and some Azure.  I know this is a ton of info to take in as we covered the whole stack plus web jobs.  Tweet me: @DavidCrook1988 for any assistance and I will gladly help you get this rolled out.

 

Leave a Reply

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