July 2014

Volume 29 Number 7

Azure Web Sites : Teaching from the Cloud

James Chambers

This is an exciting time to be a Web developer. The end-to-end task of creating a project and deploying it to a public-facing endpoint is truly a challenge that was once daunting, perhaps even prohibitive. Yet today stands as one of computing’s “solved” challenges.

With very few resources, you can download a free IDE and source control tools. You can start a project and deploy it to a rich infrastructure, maintained for you without needing access to or knowledge of the hardware. You can have your project hosted at no cost to get started.

The building blocks we have to work with are more comprehensive than ever—whether PHP, Java or the Microsoft .NET Framework. We can now focus on the UX instead of project management, networking, storage, deployment procedures or scalability.

FrontClass, the application covered in this article, is something that decades ago would’ve been weeks of work, if not longer. It would’ve been difficult to get working in all environments. Deployment would’ve been a nightmare. And, most likely, I wouldn’t have been able to solve scalability in that time frame. Today, I can build the project and have it deployed in hours and ready to scale. The downloadable solution contains the complete, working source code you can deploy without having to modify your own Microsoft Azure account.

I started FrontClass while volunteering at a local junior high school, teaching programming to kids ages 10 to 14. I wanted to share content with students in a way that I could control the pace, but let them go back to previous steps on-demand. There are three functional areas of the application that help a teacher conduct a class: lesson composition, classroom instruction and student participation. I’ll break down each of these areas, but, naturally, there is some overlap.

Project Basics

To build the app, I’ll use Visual Studio 2013 Update 2. I’ll also use the ASP.NET Web Application when creating the solution and the ASP.NET MVC template. The project spawned from the template will use the popular Bootstrap front-end framework for styling and some UI functionality.

To enable real-time functionality, I’ll add the SignalR packages and use tooling now well-known to Visual Studio. I’ll also use the requisite jQuery libraries on the client pages. I’ll configure the Entity Framework (EF) to use LocalDb by default in the develop­ment environment, but when I deploy to Azure Web Sites, I’ll be using Azure SQL Database as the data store. I start the whole project, however, in the Azure Portal (portal.azure.com), where I can configure my deployment target.

Create the Azure Web Site At the bottom-left corner of the Portal, click New and select the Website + SQL template, as shown in Figure 1. Azure will create a set of linked resources. Select an appropriate name for this group and name the application. I can choose to create a new database server or select an existing one on my account to create the database for my site. It’s recommended to have the database and the Web site in the same zone to reduce network traffic times.

Create a New Azure Web Site with Linked Database
Figure 1 Create a New Azure Web Site with Linked Database

In my case, I called the resource group ELearning, the database FrontClass_DB, and the site FrontClass. You’ll need to choose a unique site name. Once provisioning is complete, I get the frontclass.azurewebsites.net hostname and my deployment target is ready to host my site.

Despite the appearance of magical happenings, there’s really not much that should surprise you here. I’ve created a DNS entry, mapped a host name to an IP address, and made some configuration options like default documents and connection strings. These are essentially the things you’d be doing in IIS behind the scenes to get your site running. So, again, it’s not magical, but it’s quite convenient. There are also some infrastructure-type tools like source control and deployment scripts available to help get you started.

Create the Solution Next, I head into Visual Studio and select the aforementioned ASP.NET Web Application as a base for my solution. As I choose the type of project to create—using the ASP.NET MVC template—I also get options to create the related resources on Azure. I’ve already created the site and database through the Portal, so I clear the checkbox and proceed with creating the site.

Compose Course Modules

Because of the scope of this project, I’m able to maintain a fairly straightforward data model. I use EF6 to create the models via Code First, which leaves the door open for modifications down the road using data migrations. The end result, shown in Figure 2, is a simple set of classes representing the course, module and step structures.

The Basic Application Data Model
Figure 2 The Basic Application Data Model

There’s a bit of ceremony to walk through to get all the wiring where I want it. Namely, I want to use a single database, I want to be able to control when migrations are generated and I want my application to automatically execute any outstanding migrations at application startup. 

