This tutorial shows how to deploy an ASP.NET web application that uses the ASP.NET Web API to a Windows Azure Web Site by using the Publish Web wizard in Visual Studio 2012 or Visual Studio 2012 for Web Express.
You can open a Windows Azure account for free, and if you don't already have Visual Studio 2012, the SDK automatically installs Visual Studio 2012 for Web Express. So you can start developing for Windows Azure entirely for free.
This tutorial assumes that you have no prior experience using Windows Azure. On completing this tutorial, you'll have a data-driven web application up and running in the cloud and using a cloud database.
You'll learn:
- How to enable your machine for Windows Azure development by installing the Windows Azure SDK.
- How to create a Visual Studio ASP.NET MVC 4 project and publish it to a Windows Azure Web Site.
- How to use the ASP.NET Web API to enable Restful API calls.
- How to use a SQL database to store data in Windows Azure.
- How to publish application updates to Windows Azure.
You'll build a simple contact list web application that is built on ASP.NET MVC 4 and uses the ADO.NET Entity Framework for database access. The following illustration shows the completed application:
In this tutorial:
- Set up the development environment
- Set up the Windows Azure environment
- Create an ASP.NET MVC 4 application
- Deploy the application to Windows Azure
- Add a database to the application
- Add a Controller and a view for the data
- Add a Web API Restful interface
- Add XSRF Protection
- Publish the application update to Windows Azure and SQL Database
To start, set up your development environment by installing the Windows Azure SDK for the .NET Framework.
- To install the Windows Azure SDK for .NET, click the link below. If you don't have Visual Studio 2012 installed yet, it will be installed by the link. This tutorial requires Visual Studio 2012.
Get Tools and SDK for Visual Studio 2012 - When you are prompted to run or save vwdorvs11azurepack.exe, click Run.
When the installation is complete, you have everything necessary to start developing.
Next, set up the Windows Azure environment by creating a Windows Azure Web Site and a SQL database.
The next step is to create the Windows Azure web site and the SQL database that your application will use.
Your Windows Azure Web Site will run in a shared hosting environment, which means it runs on virtual machines (VMs) that are shared with other Windows Azure clients. A shared hosting environment is a low-cost way to get started in the cloud. Later, if your web traffic increases, the application can scale to meet the need by running on dedicated VMs. If you need a more complex architecture, you can migrate to a Windows Azure Cloud Service. Cloud services run on dedicated VMs that you can configure according to your needs.
SQL Database is a cloud-based relational database service that is built on SQL Server technologies. The tools and applications that work with SQL Server also work with SQL Database.
- In the Windows Azure Management Portal, click Web Sites in the left tab, and then click New.
- Click CUSTOM CREATE.
The New Web Site - Custom Create wizard opens. - In the New Web Site step of the wizard, enter a string in the URL box to use as the unique URL for your application. The complete URL will consist of what you enter here plus the suffix that you see below the text box. The illustration shows "contactmgr22", but that URL is probably taken so you’ll have to choose a different one.
- In the Region drop-down list, choose the region that is closest to you.
- In the Database drop-down list, choose Create a new SQL database.
Accept the default connection string.
- Click the arrow that points to the right at the bottom of the box. The wizard advances to the Database Settings step.
- In the Name box, enter ContactDB.
- In the Server box, select New SQL Database server. Alternatively, if you previously created a SQL Server database, you can select that SQL Server from the dropdown control.
- Click the arrow that points to the right at the bottom of the box.
- Enter an administrator LOGIN NAME and PASSWORD. If you selected New SQL Database server you aren't entering an existing name and password here, you're entering a new name and password that you're defining now to use later when you access the database. If you selected a SQL Server you’ve created previously, you’ll be prompted for the password to the previous SQL Server account name you created. For this tutorial, we won't check the **Advanced ** box. The **Advanced ** box allows you to set the DB size (the default is 1 GB but you can increase this to 150 GB) and the collation.
- Click the check mark at the bottom of the box to indicate you're finished.
The following image shows using an existing SQL Server and Login.
The Management Portal returns to the Web Sites page, and the Status column shows that the site is being created. After a while (typically less than a minute), the Status column shows that the site was successfully created. In the navigation bar at the left, the number of sites you have in your account appears next to the Web Sites icon, and the number of databases appears next to the SQL Databases icon.
You have created a Windows Azure Web Site, but there is no content in it yet. Your next step is to create the Visual Studio web application project that you'll publish to Windows Azure.
- Start Visual Studio 2012.
- From the File menu click New Project.
- In the New Project dialog box, expand Visual C# and select Web under Installed Templates and then select ASP.NET MVC 4 Web Application. Keep the default .NET Framework 4.5. Name the application ContactManager and click OK.
- In the New ASP.NET MVC 4 Project dialog box, select the Internet Application template. Keep the default Razor View Engine and then click OK.
- In Solution Explorer, expand the Views\Shared folder and open the _Layout.cshtml file.
- Replace the contents of the _Layout.cshtml file with the following code:
<!DOCTYPE html><br/>
<html lang="en"><br/>
<head><br/>
<meta charset="utf-8" /><br/>
<title>@ViewBag.Title - Contact Manager</title><br/>
<link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" /><br/>
<meta name="viewport" content="width=device-width" /><br/>
@Styles.Render("~/Content/css")<br/>
@Scripts.Render("~/bundles/modernizr")<br/>
</head><br/>
<body><br/>
<header><br/>
<div class="content-wrapper"><br/>
<div class="float-left"><br/>
<p class="site-title">@Html.ActionLink("Contact Manager", "Index", "Home")</p><br/>
</div><br/>
</div><br/>
</header><br/>
<div id="body"><br/>
@RenderSection("featured", required: false)<br/>
<section class="content-wrapper main-content clear-fix"><br/>
@RenderBody()<br/>
</section><br/>
</div><br/>
<footer><br/>
<div class="content-wrapper"><br/>
<div class="float-left"><br/>
<p>&copy; @DateTime.Now.Year - Contact Manager</p><br/>
</div><br/>
</div><br/>
</footer><br/><br/>
@Scripts.Render("~/bundles/jquery")<br/>
@RenderSection("scripts", required: false)
</body><br/>
</html>
This is all you need to do for now to create the application that you'll deploy to Windows Azure. Later you'll add database functionality.
-
In your browser, open the Windows Azure Management Portal.
-
In the Web Sites tab, click the name of the site you created earlier.
-
On the right side of the window, click Download publish profile.
This step downloads a file that contains all of the settings that you need in order to deploy an application to your Web Site. You'll import this file into Visual Studio so you don't have to enter this information manually. -
Save the .publishsettings file in a folder that you can access from Visual Studio.
Security Note: The .publishsettings file contains your credentials (unencoded) that are used to administer your Windows Azure subscriptions and services. The security best practice for this file is to store it temporarily outside your source directories (for example in the Libraries\Documents folder), and then delete it once the import has completed. A malicious user gaining access to the publishsettings file can edit, create, and delete your Windows Azure services. -
In Visual Studio, right-click the project in Solution Explorer and select Publish from the context menu.
The Publish Web wizard opens. -
Select the .publishsettings file you downloaded earlier, and then click Open.
-
In the Connection tab, click Validate Connection to make sure that the settings are correct. When the connection has been validated, a green check mark is shown next to the Validate Connection button.
-
In the Settings tab, click Next.
You can accept all of the default settings on this page. You are deploying a Release build configuration and you don't need to delete files at the destination server. The UsersContext (DefaultConnection) entry under Databases comes from the UsersContext:DbContext class which uses the DefaultConnection string. -
In the Preview tab, click Start Preview.
The tab displays a list of the files that will be copied to the server. Displaying the preview isn't required to publish the application but is a useful function to be aware of. In this case, you don't need to do anything with the list of files that is displayed.
-
Click Publish.
Visual Studio begins the process of copying the files to the Windows Azure server. The Output window shows what deployment actions were taken and reports successful completion of the deployment. -
The default browser automatically opens to the URL of the deployed site.
The application you created is now running in the cloud.
Next, you'll update the MVC application to add the ability to display and update contacts and store the data in a database. The application will use the Entity Framework to create the database and to read and update data in the database.
You begin by creating a simple data model in code.
-
In Solution Explorer, right-click the Models folder, click Add, and then Class.
-
In the Add New Item dialog box, name the new class file Contact.cs, and then click Add.
-
Replace the contents of the Contacts.cs file with the following code.
using System.Globalization; namespace ContactManager.Models { public class Contact { public int ContactId { get; set; } public string Name { get; set; } public string Address { get; set; } public string City { get; set; } public string State { get; set; } public string Zip { get; set; } public string Email { get; set; } public string Twitter { get; set; } public string Self { get { return string.Format(CultureInfo.CurrentCulture, "api/contacts/{0}", this.ContactId); } set { } } } }
The Contacts class defines the data that you will store for each contact, plus a primary key, ContactID, that is needed by the database.
The ASP.NET MVC the scaffolding feature can automatically generate code that performs create, read, update, and delete (CRUD) actions.
- In Solution Explorer, expand the Controllers folder.
- Build the project (Ctrl+Shift+B). (You must build the project before using scaffolding mechanism.)
- Right-click the Controllers folder and click Add, and then click Controller....
- In the Add Controller dialog box, enter "HomeController" as your controller name. Set the Scaffolding options Template to MVC Controller with read/write actions and views, using Entity Framework.
- Select Contact as your model class and <New data context...> as your data context class.
- On the New Data Context dialog box, accept the default value ContactManager.Models.ContactManagerContext.
- Click OK, then click Add in the Add Controller dialog box.
- On the Add Controller overwrite dialog, make sure all options are checked and click OK.
Visual Studio creates a controller methods and views for CRUD database operations for Contact objects.
The next task is to enable the Code First Migrations feature in order to create the database based on the data model you created.
-
In the Tools menu, select Library Package Manager and then Package Manager Console.
-
In the Package Manager Console window, enter the following command:
enable-migrations -ContextTypeName ContactManagerContext
You must specify the context type name (ContactManagerContext) because the project contains two DbContext derived classes, the ContactManagerContext we just added and the UsersContext, which is used for the membership database. The ContactManagerContext class was added by the Visual Studio scaffolding wizard.
The enable-migrations command creates a Migrations folder and it puts in that folder a Configuration.cs file that you can edit to configure Migrations.
-
In the Package Manager Console window, enter the following command:
add-migration Initial
The add-migration Initial command generates a class named <date_stamp>Initial that creates the database. The first parameter ( Initial ) is arbitrary and used to create the name of the file. You can see the new class files in Solution Explorer.
In the Initial class, the Up method creates the Contacts table, and the Down method (used when you want to return to the previous state) drops it. -
Right-click the Migrations folder and open the Configuration.cs file.
-
Add the following namespaces.
using ContactManager.Models;
-
Replace the Seed method with the following code:
protected override void Seed(ContactManager.Models.ContactManagerContext context) { context.Contacts.AddOrUpdate(p => p.Name, new Contact { Name = "Debra Garcia", Address = "1234 Main St", City = "Redmond", State = "WA", Zip = "10999", Email = "debra@example.com", Twitter = "debra_example" }, new Contact { Name = "Thorsten Weinrich", Address = "5678 1st Ave W", City = "Redmond", State = "WA", Zip = "10999", Email = "thorsten@example.com", Twitter = "thorsten_example" }, new Contact { Name = "Yuhong Li", Address = "9012 State st", City = "Redmond", State = "WA", Zip = "10999", Email = "yuhong@example.com", Twitter = "yuhong_example" }, new Contact { Name = "Jon Orton", Address = "3456 Maple St", City = "Redmond", State = "WA", Zip = "10999", Email = "jon@example.com", Twitter = "jon_example" }, new Contact { Name = "Diliana Alexieva-Bosseva", Address = "7890 2nd Ave E", City = "Redmond", State = "WA", Zip = "10999", Email = "diliana@example.com", Twitter = "diliana_example" } ); }
This code above will initialize the database with the contact information. For more information on seeding the database, see Debugging Entity Framework (EF) DBs.
-
In the Package Manager Console enter the command:
update-database
The update-database runs the first migration which creates the database. By default, the database is created as a SQL Server Express LocalDB database. (Unless you have SQL Server Express installed, in which case the database is created using the SQL Server Express instance.)
-
Press CTRL+F5 to run the application.
The application shows the seed data and provides edit, details and delete links.
-
Expand the Views\Home folder and open the Index.cshtml file.
-
Replace the contents of the file with the following code.
@model IEnumerable<ContactManager.Models.Contact> @{ ViewBag.Title = "Home"; } @section Scripts { @Scripts.Render("~/bundles/knockout") <script type="text/javascript"> function ContactsViewModel() { var self = this; self.contacts = ko.observableArray([]); self.addContact = function () { $.post("api/contacts", $("#addContact").serialize(), function (value) { self.contacts.push(value); }, "json"); } self.removeContact = function (contact) { $.ajax({ type: "DELETE", url: contact.Self, success: function () { self.contacts.remove(contact); } }); } $.getJSON("api/contacts", function (data) { self.contacts(data); }); } ko.applyBindings(new ContactsViewModel()); </script> } <ul id="contacts" data-bind="foreach: contacts"> <li class="ui-widget-content ui-corner-all"> <h1 data-bind="text: Name" class="ui-widget-header"></h1> <div><span data-bind="text: $data.Address || 'Address?'"></span></div> <div> <span data-bind="text: $data.City || 'City?'"></span>, <span data-bind="text: $data.State || 'State?'"></span> <span data-bind="text: $data.Zip || 'Zip?'"></span> </div> <div data-bind="if: $data.Email"><a data-bind="attr: { href: 'mailto:' + Email }, text: Email"></a></div> <div data-bind="ifnot: $data.Email"><span>Email?</span></div> <div data-bind="if: $data.Twitter"><a data-bind="attr: { href: 'http://twitter.com/' + Twitter }, text: '@@' + Twitter"></a></div> <div data-bind="ifnot: $data.Twitter"><span>Twitter?</span></div> <p><a data-bind="attr: { href: Self }, click: $root.removeContact" class="removeContact ui-state-default ui-corner-all">Remove</a></p> </li> </ul> <form id="addContact" data-bind="submit: addContact"> <fieldset> <legend>Add New Contact</legend> <ol> <li> <label for="Name">Name</label> <input type="text" name="Name" /> </li> <li> <label for="Address">Address</label> <input type="text" name="Address" > </li> <li> <label for="City">City</label> <input type="text" name="City" /> </li> <li> <label for="State">State</label> <input type="text" name="State" /> </li> <li> <label for="Zip">Zip</label> <input type="text" name="Zip" /> </li> <li> <label for="Email">E-mail</label> <input type="text" name="Email" /> </li> <li> <label for="Twitter">Twitter</label> <input type="text" name="Twitter" /> </li> </ol> <input type="submit" value="Add" /> </fieldset> </form>
-
Right-click the Content folder and click Add, and then click New Item....
-
In the Add New Item dialog box, enter Style in the upper right search box and then select Style Sheet.
-
Name the file Contacts.css and click Add. Replace the contents of the file with the following code.
.column { float: left; width: 50%; padding: 0; margin: 5px 0; } form ol { list-style-type: none; padding: 0; margin: 0; } form li { padding: 1px; margin: 3px; } form input[type="text"] { width: 100%; } #addContact { width: 300px; float: left; width:30%; } #contacts { list-style-type: none; margin: 0; padding: 0; float:left; width: 70%; } #contacts li { margin: 3px 3px 3px 0; padding: 1px; float: left; width: 300px; text-align: center; background-image: none; background-color: #F5F5F5; } #contacts li h1 { padding: 0; margin: 0; background-image: none; background-color: Orange; color: White; font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; } .removeContact, .viewImage { padding: 3px; text-decoration: none; }
-
Expand the App_Start folder and open the BundleConfig.cs file.
-
Add the following statement to register the Knockout plugin.
bundles.Add(new ScriptBundle("~/bundles/knockout").Include( "~/Scripts/knockout-{version}.js"));
This sample using knockout to simplify dynamic JavaScript code that handles the screen templates.
-
Modify the contents/css entry to register the contacts.css style sheet. Change the following line:
bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.css"));
To:
bundles.Add(new StyleBundle("~/Content/css").Include(
"~/Content/site.css",
"~/Content/contacts.css"));
- In Solution Explorer, right-click Controllers and click Add and then Controller....
- In the Add Controller dialog box, enter "ContactsController" as your controller name, select the API controller with read/write actions, using Entity Framework template.
- In Model Class select Contact (ContactManager.Models) and in Data Context Class select ContactManagerContext (ContactManager.Models).
- Click Add.
- Press CTRL+F5 to run the application.
- Enter a contact and click Add. The app returns to the home page and displays the contact you entered.
- In the browser, append /api/contacts to the URL.
The resulting URL will resemble http://localhost:1234/api/contacts. The RESTful web API you added returns the stored contacts.
FireFox and Chrome will display the data in XML format.
IE will prompt you to open or save the contacts.
You can open the returned contacts in notepad or a browser.
This output can be consumed by another application such as mobile web page or application.
-
In Solution Explorer, right click Filters and click Add and then click Class.
-
Name the file ValidateHttpAntiForgeryTokenAttribute.cs and add the following code:
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Web.Helpers; using System.Web.Http.Controllers; using System.Web.Http.Filters; using System.Web.Mvc; namespace ContactManager.Filters { public class ValidateHttpAntiForgeryTokenAttribute : AuthorizationFilterAttribute { public override void OnAuthorization(HttpActionContext actionContext) { HttpRequestMessage request = actionContext.ControllerContext.Request; try { if (IsAjaxRequest(request)) { ValidateRequestHeader(request); } else { AntiForgery.Validate(); } } catch (HttpAntiForgeryException e) { actionContext.Response = request.CreateErrorResponse(HttpStatusCode.Forbidden, e); } } private bool IsAjaxRequest(HttpRequestMessage request) { IEnumerable<string> xRequestedWithHeaders; if (request.Headers.TryGetValues("X-Requested-With", out xRequestedWithHeaders)) { string headerValue = xRequestedWithHeaders.FirstOrDefault(); if (!String.IsNullOrEmpty(headerValue)) { return String.Equals(headerValue, "XMLHttpRequest", StringComparison.OrdinalIgnoreCase); } } return false; } private void ValidateRequestHeader(HttpRequestMessage request) { string cookieToken = String.Empty; string formToken = String.Empty; IEnumerable<string> tokenHeaders; if (request.Headers.TryGetValues("RequestVerificationToken", out tokenHeaders)) { string tokenValue = tokenHeaders.FirstOrDefault(); if (!String.IsNullOrEmpty(tokenValue)) { string[] tokens = tokenValue.Split(':'); if (tokens.Length == 2) { cookieToken = tokens[0].Trim(); formToken = tokens[1].Trim(); } } } AntiForgery.Validate(cookieToken, formToken); } } }
-
You can add the [ValidateHttpAntiForgeryToken] attribute to the ContactsController to protect it from XSRF threats. A better approach is to add the ValidateHttpAntiForgeryToken attribute globally to the App_Start\WebApiConfig.cs file as shown below:
public static class WebApiConfig { public static void Register(HttpConfiguration config) { config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); GlobalConfiguration.Configuration.Filters.Add(new ValidateHttpAntiForgeryTokenAttribute()); //config.EnableQuerySupport(); } }
To publish the application, you repeat the procedure you followed earlier.
- In Solution Explorer, right click the project and select Publish.
- Click the Settings tab.
- Under ContactsManagerContext(ContactsManagerContext), click the v icon to change Remote connection string to the connection string for the contact database.
- The remote connection string box for the ContactsManagerContext(ContactsManagerContext) database now contains the SQL Database connection string that was provided in the publishsettings file. Click on the ellipsis (...) to see the ContactDB settings.
- Close the Destination Connections String Dialog and in the Publish Web dialog check the box for Execute Code First Migrations (runs on application start) for the UsersContext(DefaultConnection) database.
- You can click the ^ icon next to the UsersContext(DefaultConnection) database, that is the connection information for the membership database and we're not using it in this tutorial. A real application would require authentication and authorization, and you would use the membership database for that purpose. See Deploy a Secure ASP.NET MVC application with OAuth, Membership and SQL Database which is based on this tutorial and shows how to deploy a web application with the membership database.
- Click Next and then click Preview. Visual Studio displays a list of the files that will be added or updated.
- Click Publish.
After the deployment completes, the browser opens to the home page of the application.
The Visual Studio publish process automatically configured the connection string in the deployed Web.config file to point to the SQL database. It also configured Code First Migrations to automatically upgrade the database to the latest version the first time the application accesses the database after deployment. As a result of this configuration, Code First created the database by running the code in the Initial class that you created earlier. It did this the first time the application tried to access the database after deployment. - Enter a contact as you did when you ran the app locally, to verify that database deployment succeeded.
When you see that the item you enter is saved and appears on the contact manager page, you know that it has been stored in the database.
The application is now running in the cloud, using SQL Database to store its data. After you finish testing the application in Windows Azure, delete it. The application is public and doesn't have a mechanism to limit access.
A real application would require authentication and authorization, and you would use the membership database for that purpose. The tutorial Deploy a Secure ASP.NET MVC application with OAuth, Membership and SQL Database is based on this tutorial and shows how to deploy a web application with the membership database.
Another way to store data in a Windows Azure application is to use Windows Azure storage, which provide non-relational data storage in the form of blobs and tables. The following links provide more information on Web API, ASP.NET MVC and Window Azure.
- .NET Multi-Tier Application Using Storage Tables, Queues, and Blobs.
- Getting Started with Entity Framework using MVC
- Intro to ASP.NET MVC 4
- Your First ASP.NET Web API
This tutorial and the sample application was written by Rick Anderson (Twitter @RickAndMSFT) with assistance from Tom Dykstra, Tom FitzMacken and Barry Dorrans (Twitter @blowdart).
Please leave feedback on what you liked or what you would like to see improved, not only about the tutorial itself but also about the products that it demonstrates. Your feedback will help us prioritize improvements. We are especially interested in finding out how much interest there is in more automation for the process of configuring and deploying the membership database.