Category: .NET

  • Join Me at Microsoft TechEd to Talk DevOps, Cloud Application Architecture

    In a couple weeks, I’ll be invading Houston, TX to deliver a pair of sessions at Microsoft TechEd. This conference – one of the largest annual Microsoft events – focuses on technology available today for developers and IT professionals. I made a pair of proposals to this conference back in January (hoping to increase my odds), and inexplicably, they chose both. So, I accidentally doubled my work.

    The first session, titled Architecting Resilient (Cloud) Applications looks at the principles, patterns, and technology you can use to build highly available cloud applications. For fun, I retooled the highly available web application that I built for my pair of Pluralsight courses, Architecting Highly Available Systems on AWS and Optimizing and Managing Distributed Systems on AWS. This application now takes advantage of Azure Web Sites, Virtual Machines, Traffic Manager, Cache, Service Bus, SQL Database, Storage, and CDN. While I’ll be demonstrating a variety of Microsoft Azure services (because it’s a Microsoft conference), all of the principles/patterns apply to virtually any quality cloud platform.

    My second session is called Practical DevOps for Data Center Efficiency. In reality, this is a talk about “DevOps for Windows people.” I’ll cover what DevOps is, what the full set of technologies are that support a DevOps culture, and then show off a set of Windows-friendly demos of Vagrant, Puppet, and Visual Studio Online. The best DevOps tools have been late-arriving to Windows, but now some of the best capabilities are available across OS platforms and I’m excited to share this with the TechEd crowd.

    If you’re attending TechEd, don’t hesitate to stop by and say hi. If you think either of these talks are interesting for other conferences, let me know that too!

  • Call your CRM Platform! Using an ASP.NET Web API to Link Twilio and Salesforce.com

    I love mashups. It’s fun to combine technologies in unexpected ways. So when Wade Wegner of Salesforce asked me to participate in a webinar about the new Salesforce Toolkit for .NET, I decided to think of something unique to demonstrate. So, I showed off how to link Twilio – which in an API-driven service for telephony and SMS – with Salesforce.com data. In this scenario, job applicants can call a phone number, enter their tracking ID and hear the current status of their application. The rest of this blog post walks through what I built.

    The Salesforce.com application

    In my developer sandbox, I added a new custom object called Job Application that holds data about applicants, which job they applied to, and the status of the application (e.g. Submitted, In Review, Rejected).

    2014.04.17forcetwilio01

    I then created a bunch of records for job applicants. Here’s an example of one applicant in my system.

    2014.04.17forcetwilio02

    I want to expose a programmatic interface to retrieve “Application Status” that’s an aggregation of multiple objects. To make that happen, I created a custom Apex controller that exposes a REST endpoint. You can see below that I defined a custom class called ApplicationStatus and then a GetStatus operation that inflates and returns that custom object. The RESTful attributes (@RestResource, @HttpGet) make this a service accessible via REST query.

    @RestResource(urlMapping='/ApplicationStatus/*')
    global class CandidateRestService {
    
        global class ApplicationStatus {
    
            String ApplicationId {get; set; }
            String JobName {get; set; }
            String ApplicantName {get; set; }
            String Status {get; set; }
        }
    
        @HttpGet
        global static ApplicationStatus GetStatus(){
    
            //get the context of the request
            RestRequest req = RestContext.request;
            //extract the job application value from the URL
            String appId = req.requestURI.substring(req.requestURI.lastIndexOf('/')+1);
    
            //retrieve the job application
            seroter__Job_Application__c application = [SELECT Id, seroter__Application_Status__c, seroter__Applicant__r.Name, seroter__Job_Opening__r.seroter__Job_Title__c FROM seroter__Job_Application__c WHERE seroter__Application_ID__c = :appId];
    
            //create the application status object using relationship (__r) values
            ApplicationStatus status = new ApplicationStatus();
            status.ApplicationId = appId;
            status.Status = application.seroter__Application_Status__c;
            status.ApplicantName = application.seroter__Applicant__r.Name;
            status.JobName = application.seroter__Job_Opening__r.seroter__Job_Title__c;
    
            return status;
        }
    }
    

    With this in place – and creating an “application” that gave me a consumer key and secret for remote access – I had everything I needed to consume Salesforce.com data.

    The ASP.NET Web API project

    How does Twilio know what to say when you call one of their phone numbers? They have a markup language called TwiML that includes the constructs for handling incoming calls. What I needed was a web service that Twilio could reach and return instructions for what to say to the caller.

    I created an ASP.NET Web API project for this service. I added NuGet packages for DeveloperForce.Force (to get the Force.com Toolkit for .NET) and Twilio.Mvc, Twilio.TwiML, and Twilio. Before slinging the Web API Controller, I added a custom class that helps the Force Toolkit talk to custom REST APIs. This class, CustomServiceHttpClient, copies the base ServiceHttpClient class and changes a single line.

    public async Task<T> HttpGetAsync<T>(string urlSuffix)
            {
                var url = string.Format("{0}/{1}", _instanceUrl, urlSuffix);
    
                var request = new HttpRequestMessage()
                {
                    RequestUri = new Uri(url),
                    Method = HttpMethod.Get
                };
    

    Why did I do this? The class that comes with the Toolkit builds up a particular URL that maps to the standard Salesforce.com REST API. However, custom REST services use a different URL pattern. This custom class just takes in the base URL (returned by the authentication query) and appends a suffix that includes the path to my Apex controller operation.

    I slightly changed the WebApiConfig.cs to add a “type” to the route template. I’ll use this to create a pair of different URIs for Twilio to use. I want one operation that it calls to get initial instructions (/api/status/init) and another to get the actual status resource (/api/status).

    public static class WebApiConfig
        {
            public static void Register(HttpConfiguration config)
            {
                // Web API configuration and services
    
                // Web API routes
                config.MapHttpAttributeRoutes();
    
                config.Routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "api/{controller}/{type}",
                    defaults: new { type = RouteParameter.Optional }
                );
            }
        }
    

    Now comes the new StatusController.cs that handles the REST input. The first operation takes in VoiceRequest object that comes from Twilio and I build up a TwiML response. What’s cool is that Twilio can collect data from the caller. See the “Gather” operation where I instruct Twilio to get 6 digits from the caller, and post to another URI. In this case, it’s a version of this endpoint hosted in Windows Azure. Finally, I forced the Web API to return an XML document instead of sending back JSON (regardless of what comes in the inbound Accept header).

    The second operation retrieves the Salesforce credentials from my configuration file, gets a token from Salesforce (via the Toolkit), issues the query to the custom REST endpoint, and takes the resulting job application detail and injects it into the TwiML response.

    public class StatusController : ApiController
        {
            // GET api/<controller>/init
            public HttpResponseMessage Get(string type, [FromUri]VoiceRequest req)
            {
                //build Twilio response using TwiML generator
                TwilioResponse resp = new TwilioResponse();
                resp.Say("Thanks for calling the status hotline.", new { voice = "woman" });
                //Gather 6 digits and send GET request to endpoint specified in the action
                resp.BeginGather(new { action = "http://twilioforcetoolkit.azurewebsites.net/api/status", method = "GET", numDigits = "6" })
                    .Say("Please enter the job application ID", new { voice = "woman" });
                resp.EndGather();
    
                //be sure to force XML in the response
                return Request.CreateResponse(HttpStatusCode.OK, resp.Element, "text/xml");
    
            }
    
            // GET api/<controller>
            public async Task<HttpResponseMessage> Get([FromUri]VoiceRequest req)
            {
                var from = req.From;
                //get the digits the user typed in
                var nums = req.Digits;
    
                //SFDC lookup
                //grab credentials from configuration file
                string consumerkey = ConfigurationManager.AppSettings["consumerkey"];
                string consumersecret = ConfigurationManager.AppSettings["consumersecret"];
                string username = ConfigurationManager.AppSettings["username"];
                string password = ConfigurationManager.AppSettings["password"];
    
                //create variables for our auth-returned values
                string url, token, version;
                //authenticate the user using Toolkit operations
                var auth = new AuthenticationClient();
    
                //authenticate
                await auth.UsernamePasswordAsync(consumerkey, consumersecret, username, password);
                url = auth.InstanceUrl;
                token = auth.AccessToken;
                version = auth.ApiVersion;
    
                //create custom client that takes custom REST path
                var client = new CustomServiceHttpClient(url, token, new HttpClient());
    
                //reference the numbers provided by the caller
                string jobId = nums;
    
                //send GET request to endpoint
                var status = await client.HttpGetAsync<dynamic>("services/apexrest/seroter/ApplicationStatus/" + jobId);
                //get status result
                JObject statusResult = JObject.Parse(System.Convert.ToString(status));
    
                //create Twilio response
                TwilioResponse resp = new TwilioResponse();
                //tell Twilio what to say to the caller
                resp.Say(string.Format("For job {0}, job status is {1}", statusResult["JobName"], statusResult["Status"]), new { voice = "woman" });
    
                //be sure to force XML in the response
                return Request.CreateResponse(HttpStatusCode.OK, resp.Element, "text/xml");
            }
         }
    

    My Web API service was now ready to go.

    Running the ASP.NET Web API in Windows Azure

    As you can imagine, Twilio can only talk to services exposed to the public internet. For simplicity sake, I jammed this into Windows Azure Web Sites from Visual Studio.

    2014.04.17forcetwilio04

    Once this service was deployed, I hit the two URLs to make sure that it was returning TwiML that Twilio could use. The first request to /api/status/init returned:

    2014.04.17forcetwilio05

    Cool! Let’s see what happens when I call the subsequent service endpoint and provide the application ID in the URL. Notice that the application ID provided returns the corresponding job status.

    2014.04.17forcetwilio06

    So far so good. Last step? Add Twilio to the mix.

    Setup Twilio Phone Number

    First off, I bought a new Twilio number. They make it so damn easy to do!

    2014.04.17forcetwilio07

     

    With the number in place, I just had to tell Twilio what to do when the phone number is called. On the phone number’s settings page, I can set how Twilio should respond to Voice or Messaging input. In both cases, I point to a location that returns a static or dynamic TwiML doc. For this scenario, I pointed to the ASP.NET Web API service and chose the “GET” operation.

    2014.04.17forcetwilio08

    So what happens when I call? Hear the audio below:

    [audio https://seroter.com/wp-content/uploads/2014/07/twiliosalesforce.mp3 |titles=Calling Twilio| initialvolume=30|animation=no]

    One of the other great Twilio features is the analytics. After calling the number, I can instantly see usage trends …

    2014.04.17forcetwilio09

    … and a log of the call itself. Notice that I see the actual TwiML payload processed for the request. That’s pretty awesome for troubleshooting and auditing.

    2014.04.17forcetwilio10

     

    Summary

    In the cloud, it’s often about combining best-of-breed capabilities to deliver innovative solutions that no one technology has. It’s a lot easier to do this when working with such API-friendly systems as Salesforce and Twilio. I’m sure you can imagine all sorts of valuable cases where an SMS or voice call could retrieve (or create) data in a system. Imagine walking a sales rep through a call and collecting all the data from the customer visit and creating an Opportunity record! In this scenario, we saw how to query Salesforce.com (using the Force Toolkit for .NET) from a phone call and return a small bit of data. I hope you enjoyed the walkthrough, and keep an eye out for the recorded webcast where Wade and I explain a host of different scenarios for this Force Toolkit.

  • Co-Presenting a Webinar Next Week on Force.com and .NET

    Salesforce.com is a juggernaut in the software-as-a-service space and continues to sign up a diverse pool of global customers. While Salesforce relies on its own language (Apex) for coding extensions that run within the platform, developers can use any programming framework to integrate with Salesforce.com from external apps. That said, .NET is one of the largest communities in the Salesforce developer ecosystem and they have content specifically targeted at .NET devs.

    A few months back, a Toolkit for .NET was released and I’m participating in a fun webinar next week where we show off a wide range of use cases for it. The Toolkit makes it super easy to interact with the full Force.com platform without having to directly consume the RESTful interface. Wade Wegner – the creator of the Toolkit – will lead the session as we look at why this Toolkit was built, the delivery pipeline for the NuGet package, and a set of examples that show off how to use this in web apps, Windows Store apps, and Windows Phone apps.

    Sign up and see how to take full advantage of this Toolkit when building Salesforce.com integrations!

  • Using the New Salesforce Toolkit for .NET

    Wade Wegner, a friend of the blog and an evangelist for Salesforce.com, just built a new .NET Toolkit for Salesforce developers. This Toolkit is open source and available on GitHub. Basically, it makes it much simpler to securely interact with the Salesforce.com REST API from .NET code. It takes care of “just working” on multiple Windows platforms (Win 7/8, WinPhone), async processing, and wrapping up all the authentication and HTTP stuff needed to call Salesforce.com endpoints. In this post, I’ll do a basic walkthrough of adding the Toolkit to a project and working with a Salesforce.com resource.

    After creating a new .NET project (Console project, in my case) in Visual Studio, all you need to do is reference the NuGet packages that Wade created. Specifically, look for the DeveloperForce.Force package which pulls in the “common” package (that has baseline stuff) as well as the JSON.NET package.

    2014.01.16force01

    First up, add a handful of using statements to reference the libraries we need to use the Toolkit, grab configuration values, and work with dynamic objects.

    using System.Configuration;
    using Salesforce.Common;
    using Salesforce.Force;
    using System.Dynamic;
    

    The Toolkit is written using the async and await model for .NET, so calling this library requires some knowledge of this. To make life simple for this demo, define an operation like this that can be called from the Main entry point.

    static void Main(string[] args)
    {
            Do().Wait();
    }
    
    static async Task Do()
    {
         ...
    }
    

    Let’s fill out the “Do” operation that uses the Toolkit. First, we need to capture our Force.com credentials. The Toolkit supports a handful of viable authentication flows. Let’s use the “username-password” flow. This means we need OAuth/API credentials from Salesforce.com. In the Salesforce.com Setup screens, go to Create, then Apps and create a new application. For a full walkthrough of getting credentials for REST calls, see my article on the DeveloperForce site.

    2014.01.16force02

    With the consumer key and consumer secret in hand, we can now authenticate using the Toolkit. In the code below, I yanked the credentials from the app.config accompanying the application.

    //get credential values
    string consumerkey = ConfigurationManager.AppSettings["consumerkey"];
    string consumersecret = ConfigurationManager.AppSettings["consumersecret"];
    string username = ConfigurationManager.AppSettings["username"];
    string password = ConfigurationManager.AppSettings["password"];
    
    //create auth client to retrieve token
    var auth = new AuthenticationClient();
    
    //get back URL and token
    await auth.UsernamePassword(consumerkey, consumersecret, username, password);
    

    When you call this, you’ll see that the AuthenticationClient now has populated properties for the instance URL and access token. Pull those values out, as we’re going to use them when interacting the the REST API.

    var instanceUrl = auth.InstanceUrl;
    var accessToken = auth.AccessToken;
    var apiVersion = auth.ApiVersion;
    

    Now we’re ready to query Salesforce.com with the Toolkit. In this first instance, create a class that represents the object we’re querying.

    public class Contact
        {
            public string Id { get; set; }
            public string FirstName { get; set; }
            public string LastName { get; set; }
        }
    

    Let’s instantiate the ForceClient object and issue a query. Notice that we pass in a SQL-like syntax when querying the Salesforce.com system. Also, see that the Toolkit handles all the serialization for us!

    var client = new ForceClient(instanceUrl, accessToken, apiVersion);
    
    //Toolkit handles all serialization
    var contacts = await client.Query<Contact>("SELECT Id, LastName From Contact");
    
    //loop through returned contacts
    foreach (Contact c in contacts)
    {
          Console.WriteLine("Contact - " + c.LastName);
    }
    

    My Salesforce.com app has the following three contacts in the system …

    2014.01.16force03

    Calling the Toolkit using the code above results in this …

    2014.01.16force04

    Easy! But does the Toolkit support dynamic objects too? Let’s assume you’re super lazy and don’t want to create classes that represent the Salesforce.com objects. No problem! I can use late binding through the dynamics keyword and get back an object that has whatever fields I requested. See here that I added the “FirstName” to the query and am not passing in a known class type.

    var client = new ForceClient(instanceUrl, accessToken, apiVersion);
    
    var contacts = await client.Query<dynamic>("SELECT Id, FirstName, LastName FROM Contact");
    
    foreach (dynamic c in contacts)
    {
          Console.WriteLine("Contact - " + c.FirstName + " " + c.LastName);
    }
    

    What happens when you run this? You should have all the queried values available as properties.

    2014.01.16force05

    The Toolkit supports more than just “query” scenarios. It also works great for create/update/delete as well. Like before, these operations worked with strongly typed objects or dynamic ones. First, add the code below to create a contact using our known “contact” type.

    Contact c = new Contact() { FirstName = "Golden", LastName = "Tate" };
    
    string recordId = await client.Create("Contact", c);
    
    Console.WriteLine(recordId);
    

    That’s a really simple way to create Salesforce.com records. Want to see another way? You can use the dynamic ExpandoObject to build up an object on the fly and send it in here.

    dynamic c = new ExpandoObject();//
    c.FirstName = "Marshawn";
    c.LastName = "Lynch";
    c.Title = "Chief Beast Mode";
    
    string recordId = await client.Create("Contact", c);
    
    Console.WriteLine(recordId);
    

    After running this, we can see this record in our Salesforce.com database.

    2014.01.16force06

    Summary

    This is super useful and a fantastic way to easily interact with Salesforce.com from .NET code. Wade’s looking for feedback and contributions as he builds this out further. Add issues if you encounter bugs, and issue a pull request if you want to add features like error handling or support for other operations.

  • Data Stream Processing with Amazon Kinesis and .NET Applications

    Amazon Kinesis is a new data stream processing service from AWS that makes it possible to ingest and read high volumes of data in real-time. That description may sound vaguely familiar to those who followed Microsoft’s attempts to put their CEP engine StreamInsight into the Windows Azure cloud as part of “Project Austin.” Two major differences between the two: Kinesis doesn’t have the stream query aspects of StreamInsight, and Amazon actually SHIPPED their product.

    Kinesis looks pretty cool, and I wanted to try out a scenario where I have (1) a Windows Azure Web Site that generates data, (2) Amazon Kinesis processing data, and (3) an application in the CenturyLink Cloud which is reading the data stream.

    2014.01.08kinesis05

    What is Amazon Kinesis?

    Kinesis provides a managed service that handles the intake, storage, and transportation of real-time streams of data. Each stream can handle nearly unlimited data volumes. Users set up shards which are the means for scaling up (and down) the capacity of the stream. All the data that comes into the a Kinesis stream is replicated across AWS availability zones within a region. This provides a great high availability story. Additionally, multiple sources can write to a stream, and a stream can be read by multiple applications.

    Data is available in the stream for up to 24 hours, meaning that applications (readers) can pull shard records based on multiple schemes: given sequence number, oldest record, latest record. Kinesis uses DynamoDB to store application state (like checkpoints). You can interact with Kinesis via the provided REST API or via platform SDKs.

    What DOESN’T Kinesis do? It doesn’t have any sort of adapter model, so it’s up to the developer to build producers (writers) and applications (readers). There is a nice client library for Java that has a lot of built in logic for application load balancing and such. But for the most part, this is still a developer-oriented solution for building big data processing solutions.

    Setting up Amazon Kinesis

    First off, I logged into the AWS console and located Kinesis in the navigation menu.

    2014.01.08kinesis01

    I’m then given the choice to create a new stream.

    2014.01.08kinesis02

    Next, I need to choose the initial number of shards for the stream. I can either put in the number myself, or use a calculator that helps me estimate how many shards I’ll need based on my data volume.

    2014.01.08kinesis03

    After a few seconds, my managed Kinesis stream is ready to use. For a given stream, I can see available shards, and some CloudWatch metrics related to capacity, latency, and requests.

    2014.01.08kinesis04

    I now have an environment for use!

    Creating a data producer

    Now I was ready to build an ASP.NET web site that publishes data to the Kinesis endpoint. The AWS SDK for .NET already Kinesis objects, so no reason to make this more complicated than it has to be. My ASP.NET site has NuGet packages that reference JSON.NET (for JSON serialization), AWS SDK, jQuery, and Bootstrap.

    2014.01.08kinesis06

    The web application is fairly basic. It’s for ordering pizza from a global chain. Imagine sending order info to Kinesis and seeing real-time reactions to marketing campaigns, weather trends, and more. Kinesis isn’t a messaging engine per se, but it’s for collecting and analyzing data. Here, I’m collecting some simplistic data in a form.

    2014.01.08kinesis07

    When clicking the “order” button, I build up the request and send it to a particular Kinesis stream. First, I added the following “using” statements:

    using Newtonsoft.Json;
    using Amazon.Kinesis;
    using Amazon.Kinesis.Model;
    using System.IO;
    using System.Text;
    

    The button click event has the following (documented) code.  Notice a few things. My AWS credentials are stored in the web.config file, and I pass in an AmazonKinesisConfig to the client constructor. Why? I need to tell the client library which AWS region my Kinesis stream is in so that it can build the proper request URL. See that I added a few properties to the actual put request object. First, I set the stream name. Second, I added a partition key which is used to place the record in a given shard. It’s a way of putting “like” records in a particular shard.

    protected void btnOrder_Click(object sender, EventArgs e)
        {
            //generate unique order id
            string orderId = System.Guid.NewGuid().ToString();
    
            //build up the CLR order object
            Order o = new Order() { Id = orderId, Source = "web", StoreId = storeid.Text, PizzaId = pizzaid.Text, Timestamp = DateTime.Now.ToString() };
    
            //convert to byte array in prep for adding to stream
            byte[] oByte = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(o));
    
            //create stream object to add to Kinesis request
            using (MemoryStream ms = new MemoryStream(oByte))
            {
                //create config that points to AWS region
                AmazonKinesisConfig config = new AmazonKinesisConfig();
                config.RegionEndpoint = Amazon.RegionEndpoint.USEast1;
    
                //create client that pulls creds from web.config and takes in Kinesis config
                AmazonKinesisClient client = new AmazonKinesisClient(config);
    
                //create put request
                PutRecordRequest requestRecord = new PutRecordRequest();
                //list name of Kinesis stream
                requestRecord.StreamName = "OrderStream";
                //give partition key that is used to place record in particular shard
                requestRecord.PartitionKey = "weborder";
                //add record as memorystream
                requestRecord.Data = ms;
    
                //PUT the record to Kinesis
                PutRecordResponse responseRecord = client.PutRecord(requestRecord);
    
                //show shard ID and sequence number to user
                lblShardId.Text = "Shard ID: " + responseRecord.ShardId;
                lblSequence.Text = "Sequence #:" + responseRecord.SequenceNumber;
            }
        }
    

    With the web application done, I published it to a Windows Azure Web Site. This is super easy to do with Visual Studio 2013, and within a few seconds my application was there.

    2014.01.08kinesis08

    Finally, I submitted a bunch of records to Kinesis by adding pizza orders. Notice the shard ID and sequence number that Kinesis returns from each PUT request.

    2014.01.08kinesis09

    Creating a Kinesis application (record consumer)

    To realistically read data from a Kinesis stream, there are three steps. First, you need to describe the stream in order to find out the shards. If I want a fleet of servers to run this application and read the stream, I’d need a way for each application to claim a shard to work on. The second step is to retrieve a “shard iterator” for a given shard. The iterator points to a place in the shard where I want to start reading data. Recall from above that I can start with the latest unread records, oldest records, or at a specific point in the shard. The third and final step is to get the records from a particular iterator. Part of the result set of this operation is a “next iterator” value. In my code, if I find another iterator value, I once again call the “get records” operation to pull any records from that iterator position.

    Here’s the total code block, documented for your benefit.

    private static void ReadFromKinesis()
    {
        //create config that points to Kinesis region
        AmazonKinesisConfig config = new AmazonKinesisConfig();
        config.RegionEndpoint = Amazon.RegionEndpoint.USEast1;
    
       //create new client object
       AmazonKinesisClient client = new AmazonKinesisClient(config);
    
       //Step #1 - describe stream to find out the shards it contains
       DescribeStreamRequest describeRequest = new DescribeStreamRequest();
       describeRequest.StreamName = "OrderStream";
    
       DescribeStreamResponse describeResponse = client.DescribeStream(describeRequest);
       List<Shard> shards = describeResponse.StreamDescription.Shards;
       foreach(Shard s in shards)
       {
           Console.WriteLine("shard: " + s.ShardId);
       }
    
       //grab the only shard ID in this stream
       string primaryShardId = shards[0].ShardId;
    
       //Step #2 - get iterator for this shard
       GetShardIteratorRequest iteratorRequest = new GetShardIteratorRequest();
       iteratorRequest.StreamName = "OrderStream";
       iteratorRequest.ShardId = primaryShardId;
       iteratorRequest.ShardIteratorType = ShardIteratorType.TRIM_HORIZON;
    
       GetShardIteratorResponse iteratorResponse = client.GetShardIterator(iteratorRequest);
       string iterator = iteratorResponse.ShardIterator;
    
       Console.WriteLine("Iterator: " + iterator);
    
       //Step #3 - get records in this iterator
       GetShardRecords(client, iterator);
    
       Console.WriteLine("All records read.");
       Console.ReadLine();
    }
    
    private static void GetShardRecords(AmazonKinesisClient client, string iteratorId)
    {
       //create reqest
       GetRecordsRequest getRequest = new GetRecordsRequest();
       getRequest.Limit = 100;
       getRequest.ShardIterator = iteratorId;
    
       //call "get" operation and get everything in this shard range
       GetRecordsResponse getResponse = client.GetRecords(getRequest);
       //get reference to next iterator for this shard
       string nextIterator = getResponse.NextShardIterator;
       //retrieve records
       List<Record> records = getResponse.Records;
    
       //print out each record's data value
       foreach (Record r in records)
       {
           //pull out (JSON) data in this record
           string s = Encoding.UTF8.GetString(r.Data.ToArray());
           Console.WriteLine("Record: " + s);
           Console.WriteLine("Partition Key: " + r.PartitionKey);
       }
    
       if(null != nextIterator)
       {
           //if there's another iterator, call operation again
           GetShardRecords(client, nextIterator);
       }
    }
    

    Now I had a working Kinesis application that can run anywhere. Clearly it’s easy to run this on AWS EC2 servers (and the SDK does a nice job with retrieving temporary credentials for apps running within EC2), but there’s a good chance that cloud users have a diverse portfolio of providers. Let’s say I love the application services from AWS, but like the server performance and management capabilities from CenturyLink. In this case, I built a Windows Server to run my Kinesis application.

    2014.01.08kinesis10

    With my server ready, I ran the application and saw my shards, my iterators, and my data records.

    2014.01.08kinesis11

    Very cool and pretty simple. Don’t forget that each data consumer has some work to do to parse the stream, find the (partition) data they want, and perform queries on it. You can imagine loading this into an Observable and using LINQ queries on it to aggregate data. Regardless, it’s very nice to have a durable stream processing service that supports replays and multiple readers.

    Summary

    The “internet of things” is here, and companies that can quickly gather and analyze data will have a major advantage. Amazon Kinesis is an important service to that end, but don’t think of it as something that ONLY works with other applications in the AWS cloud. We saw here that you could have all sorts of data producers running on devices, on-premises, or in other clouds. The Kinesis applications that consume data can also run virtually anywhere. The modern architect recognizes that composite applications are the way to go, and hopefully this helped you understand another services that’s available to you!

  • How Do BizTalk Services Work? I Asked the Product Team to Find Out

    Windows Azure BizTalk Services was recently released by Microsoft, and you can find a fair bit about this cloud service online. I wrote up a simple walkthrough, Sam Vanhoutte did a nice comparison of features between BizTalk Server and BizTalk Services,  the Neudesic folks have an extensive series of blog posts about it, and the product documentation isn’t half bad.

    However, I wanted to learn more about how the service itself works, so I reached out to Karthik Bharathy who is a senior PM on the BizTalk team and part of the team that shipped BizTalk Services. I threw a handful of technical questions at him, and I got back some fantastic answers. Hopefully you learn something new;  I sure did!

    Richard: Explain what happens after I deploy an app. Do you store the package in my storage account and add it to a new VM that’s in a BizTalk Unit?

    Karthik: Let’s start with some background information – the app that you are referring today is the VS project with a combination of the bridge configuration and artifacts like maps, schemas and DLLs. When you deploy the project, each of the artifacts and the bridge configuration are uploaded into one by one. The same notion also applies through the BizTalk Portal when you are deploying an agreement and uploading artifacts to the resources.

    The bridge configuration represents the flow of the message in the pipeline in XML format. Every time you build BizTalk Services project in Visual Studio, an <entityName>.Pipeline.atom is generated in the project bins folder. This atom file is the XML representation of the pipeline configuration. For example, under the <pipelines> section you can see the bridges configured along with the route information. You can also get a similar listing by issuing a GET operation on the bridge endpoint with the right ACS credentials.

    Now let’s say the bridge is configured with Runtime URL <deploymentURL>/myBridge1. After you click deploy, the pipeline configuration gets published in the repository of the <deploymentURL> for handling /myBridge1. For every message sent to the <deploymentURL>, the role looks at the complete path including /myBridge1 and load the pipeline configuration from the repository. Once the pipeline configuration is loaded, the message is processed per the configuration. If the configuration does not exist, then an error is returned to the caller.

    Richard: What about scaling an integration application? How does that work?

    Karthik: Messages are processed by integration roles in the deployment. When the customer initiates a scale operation, we update the service configuration to add/remove instances based on the ask. The BizTalk Services deployment updates its state during scaling operation and new messages to the deployment is handled by one of the instances of the role. This is similar to how Web or Worker roles are scaled up/down in Azure today.

    Richard: Is there any durability in the bridge? What if a downstream endpoint is offline?

    Karthik: The concept of a bridge is close to a messaging channel if we may borrow the phrase from Enterprise Integration Patterns. It helps in bridging the impedance between two messaging systems. As such the bridge is a stateless system and does not have persistence built into it. Therefore bridges need to report any processing errors back to the sender. In the case where the downstream endpoint is offline, the bridge propagates the error back to the sender – the semantics are slightly different a) based on the bridge and b) based on the source from where the message has been picked up.

    For EAI, bridges with HTTP the error code is sent back to the sender while with the same bridge using an FTP head, the system tries to pickup and process the message again from the source at regular intervals (and errors out eventually). In both cases you can see relevant track records in the portal.

    For B2B, our customers rarely intend to send an HTTP error back to their partners. When the message cannot be sent to a downstream (success) endpoint, the message is routed to the suspend endpoint. You might argue that the suspend endpoint could be down as well – while this is generally a bad idea to put in a flaky target in success or suspend endpoints, we don’t rule out this possibility. In the worst case we deliver the error code back to the sender.

    Richard: Bridges resemble BizTalk Server ESB Toolkit itineraries. Did you ever consider re-using that model?

    Karthik: ESB is an architectural pattern and you should look at the concept of bridge as being part of the ESB model for BizTalk Services on Azure. The sources and destinations are similar to the on-ramp, off-ramp model and the core processing is part of the bridge. Of course, additional capabilities like exception management, governance, alerts will need to added to bring it closer to the ESB Toolkit.

    Richard: How exactly does the high availability option work?

    Karthik: Let’s revisit the scaling flow we talked about earlier. If we had a scale >=2, you essentially have a system that can process messages even when one of the machines can down in your configuration. If one of the machines are down, the load balancer in our system routes the message to the running instances. For example, this is taken care of during “refresh” when customers can restart their deployment after updating a user DLL. This ensures message processing is not impacted.

    Richard: It looks like backup and restore is for the BizTalk Services configuration, not tracking data. What’s the recommended way to save/store an audit trail for messages?

    Karthik: The purpose of backup and restore is for the deployment configuration including schemas, maps, bridges, agreements. The tracking data comes from the Azure SQL database provided by the customer. The customer can add the standard backup/restore tools directly on that storage. To save/store an audit of messages, you have couple of options at the moment – with B2B you can turn archiving on either AS2 or X12 processing and with EAI you can plug-in an IMessageInspector extension that can read the IMessage data and save it to an external store.

    Richard: What part of the platform are you most excited about?

    Karthik: Various aspects of the platform are exciting – we started off building capabilities with ‘AppFabric Connect’ to enable server customers leverage existing investments with the cloud. Today, we have built a richer set of functionality with BizTalk Adapter services to connect popular LOBs with Bridges. In the case of B2B, BizTalk Server traditionally exposed functionality for IT Operators to manage trading partner relationships using the Admin Console. Today, we have a rich TPM functionality in the BizTalk Portal and also have the OM API public for the developer community. In EAI we allow extending message processing using custom code  If I should call out one I like, it has to be custom code enablement. The dedicated deployment model managed by Microsoft makes this possible. It is always a challenge to enable user DLL to execute without providing some sort of sandboxing. Then there are also requirements around performance guarantees. BizTalk Services dedicated deployment takes care of all these – if the code behaves in an unexpected way, only that deployment is affected. As the resources are isolated, there are also better guarantees about the performance. In a configuration driven experience this makes integration a whole lot simpler.

    Thanks Karthik for an informative chat!

  • Window Azure BizTalk Services: How to Get Started and When to Use It

    The “integration as a service” space continues to heat up, and Microsoft officially entered the market with the General Availability of Windows Azure BizTalk Services (WABS) a few weeks ago.  I recently wrote up an InfoQ article that summarized the product and what it offered. I also figured that I should actually walk through the new installation and deployment process to see what’s changed. Finally, I’ll do a brief assessment of where I’d consider using this vs. the other cloud-based integration tools.

    Installation

    Why am I installing something if this is a cloud service? Well, the development of integration apps still occurs on premises, so I need an SDK for the necessary bits. Grab the Windows Azure BizTalk Services SDK Setup and kick off the process. I noticed what seems to be a much cleaner installation wizard.

    2013.12.10biztalkservices01

    After choosing the components that I wanted to install (including the runtime, developer tools, and developer SDK) …

    2013.12.10biztalkservices02

    … you are presented with a very nice view of the components that are needed, and which versions are already installed.

    2013.12.10biztalkservices03

    At this point, I have just about everything on my local developer machine that’s needed to deploy an integration application.

    Provisioning

    WABS applications run in the Windows Azure cloud. Developers provision and manage their WABS instances in the Windows Azure portal. To start with, choose App Services and then BizTalk Services before selecting Custom Create.

    2013.12.10biztalkservices04

    Next, I’m asked to pick an instance name, edition, geography, tracking database, and Windows Azure subscription. There are four editions: basic, developer, standard, and premium. As you move between editions (and pay more money), you have access to greater scalability, more integration applications, on-premises connectivity, archiving, and high availability.

    2013.12.10biztalkservices05

    I created a new database instance and storage account to ensure that there would be no conflicts with old (beta) WABS instances. Once the provisioning process was complete (maybe 15 minutes or so), I saw my new instance in the Windows Azure Portal.

    2013.12.10biztalkservices07

    Drilling into the WABS instance, I saw connection strings, IP addresses, certificate information, usage metrics, and more.

    2013.12.10biztalkservices08

    The Scale tab showed me the option to add more “scale units” to a particular instance. Basic, standard and premium edition instances have “high availability” built in where multiple VMs are beneath a single scale unit. Adding scale units to an instance requires standard or premium editions.

    2013.12.10biztalkservices09

    In the technical preview and beta releases of WABS, the developer was forced to create a self-signed certificate to use when securing a deployment. Now, I can download a dev certificate from the Portal and install it into my personal certificate store and trusted root authority. When I’m ready for production, I can also upload an official certificate to my WABS instance.

    Developing

    WABS projects are built in Visual Studio 2012/2013. There’s an entirely new project type for WABS, and I could see it when creating a new project.

    2013.12.10biztalkservices10

    Let’s look at what we have in Visual Studio to create WABS solutions. First, the Server Explorer includes a WABS component for creating cloud-accessible connections to line-of-business systems. I can create connections to Oracle/SAP/Siebel/SQL Server repositories on-premises and make them part of the “bridges” that define a cloud integration process.

    2013.12.10biztalkservices11

    Besides line-of-business endpoints, what else can you add to a Bridge? The final palette of activities in the Toolbox is shown below. There are a stack of destination endpoints that cover a wide range of choices. The source options are limited, but there are promises of new items to come. The Bridges themselves support one-way or request-response scenarios.

    2013.12.10biztalkservices12

    Bridges expect either XML or flat file messages. A message is defined by a schema. The schema editor is virtually identical to the visual tool that ships with the standard BizTalk Server product. Since source and destination message formats may differ, it’s often necessary to include a transformation component. Transformation is done via a very cool Mapper that includes a sophisticated set of canned operations for transforming the structure and content of a message. This isn’t the Mapper that comes with BizTalk Server, but a much better one.

    2013.12.10biztalkservices14

     

    A bridge configuration model includes a source, one or more bridges (which can be chained together), and one or more destinations. In the case below, I built a simple one-way model that routes to a Windows Azure Service Bus Queue.

    2013.12.10biztalkservices15

    Double-clicking a particular bridge shows me the bridge configuration. In this configuration, I specified an XML schema for the inbound message, and a transformation to a different format.

    2013.12.10biztalkservices16

     

    At this point, I have a ready-to-go integration solution.

    Deploying

    To deploy one of theses solutions, you’ll need a certificate installed (see earlier note), and the Windows Azure Access Control Service credentials shown in the Windows Azure Portal. With that info handy, I right-clicked the project in Visual Studio and chose Deploy. Within a few seconds, I was told that everything was up and running. To confirm, I clicked the Manage button on the WABS instance page was visited the WABS-specific Portal. This Portal shows my deployed components, and offers tracking services. Ideally, this would be baked into the Windows Azure Portal itself, but at least it somewhat resembles the standard Portal.

    2013.12.10biztalkservices17

    So it looks like I have everything I need to build a test.

    Testing

    I finally built a simple Console application in Visual Studio to submit a message to my Bridge. The basic app retrieved a valid ACS token and sent it along with my XML message to the bridge endpoint. After running the app, I got back the tracking ID for my message.

    2013.12.10biztalkservices19

    To actually see that this worked, I first looked in the WABS Portal to find the tracked instance. Sure enough, I saw a tracked message.

    2013.12.10biztalkservices18

    As a final confirmation, I opened up the powerful Service Bus Explorer tool and connected to my Windows Azure account. From here, I could actually peek into the Windows Azure Service Bus Queue that the WABS bridge published to. As you’d expect, I saw the transformed message in the queue.

    2013.12.10biztalkservices20

    Verdict

    There is a wide spectrum of products in the integration-as-a-service domain. There are batch-oriented tools like Informatica Cloud and Dell Boomi, and things like SnapLogic that handle both real-time and batch. Mulesoft sells the CloudHub which is a comprehensive platform for real-time integration. And of course, there are other integration solutions like AWS Simple Notification Services or the Windows Azure Service Bus.

    So where does WABS fit in? It’s clearly message-oriented, not batch-oriented. It’s more than a queuing solution, but less than an ESB. It seems like a good choice for simple connections between different organizations, or basic EDI processing. There are a decent number of source and destination endpoints available, and the line-of-business connectivity is handy. The built in high availability and optional scalability mean that it can actually be used in production right now, so that’s a plus.

    There’s still lots of room for improvement, but I guess that’s to be expected with a v1 product. I’d like to see a better entry-level pricing structure, more endpoint choices, more comprehensive bridge options (like broadcasting to multiple endpoints), built-in JSON support, and SDKs that support non-.NET languages.

    What do you think? See any use cases where you’d use this today, or are there specific features that you’ll be waiting for before jumping in?

  • New Article on Creating and Consuming Custom Salesforce.com Web Services

    I’ve been asked to write a few more articles for the DeveloperForce site (the developer-centric destination for Salesforce.com developers) and the first one is now online. This article, entitled “Working with Custom SOAP and REST Services in .NET Applications” takes a look at how to construct custom SOAP and REST services in Force.com, and then consume them from .NET applications.

    In this longer-than-expected article, I reviewed WHY you create custom services in a product that already has a robust SOAP/REST API, and show you how to build composite services, transaction-friendly services, and more. Consuming these custom services from .NET (or products like BizTalk Server) is easy and I tried to make it simple to follow along.

    Salesforce.com is growing like gangbusters, and the need for qualified integration architects is growing with it. Every time someone stands up a SaaS application, they should be thinking about how to integrate with other cloud or on-premises systems. I’ve been writing all these articles for them because (a) it’s fun, and (b) it’s important to understand all the integration options! Next up, I’ll be looking at mobile notification services (like Windows Azure Notification Hubs) and their Streaming API.

  • Using the Windows Azure Service Bus REST API to Send to Topic from Salesforce.com

    In the past, I’ve written and talked about integrating the Windows Azure Service Bus with non-Microsoft platforms like Salesforce.com. I enjoy showing how easy it is to use the Service Bus Relay to connect on-premises services with Salesforce.com. On multiple occasions, I’ve been asked how to do this with Service Bus brokered messaging options (i.e. Topics and Queues) as well. It can be a little tricky as it requires the use of the Windows Azure REST API and there aren’t a ton of public examples of how to do it! So in this blog post, I’ll show you how to send a message to a Service Bus Topic from Salesforce.com. Note that this sequence resembles how you’d do this on ANY platform that can’t use a Windows Azure SDK.

    Creating the Topic and Subscription

    First, I needed a Topic and Subscription to work with. Recall that Topics differ from Queues in that a Topic can have multiple subscribers. Each subscription (which may filter on message properties) has its own listener and gets their own copy of the message. In this fictitious scenario, I wanted users to submit IT support tickets from a page within the Salesforce.com site.

    I could create a Topic in a few ways. First, there’s the Windows Azure portal. Below you can see that I have a Topic called “TicketTopic” and a Subscription called “AllTickets”.

    2013.09.18topic01

    If you’re a Visual Studio developer, you can also use the handy Windows Azure extensions to the Server Explorer window. Notice below that this tool ALSO shows me the filtering rules attached to each Subscription.

    2013.09.18topic02

    With a Topic and Subscription set up, I was ready to create a custom VisualForce page to publish to it.

    Code to Get an ACS Token

    Before I could send a message to a Topic, I needed to get an authentication token from the Windows Azure Access Control Service (ACS). This token goes into the request header and lets Windows Azure determine if I’m allowed to publish to a particular Topic.

    In Salesforce.com, I built a custom VisualForce page with the markup necessary to submit a support ticket. The final page looks like this:

    2013.09.18topic03

    I also created a custom Controller that extended the native Accounts Controller and added an operation to respond to the “Submit Ticket” button event. The first bit of code is responsible for calling ACS and getting back a token that can be included in the subsequent request. Salesforce.com extensions are written in a language called Apex, but it should look familiar to any C# or Java developer.

           Http h= new Http();
           HttpRequest acReq = new HttpRequest();
           HttpRequest sbReq = new HttpRequest();
    
            // define endpoint and encode password
           String acUrl = 'https://seroter-sb.accesscontrol.windows.net/WRAPV0.9/';
           String encodedPW = EncodingUtil.urlEncode(sbUPassword, 'UTF-8');
    
           acReq.setEndpoint(acUrl);
           acReq.setMethod('POST');
           // choose the right credentials and scope
           acReq.setBody('wrap_name=demouser&amp;wrap_password=' + encodedPW + '&amp;wrap_scope=http://seroter.servicebus.windows.net/');
           acReq.setHeader('Content-Type','application/x-www-form-urlencoded');
    
           HttpResponse acRes = h.send(acReq);
           String acResult = acRes.getBody();
    
           // clean up result to get usable token
           String suffixRemoved = acResult.split('&amp;')[0];
           String prefixRemoved = suffixRemoved.split('=')[1];
           String decodedToken = EncodingUtil.urlDecode(prefixRemoved, 'UTF-8');
           String finalToken = 'WRAP access_token=\"' + decodedToken + '\"';
    

    This code block makes an HTTP request to the ACS endpoint and manipulates the response into the token format I needed.

    Code to Send the Message to a Topic

    Now comes the fun stuff. Here’s how you actually send a valid message to a Topic through the REST API. Below is the complete code snippet, and I’ll explain it further in a moment.

          //set endpoint using this scheme: https://&lt;namespace&gt;.servicebus.windows.net/&lt;topic name&gt;/messages
           String sbUrl = 'https://seroter.servicebus.windows.net/demotopic/messages';
           sbReq.setEndpoint(sbUrl);
           sbReq.setMethod('POST');
           // sending a string, and content type doesn't seem to matter here
           sbReq.setHeader('Content-Type', 'text/plain');
           // add the token to the header
           sbReq.setHeader('Authorization', finalToken);
           // set the Brokered Message properties
           sbReq.setHeader('BrokerProperties', '{ \"MessageId\": \"{'+ guid +'}\", \"Label\":\"supportticket\"}');
           // add a custom property that can be used for routing
           sbReq.setHeader('Account', myAcct.Name);
           // add the body; here doing it as a JSON payload
           sbReq.setBody('{ \"Account\": \"'+ myAcct.Name +'\", \"TicketType\": \"'+ TicketType +'\", \"TicketDate\": \"'+ SubmitDate +'\", \"Description\": \"'+ TicketText +'\" }');
    
           HttpResponse sbResult = h.send(sbReq);
    

    So what’s happening here? First, I set the endpoint URL. In this case, I had to follow a particular structure that includes “/messages” at the end. Next, I added the ACS token to the HTTP Authorization header.

    After that, I set the brokered messaging header. This fills up a JSON-formatted BrokerProperties structure that includes any values you needed by the message consumer. Notice here that I included a GUID for the message ID and provided a “label” value that I could access later. Next, I defined a custom header called “Account”. These custom headers get added to the Brokered Message’s “Properties” collection and are used in Subscription filters. In this case, a subscriber could choose to only receive Topic messages related to a particular account.

    Finally, I set the body of the message. I could send any string value here, so I chose a lightweight JSON format that would be easy to convert to a typed object on the receiving end.

    With all that, I was ready to go.

    Receiving From Topic

    To get a message into the Topic, I submitted a support ticket from the VisualForce page.

    2013.09.18topic04

    I immediately switched to the Windows Azure portal to see that a message was now queued up for the Subscription.

    2013.09.18topic05

    How can I retrieve this message? I could use the REST API again, but let’s show how we can mix and match techniques. In this case, I used the Windows Azure SDK for .NET to retrieve and delete a message from the Topic. I also referenced the excellent JSON.NET library to deserialize the JSON object to a .NET object. The tricky part was figuring out the right way to access the message body of the Brokered Message. I wasn’t able to simply pull it out a String value, so I went with a Stream instead. Here’s the complete code block:

               //pull Service Bus connection string from the config file
                string connectionString = ConfigurationManager.AppSettings["Microsoft.ServiceBus.ConnectionString"];
    
                //create a subscriptionclient for interacting with Topic
                SubscriptionClient client = SubscriptionClient.CreateFromConnectionString(connectionString, "tickettopic", "alltickets");
    
                //try and retrieve a message from the Subscription
                BrokeredMessage m = client.Receive();
    
                //if null, don't do anything interesting
                if (null == m)
                {
                    Console.WriteLine("empty");
                }
                else
                {
                    //retrieve and show the Label value of the BrokeredMessage
                    string label = m.Label;
                    Console.WriteLine("Label - " + label);
    
                    //retrieve and show the custom property of the BrokeredMessage
                    string acct = m.Properties["Account"].ToString();
                    Console.WriteLine("Account - " + acct);
    
                    Ticket t;
    
                    //yank the BrokeredMessage body as a Stream
                    using (Stream c = m.GetBody&lt;Stream&gt;())
                    {
                        using (StreamReader sr = new StreamReader(c))
                        {
                            //get a string representation of the stream content
                            string s = sr.ReadToEnd();
    
                            //convert JSON to a typed object (Ticket)
                            t = JsonConvert.DeserializeObject&lt;Ticket&gt;(s);
                            m.Complete();
                        }
                    }
    
                    //show the ticket description
                    Console.WriteLine("Ticket - " + t.Description);
                }
    

    Pretty simple. Receive the message, extract interesting values (like the “Label” and custom properties), and convert the BrokeredMessage body to a typed object that I could work with. When I ran this bit of code, I saw the values we set in Salesforce.com.

    2013.09.18topic06

    Summary

    The Windows Azure Service Bus brokered messaging services provide a great way to connect distributed systems. The store-and-forward capabilities are key when linking systems that span clouds or link the cloud to an on-premises system. While Microsoft provides a whole host of platform-specific SDKs for interacting with the Service Bus, there are platforms that have to use the REST API instead. Hopefully this post gave you some insight into how to use this API to successfully publish to Service Bus Topics from virtually ANY software platform.

  • New Pluralsight course released: “Optimizing and Managing Distributed Systems on AWS”

    My trilogy of AWS courses for Pluralsight is complete. I originally created AWS Developer Fundamentals, then added Architecting Highly Available Systems on AWS, and today released Optimizing and Managing Distributed Systems on AWS.

    This course picks up from where we left off with the last one. By the end of the Architecting Highly Available Systems on AWS course, we had built a fault tolerant ASP.NET-based cloud system that used relational databases, NoSQL databases, queues, load balancers, auto scaling, and more. Now, we’re looking at what it takes to monitor the system, deploy code, add CDNs, and introduce application caching. All of this helps us create a truly high performing, self-healing environment in the cloud. This course has a total of four modules, and each one covers the relevant AWS service, how to consume it, and what the best practices are.

    • Monitoring Cloud Systems with Amazon CloudWatch. Here we talk about the role of monitoring in distributed systems, and dig into CloudWatch. After inspecting the various metrics available to us, we test one and see how to send email-based alerts. We then jump into more complex scenarios and see how to configure Auto Scaling policies that alter the size of the cloud environment based on server CPU utilization.
    • Deploying Web Application Stacks. Deploying apps to cloud servers often requires a new way of thinking. AWS provides three useful deployment frameworks, and this module goes over each one. We discuss the AWS Elastic Beanstalk and see how to push our web application to cloud servers directly from Visual Studio. Then to see how easy it is to change an application – and demonstrate the fun of custom CloudWatch metrics – we deploy a new version of the application that captures unique business metrics. We then look at CloudFormation and how to use the CloudFormer tool to generate comprehensive templates that can deploy an entire system. Finally, we review the new OpsWorks framework and where it’s the right fit.
    • Placing Content Close to Users with CDNs. Content Delivery Networks are an awesome way to offload static content to edge locations that are closer to your users. This module talks about why CDNs matter in distributed systems and shows off Amazon CloudFront. We set up a CloudFront distribution, update our ASP.NET application to use it, and even try out the “invalidation” function to get rid of an old image.
    • Improving Application Performance with ElastiCache. Application caching is super handy and ElastiCache gives you a managed, Memcached-compliant solution. Here we talk about when and what to cache, how Memcached works, what ElastiCache is, how to create and scale clusters, and how to use the cache from .NET code. There’s a handful of demos sprinkled in, and you should get a good sense of how to configure and test a cache.

    It’s been fun crafting these two AWS courses over the summer and I hope you enjoy them!