This lets me explicitly control the changes that appear in each migration. It also lets my application update itself without intervention. I will also set up a means to pre-populate the database with the Administrator role and the Instructor role (the first and only administrative user) through the Seed override on the Configuration class.

Specify a Connection String Entity Framework lets me use the same database with different contexts and migrations within a single connection string. By calling the base class constructor and passing in a name, the framework will look first to the application or Web configuration to see if there’s a connection string defined by the same name. If so, it will use it to make the connection.

Migration history for each context is maintained by logging the namespace as part of the update process. This helps my migrations execute independently of each other. To set this up, I added a default constructor to my context class as follows:

public FrontClassContext()
  : base("DefaultConnection") { }

If you look at the context created as part of the project template located in the IdentityModels.cs file, you’ll see there’s a similar default constructor present. It’s slightly modified to reflect the nature of the IdentityDbContext base class, but still uses the DefaultConnection connection string from the Web.Config file.

Enable Migrations I generated the configuration class for the entities created by executing the following command from the Package Manager Console in Visual Studio:

Enable-Migrations -ContextTypeName FrontClass.DAL.FrontClassContext

This lights up migrations for my course-­related entities. I want to do the same for the ApplicationDbContext, as well. I could run that command again with the class name swapped out. However, when I enable configuration, migrations and seeding in the context where the accounts are stored, I don’t want to overwrite the previously scaffolded configuration class. Instead, I specify an alternate directory for the migrations, as follows, with the Migrations­Directory parameter passed into the command:

 

Enable-Migrations -ContextTypeName FrontClass.Models.ApplicationDbContext -MigrationsDirectory:"Models\AccountMigrations"

Add the First Migrations The next step is to simply scaffold the classes the Entity Framework will execute. I use the following command twice, once for each DbContext for which I wish to create a migration:

Add-Migration Initial-Model -ConfigurationTypeName FrontClass.Migrations.Configuration
Add-Migration Initial-Model -ConfigurationTypeName FrontClass.Models.AccountMigrations.Configuration

Again, working with multiple contexts adds a bit of complexity because you have to specify the ConfigurationTypeName parameter. Otherwise, this is a straightforward operation.

Set the Database Initialization Strategy To configure EF to execute my migrations automatically, I need to tell it what strategy to use before performing any database access. Without doing so, I’ll receive exception messages at run time that indicate my model is out of sync with the database. Each change to my classes affects the computed hash of my data model, which is tracked in the database.

In my Global.asax I’ve added the following two lines of code to use the MigrateDatabaseToLatestVersion initializer:

Database.SetInitializer<ApplicationDbContext>(
  new MigrateDatabaseToLatestVersion
    <ApplicationDbContext, 
     FrontClass.Models.AccountMigrations.Configuration>());
Database.SetInitializer<FrontClassContext>(
  new MigrateDatabaseToLatestVersion
    <FrontClassContext, FrontClass.Migrations.Configuration>());

Note that I’m calling the generic SetInitializer method that accepts the context I want to configure. In my case, my configuration classes are like-named so I’ve specified the fully namespaced class names.

Seed the Tables At first run, I want to be able to deliver an experience that lets someone “just log in” and start using the app. I could create a run-once controller akin to what you’d find in popular blogging applications. Another option is to use the Seed methods in my Configuration classes. The seed method is passed in an instance of the appropriate context, from which I can manipulate the tables. 

With ASP.NET Identity 2.0, I also get a rich set of classes that are EF-aware. This lets me conditionally inject the role and user into the database, as I’m doing in Figure 3.

Figure 3 Seeding the First Role and Administrative User

if (!context.Roles.Any(r => r.Name == 
  FrontClass.MvcApplication.AdministratorRoleName))
{
  var roleStore = new RoleStore<IdentityRole>(context);
  var roleManager = new RoleManager<IdentityRole>(roleStore);
  var identityRole = new IdentityRole 
    {Name = FrontClass.MvcApplication.AdministratorRoleName};
  roleManager.Create(identityRole);
}
var instructorName = "instructor@contonso.com";
if (!context.Users.Any(u => u.UserName == instructorName))
{
  var userStore = new UserStore<ApplicationUser>(context);
  var userManager = new UserManager<ApplicationUser>(userStore);
  var applicationUser = 
    new ApplicationUser { UserName = instructorName };
  userManager.Create(applicationUser, "init_2014");
  userManager.AddToRole(applicationUser.Id, 
    FrontClass.MvcApplication.AdministratorRoleName);
}

I’ve also seeded the module-related tables with some sample data, which you can see in the download that accompanies this article. When the application starts up, I can log in with the instructor@contonso.com username using the password init_2014. At this point, I have my data structures in place, the application is configured with multiple contexts to use the same database and I have an administrative user—the instructor account—that can log in.

Basic Editing Capabilities The last piece required to allow actual course composition is to provide the create, read, update and delete (CRUD) capabilities. I create a new area called administration in the root of my project and use the built-in scaffolding tools to build out the UI. Finally, I create an Admin controller with an index action and a view that provides links to course maintenance, modules and steps.

Instruct the Course

As the instructor, you can choose a course from the same administration view, from which you would then choose a module. Each of the steps are displayed on the subsequent module page, as you can see in Figure 4. You can send any step to any student in the virtual classroom with a preview of the content available to the instructor.

Conduct the Class
Figure 4 Conduct the Class

The students could be in a conference session, in a classroom with an instructor, or spread around the world. One context in which you could use this application would be a live, online virtual classroom with dozens or even hundreds of students. I want to ensure that regardless of how you may need to adapt the application, you don’t lose the ability to scale. So I have to consider how the lesson payload will actually get to the student.

You can create the steps within a course module as plain text or HTML, and each step can be an arbitrary length. SignalR does a great job of handling the mechanics of negotiating transport (with WebSockets, server-sent events, long polling or forever frame) and it abstracts the need to worry about message serialization.

Ultimately, to remain scalable, I need to keep my messages small. This is to minimize demand on server resources, reduce the costs of serialization, let the client’s browser leverage parts of infrastructure such as caching, and use SignalR in the same vein of its design: for signaling.

The best way to achieve this is to simply send a message to the client saying, “New content is available here,” instead of sending the entire lesson step along. Consider the following serialized message as received by the client in the JSON here:

{"H":"ModuleStepHub", "M":"updateStep",
  "A":["\n<h1>Welcome to the course!</h1><p>trimmed for brevity...</p>\n"]}

That message carries HTML as the argument payload for the client-side updateStep method. That “trimmed for brevity” text is the source of the concern. The content could grow dramatically depending on how an instructor created a step. For now, this is just text. You can imagine how the size of the message would grow if you tried to send pages of content or an image down the pipe. The text or image would be serialized as JSON and delivered to each client using the signaling pipeline resources. Instead, I just want to send the signal, particularly the new content ID the browser should load. That considerably smaller message would look more like this:

{"H":"ModuleStepHub","M":"notifyStepAvailable","A":[7]}

Now that I know what I’m trying to accomplish with my messaging, I can build out this functionality in my application.

Create the Hub: I add a Hub folder to my project, then add a SignalR Hub Class (v2) from the Add New Item dialog. A hub is the server-side piece of SignalR you create to publish messages and handle client calls. Going this route, Visual Studio pulls in my dependencies and scaffolds a class with a sample method in my hub. I remove the sample method and create a new one that lets me send a message with the following code:

public void MakeStepAvailable(int stepId)
{
  Clients.Others.notifyStepAvailable(stepId);
}

The premise here is the course instructor will invoke some kind of action that sends the step along to the students. Using the Others dynamic property on the Clients object, I tell SignalR to send the step ID to all other connected clients. SignalR provides a number of such filtering options so I can update a specific user, a group of users, or some other slice of connected clients. The hub also lets instructors start a new module. Students can get the list of steps made available by the instructor.

Map SignalR Hubs To expose the functionality I create in my hub, I need to poke SignalR as my application is starting. A call to MapSignalR sets up a default endpoint that serves up a JavaScript proxy. When included in the client, this invokes server-side methods from the client and vice versa. The root folder of my project includes an OWIN Startup class where I make the call to do the wiring in the Configuration method. This is how that looks after my changes:

public void Configuration(IAppBuilder app)
{
  ConfigureAuth(app);
  app.MapSignalR();
}

It’s important to call ConfigureAuth here first. The OWIN pipeline pushes messages through middleware in the order of which the middleware is registered. In our case, we want authentication and authorization to occur before calls reach our Hub.

Enable Sharing To let the instructor share content, I add another controller to the application called InstructController. This has only an Index action. I’ve decorated the class with the Authorize attribute, so only Administrators can control the classroom. The index action accepts a module ID as a parameter, the route for which is configured in my App_Startup\RouteConfig.cs class. The method looks up the module from the database and returns the record to the view with the Steps collection included in the query.

In the corresponding view (located at Views\Instruct\Index.cshtml), I simply generate a Share button for each step. I use a data-id attribute to store the ID of the step. I include the SignalR library and the hub proxy exposed in the previous step, then write a small amount of JavaScript to start up the proxy and handle click events from the instructor, as shown in Figure 5.

Figure 5 JavaScript to Start up the Proxy and Handle Click Events

<script src="~/Scripts/jquery.signalR-2.0.3.js"></script>
<script src="~/SignalR/Hubs"></script>
<script>
  $(function() {
    var hub = $.connection.moduleStepHub;
    $.connection.hub.start().done(function() {
      $(".share-step").click(function() {
        var stepId = $(this).attr("data-id");
          hub.server.makeStepAvailable(stepId);
      });
    });
  });
</script>

Finally, I modify my administrative index page to include the list of courses and modules from which the instructor can choose. The final interface, as displayed in Figure 6, lets the instructor jump right into a module and start teaching.

The Administrative Interface for FrontClass
Figure 6 The Administrative Interface for FrontClass

Using the module view from Figure 4, the instructor can then send content to the class.

Class Participation

As a student, the story is much simpler. Just show up! Each student will need to sign up to access the site, and receive instructions for the active course module they need to enter the passcode. The registration process is taken care of by the default Account controller in my project. I’ll need to create the page that hosts the lesson content and write the code needed for students to participate in the class. For students to join the classroom when a class is active, they must have first enrolled for the course.

Build the Classroom Controller Right-clicking on the Controllers folder in the root of the project lets me add a new controller and name it ClassroomController. The two primary methods I add to this class are Index, where the main content will be served, and GetModuleStep, which returns the requested step after meeting a number of preconditions. A third action handles cases where there’s no active module for the class. To access module materials, a student must be logged in to the site and enrolled in the active module’s course.

Allow Course Enrollment The ClassroomController is deco­rated with an EnrollmentVerficationFilter I created to ensure students can only access courses for which they have the entry code set by the instructor. If the user hasn’t yet enrolled or an instructor hasn’t started a module, then students are redirected to the Index action on the EnrollmentController, as you can see in Figure 7. Students can enroll in a course with the appropriate entry code. Upon successful enrollment, I add a claim to the user account using the relevant ASP.NET Identity components.

The Course Lobby and Enrollment Page
Figure 7 The Course Lobby and Enrollment Page

I add a claim through the UserManager class, to which I gain access by getting an instance of my ApplicationDbContext and using that to build a UserStore, which is then passed into my target class:

var context = new ApplicationDbContext();
var userStore = new UserStore<ApplicationUser>(context);
var userManager = new UserManager<ApplicationUser>(userStore);

Once I have the necessary component in place, I get the user’s ID through the principal representing his identity and build a claim object. Then I add that to the user’s account:

var userId = User.Identity.GetUserId();
var courseClaim = new Claim(MvcApplication.CourseRegistrationClaimUrn,
  enroll.CourseId.ToString(CultureInfo.InvariantCulture));
userManager.AddClaim(userId, courseClaim);

With the claim in place on the user’s account, a student may now access the classroom.

Examine the Classroom View As you can see in Figure 8, the classroom is divided into two parts. The top of the page gives an overview of the current module and provides controls to jump to any available step. The bottom section is called the chalkboard, and displays the content shared by the instructor.

The Virtual Chalkboard
Figure 8 The Virtual Chalkboard

This page really only has a couple of DIV elements as content containers. The rest is wired up via JavaScript and through content fetched based on messages coming from the ClassroomHub or the student’s selection of a previous step. As the instructor selects new steps, the ClassroomHub is notified and sends signals to all who are in the classroom. This in turn fetches data from the ClassroomController, thus enabling caching.

Deploy the Project

The instructor can create and manage courses, modules and steps. A student can register for the site and enroll himself in courses. Courses are protected through enrollment claims, and the classroom’s virtual chalkboard is updated with content as directed by the instructor. Time to ship!

From the Build menu, I select the option to publish my project. The Publish Web dialog is displayed, and I choose Azure Web Sites as the publish target. Visual Studio prompts me for my credentials if I haven’t already signed in. Then I can choose the existing site I created at the start of this project. My publishing profile is then downloaded, complete with the pre-configured database connection strings and all credentials required to send my site to Azure.

At the beginning of this project, I first prepped my site in the Azure Portal. Because this project uses the DefaultConnection connection string, already present in my publishing profile, I don’t need to make any changes when I go to production. The production connection string automatically points my application at the previously configured Azure SQL Database.

Take Advantage of Azure Web Sites

Publishing a site to a pre-configured endpoint in Azure Web Sites was a welcome surprise. It was actually easy. After years of surviving with much more complicated deployment procedures, this was surely a treat. This alone is not the end game for Azure Web Sites. There are many more tools available:

  • Add a Custom Domain: If you can register a domain and set up a couple of DNS records, it only takes minutes to add a unique domain of your choosing to your site. Read more about this at bit.ly/1sV8R1y.
  • Secure the Application: SNI-based certificates are afford­able, and you can add them through the dashboard of your Azure Web Site. Read more about this at bit.ly/1mYXndJ.
  • Scale Up the Site: If you find your project is growing, you have the option to scale up (more powerful hardware) or out (more instances). Don’t forget to also configure Azure Service Bus to handle your SignalR traffic. Read more about SignalR at bit.ly/1o6B7AC.
  • Add Continuous Deployment: For even the smallest projects, I forego direct deployment and use a Git-based source control server. Azure then creates, stages and automatically deploys my site on check-in. Read more about this at bit.ly/1o6BACT.
  • Add Monitoring and Alerts: It’s always best to know when something’s not going quite right in your application. You can watch for certain types of problems and get notifications as they happen, all configured from your site’s dashboard.

Wrapping Up

In this article, I used ASP.NET Identity 2.0, which is now part of the default ASP.NET MVC template in Visual Studio 2013. To learn more about the enhancements and changes, please check out the post on the .NET Web Development and Tools Blog at bit.ly/PXgQ2d. I also used SignalR to enable real-time communication between the client and the server. This automatically generates JavaScript proxies and invokes code on the server from the client and vice versa. For more on creating your data model using EF with Code First in an ASP.NET MVC 5 application, visit the tutorial at bit.ly/1pivbmE.

Rich experiences are a lot easier to deliver when you don’t have to take care of the underlying infrastructure or the complexities of deployment. The FrontClass application leverages authentication, authorization, real-time messaging and a persistent data store. As a developer, I get many of these building blocks thanks to the efforts of others. I don’t have to worry about the other moving parts as I move my project into production.


James Chambers is a Microsoft MVP in ASP.NET/IIS and frequent speaker at conferences and user groups across Canada. He’s the author of “Windows Azure Web Sites” (Wrox, 2013), available via eBook (bit.ly/wawsbook), and presented on the Microsoft Virtual Academy (bit.ly/wawsmva). He blogs at jameschambers.com and you can reach him on Twitter at twitter.com/CanadianJames.

Thanks to the following technical expert for reviewing this article: Chad McCallum (independent consultant)