January 2011

Volume 26 Number 01

Visual Studio - Use Multiple Visual Studio Project Types for Cloud Success

By Patrick Foley | January 2011

As you’ve probably noticed, there are many different project types in Visual Studio these days. Which one do you choose? All have strengths that help solve problems in different situations. Even within a single business problem, there are often multiple use cases that can best be solved by different Visual Studio project types.

I was confronted with a real-world example of such a problem recently while building out the infrastructure for a cloud-based program I lead that’s designed to highlight success stories: Microsoft Solutions Advocates (microsoftsolutionsadvocates.com). I used several different Visual Studio project types to build my solution, and in this article, I’ll walk through a simplified example of my project called “Customer Success Stories,” or CSS.

CSS has three distinct use cases:

  1. Anonymous users read success stories on a public Web site.
  2. Users who belong to the program log in to a private Web site to create and edit their own success stories.
  3. Administrators (like me) log in to an administrative Web site to manage and edit all the data, including minutia such as lookup tables.

The approach I settled on combined three Microsoft .NET Framework technologies:

  1. ASP.NET MVC for the public site
  2. WCF RIA Services for the private, customer-edit site
  3. ASP.NET Dynamic Data for the administrative site

Any of these technologies could’ve been used to create the whole solution, but I preferred to take advantage of the best features of each. ASP.NET MVC is an ideal technology for creating a public Web site that will work everywhere, because it emits standard HTML, for one thing. The public site has a marketing purpose, so I’ll eventually engage a designer to polish the appearance. Working with a designer adds complexity, but ASP.NET MVC has a straightforward view implementation that makes it easy to incorporate a designer’s vision. Making the site read-only and separating it from the other use cases helps isolate the scope of the designer’s involvement.

Although ASP.NET MVC could also be used to implement the customer-editing functionality, WCF RIA Services is an even better fit. (Conversely, WCF RIA Services could be used to build a great-looking public Web site, but Silverlight isn’t supported on some devices, such as iPhones and iPads, and I wanted the greatest reach for the public use case.) Silverlight is here to stay, and it’s perfect for creating a rich editing experience with very little programming, so long as it’s reasonable to expect users to have it or install it, as would be the case with customers collaborating on a success-stories site.

ASP.NET Dynamic Data provides a handy way to build an administrative solution without too much work. The administrative site doesn’t need to be fancy; it simply needs to provide a way to manage all of the data in the solution without having to resort to SQL Server Management Studio. As my solution evolves, the ASP.NET Dynamic Data site could conceivably be subsumed by the WCF RIA Services site. Nevertheless, it’s useful at the beginning of a data-centric development project such as this one, and it costs almost nothing to build.

Targeting Azure

Again, this example is based on a real-world problem, and because the solution requires a public Web site, I’m going to target Azure and SQL Azure. Windows Server and SQL Server might be more familiar, but I need the operational benefits of running in the cloud (no need to maintain the OS, apply patches and so on). I barely have time to build the solution—I certainly don’t have time to operate it, so Azure is a must for me.

To work through this example and try it on Azure, you need an account. There are various options and packages found at microsoft.com/windowsazure/offers. MSDN subscribers and Microsoft partners (including BizSpark startups—visit bizspark.com to learn more) have access to several months of free resources. For prototyping and learning (such as working through this example), you can use the “Introductory Special.” It includes three months of a 1GB SQL Azure database and 25 hours of a Azure small compute instance, which should be enough to familiarize yourself with the platform. I built this example using the Introductory Special without incurring any additional charges.

‘Customer Success Stories’ Overview

This example is presented in the form of a tutorial. Several important aspects of a real-world implementation are out of scope for this article, including user-level security, testing, working with a designer and evolving beyond an extremely simplified model. I’ll attempt to address these in future articles or on my blog at pfoley.com.

The steps are presented at a high level and assume some familiarity with Visual Studio and with the technologies involved. Code for the entire solution can be downloaded from code.msdn.microsoft.com/mag201101VSCloud, and click-by-click instructions for each step can be found at pfoley.com/mm2011jan.

Step 1: Create a Project for the Entity Framework Data Model

The Web technologies used in this example all use the Entity Framework effectively, so I chose to integrate the three use cases by having them all share a common Entity Framework model. When working with an existing database, you have to generate the model from the database. Whenever possible, I prefer to create the model first and generate the database from it, because I like to think about my design more at the model level than the database level. To keep things simple, this example uses just two entities: Company and Story.

The Entity Framework model will be created in its own project and shared across multiple projects (I learned how to do this from Julie Lerman; see pfoley.com/mm2011jan01 for more on that). I call best practices like these “secret handshakes”—figuring it out the first time is a challenge, but once you know the secret, it’s simple:

  1. Create the Entity Framework model in a “class library” project.
  2. Copy the connection string into any projects that share the model.
  3. Add a reference to the Entity Framework project and System.Data.Entity in any projects that share the model.

To start, create a Blank Solution in Visual Studio 2010 named “Customer Success Stories” and add a Class Library project named “CSSModel.” Delete the class file and add an empty ADO.NET Entity Data Model item named “CSSModel.” Add Company and Story entities with an association between them as in Figure 1 (when you right-click on Company to add the association, make sure that “Add foreign key properties to ‘Person’ Entity” is checked on the ensuing dialog—foreign key properties are required in future steps).

image: Adding Company and Story Entities to the Visual Studio Project

Figure 1 Adding Company and Story Entities to the Visual Studio Project

The model is now ready to generate database tables, but a SQL Azure database is needed to put them in. When prototyping is completed and the project is evolving, it’s useful to add a local SQL Server database for testing purposes, but at this point, it’s less complicated to work directly with a SQL Azure database.

From your SQL Azure account portal, create a new database called “CSSDB” and add rules for your current IP address and to “Allow Microsoft Services access to this server” on the Firewall Settings tab. Your SQL Azure account portal should look something like Figure 2.

image: Configuring Settings in the SQL Azure Portal

Figure 2 Configuring Settings in the SQL Azure Portal

In Visual Studio, right-click on the design surface and select “Generate Database from Model.” Add a connection to your new SQL Azure database and complete the wizard, which generates some Data Definition Language (DDL) and opens it in a .sql file, as shown in Figure 3.

image: Generating the Database Model

Figure 3 Generating the Database Model

Before you can execute the SQL, you must connect to the SQL Azure database (click the Connect button on the Transact-SQL Editor toolbar). The “USE” statement is not supported in SQL Azure, so you must choose your new database from the Database dropdown on the toolbar and then execute the SQL. Now you have a SQL Azure database that you can explore in Visual Studio Server Explorer, SQL Server Management Studio or the new management tool, Microsoft Project Code-Named “Houston” (sqlazurelabs.com/houston.aspx). Once you build the solution, you have an Entity Framework project that you can use to access that database programmatically, as well.

Step 2: Create the ASP.NET Dynamic Data Project

An ASP.NET Dynamic Data Web site provides a simple way to work with all the data in the database and establishes baseline functionality to ensure the environment is working properly—all with one line of code.

Add a new ASP.NET Dynamic Data Entities Web Application project to the solution and call it “CSSAdmin.” To use the data model from the first step, copy the connectionStrings element from App.Config in CSSModel to web.config in CSSAdmin. Set CSSAdmin as the startup project and add references to the CSSModel project and System.Data.Entity.

There are lots of fancy things you can do with ASP.NET Dynamic Data projects, but it’s surprisingly useful to implement the default behavior that comes by simply uncommenting the RegisterContext line in Global.asax.cs and changing it to:

DefaultModel.RegisterContext(typeof(CSSModel.CSSModelContainer), new ContextConfiguration() { ScaffoldAllTables = true });

Build and run the project, and you have a basic site to manage your data. Add some test data to make sure everything’s working.

Step 3: Create the Azure Services Project

The result of the previous step is a local Web site that accesses a database on SQL Azure—the next step is it to get that Web site running on Azure.

From your Azure account portal, create a Storage Service called “CSS Storage” and a Hosted Service called “CSS Service.” Your Azure account portal should look similar to Figure 4.

image: Creating Services in the Azure Portal

Figure 4 Creating Services in the Azure Portal

In Visual Studio, add a new Azure Cloud Service project to your solution called “CSSAdminService” (you must have Azure Tools for Visual Studio installed), but don’t add additional “cloud service solutions” from the wizard. The cloud service project adds the infrastructure necessary to run your application in a local version of the “cloud fabric” for development and debugging. It also makes it easy to publish to Azure interactively. This is great for prototyping and for simpler Azure solutions, but once you get serious about developing on Azure, you’ll probably want to use Windows PowerShell to script deployment, perhaps as part of a continuous integration solution.

Right-click on the Roles folder in CSSAdminService, then select “Add | Web Role Project in solution” to associate the CSSAdmin project with the cloud service project. Now when you compile and run the solution, it runs in the development fabric. At this point, the solution doesn’t look any different than it did running on IIS or Cassini, but it’s important to run on the dev fabric anyway to catch mistakes such as using unsupported Windows APIs as you evolve a Azure solution.

Deploy to your Azure account by right-clicking on the CSSAdminService project and selecting Publish. The first time you do this, you’ll need to add credentials (follow the instructions to copy a certificate to your Azure account). Then select a “Hosted Service Slot” and a “Storage Account” to deploy your solution to. There are two options for the hosted service slot: production and staging. When updating a real-world solution in production, deploy first to staging to make sure everything works and then promote the staging environment into production. While prototyping, I prefer to deploy straight to production because I’m not going to leave the solution running anyway. Click OK to deploy to Azure, which can take several minutes. Once complete, run your Azure application using the Web site URL shown on the service page, which should look similar to Figure 5.

image: An Azure Deployed Service

Figure 5 An Azure Deployed Service

After verifying that the service works, suspend and delete the deployment to avoid charges (consumption-based plans are billed for any time a service package is deployed, whether or not it’s actually running). Don’t delete the service itself, because doing so returns the Web site URL back into the pool of available URLs. Obviously, when you’re ready to flip the switch on a real production solution, you’ll have to budget for running Azure services nonstop.

When a service deployment fails, it doesn’t always tell you exactly what’s wrong. It usually doesn’t even tell you something is wrong. The service status just enters a loop such as “Initializing … Busy … Stopping … Initializing …” When this happens to you—and it will—look for problems such as attempting to access local resources (perhaps a local SQL Server database) or referencing assemblies that don’t exist on Azure. Enabling IntelliTrace when you deploy the package (see Figure 6) can help you pinpoint problems by identifying the specific exceptions that are being thrown.

image: Enabling IntelliTrace While Publishing to Azure

Figure 6 Enabling IntelliTrace While Publishing to Azure

Step 4: Create the ASP.NET MVC Project

The solution so far consists of an administrative Web site (albeit with no user-level security) that runs on Azure and accesses a SQL Azure database, all with one line of code. The next step is to create the public Web site.

Add a new ASP.NET MVC 2 Web Application project to the solution named “CSSPublic” (don’t create a unit test project while working through this example). If you’re already quite experienced with ASP.NET MVC, you might prefer to start with an ASP.NET MVC 2 Empty Web Application, but I prefer to start from a Web site structure that already works and modify it bit by bit to make it do what I want.

Right-click on CSSPublic to make it your startup project, and then run it to see what you’re starting with. The public site for CSS is read-only and anonymous, so remove all login and account functionality with these steps:

  1. Delete the “logindisplay” div from Site.Master.
  2. Delete the ApplicationServices connection string and authentication element from the main Web.config.
  3. Delete AccountController.cs, AccountModels.cs, LogOnUserControl.ascx and the entire Account folder under Views.
  4. Run it again to make sure it still works.
  5. Copy the connection string from the CSSModel App.Config into the CSSPublic Web.config and add references to CSSModel and System.Data.Entity as before.
  6. Select all the references for CSSPublic and set the Copy Local property to true.

I think it makes sense to add separate controllers (with associated views) for Companies and Stories, while keeping the Home controller as a landing page. These are important decisions; a designer can make the site look good, but the information architecture—the site structure—has to be right first.

Naming is relevant in a Model View Controller (MVC) project. Use plural controller names (Companies, not Company) and matching view folders. Use the standard conventions of Index, Details and so on for controller methods and view names. You can tweak these conventions if you really want to, but that adds complexity.

Right-click on the Controllers folder to add a new controller named “CompaniesController.” This site won’t implement any behavior—it’s read-only—so there’s no need for an explicit model class. Treat the Entity Framework model container itself as the model. In CompaniesController.cs, add “using CSSModel” and change the Index method to return a list of companies as follows:

CSSModelContainer db = new CSSModelContainer();
return View(db.Companies.ToList());

To create the view, create an empty Companies folder under Views and right-click on it to add a view called “Index.” Make it strongly typed with a View data class of CSSModel.Company and View content of List.

In Site.Master, add a list item in the menu to reference the new Controller:

<li><%: Html.ActionLink("Companies", "Index", "Companies")%></li>

Run the app and click the menu to see the list of Companies. The default view is a good starting point, but remove the unnecessary “Id” field. Because this site is intended to be read-only, delete the ActionLink entries for “Edit,” “Delete” and “Create.” Finally, make the company name itself a link to the Details view:

<%: Html.ActionLink(item.Name, "Details", new { id=item.Id })%>

Your Companies list should now look similar to what is shown in Figure 7.

image: A List of Companies in ASP.NET MVC Web Site

Figure 7 A List of Companies in ASP.NET MVC Web Site

To implement Details, add a method to CompaniesController:

public ActionResult Details(int id)
{
  CSSModelContainer db = new CSSModelContainer();
  return View(db.Companies.Single(c => c.Id.Equals(id)));
}

The id parameter represents the integer following Companies\Details\ in the URL. That integer is used to find the appropriate company using a simple LINQ expression.

Add the Details view underneath the Companies folder as before, but this time select “Details” as the View content and name the view “Details.”

Run the project, navigate to Companies, and then click one of the company names to see the default Details view.

Adding a controller and views for Stories is similar. The views still require a fair amount of tweaking before being ready for a designer, but this is a good start, and it’s easy to evolve.

To verify this project will work on Azure, create a cloud service project called “CSSPublicService” and add the CSSPublic role to it. Run the service locally in the dev fabric and then publish the site to Azure and run it from the public URL. Don’t forget to suspend and delete the deployment when you’re done to avoid being billed.

Step 5: Create the WCF RIA Services Project

The solution at this point contains ASP.NET MVC and ASP.NET Dynamic Data Web sites running (or at least runnable) on Azure, using a shared Entity Framework model to access a SQL Azure database. Very little manual plumbing code has been required to obtain a decent amount of functionality. Adding a WCF RIA Services Web site adds another dimension: a rich editing experience.

Add a Silverlight Business Application project named “CSSCustomerEdit” (no spaces) and Visual Studio adds two projects to your solution: a Silverlight client (CSSCustomerEdit) and a Web service (CSSCustomerEdit.Web). Run the solution to see what you’re starting with. Open ApplicationStrings.resx in CSSCustomerEdit project and change the value for ApplicationName to “Customer Success Stories” to make it look nice.

In CSSCustomerEdit.Web, copy connectionStrings from CSSModel into Web.config, add references to CSSModel and System.Data.Entity and set Copy Local to true for all the references. Then right-click on the Services folder and add a new Domain Service Class item called “CSSDomainService.” Make sure the name of this class ends in Service—without a number—to gain the full benefit of the tooling between the two projects (another “secret handshake”). Click OK to bring up the Add New Domain Service Class dialog and check all the entities along with Enable editing for each (Figure 8).

image: Adding a Domain Service Class

Figure 8 Adding a Domain Service Class

Notice that “Generate associated classes for metadata” is grayed out. This illustrates a tradeoff with the approach I’m espousing here. In a Silverlight Business Application, metadata classes can be used to add additional validation logic such as ranges and display defaults. However, when the Entity Framework model is in a separate project from CSSCustomerEdit.Web, the toolkit doesn’t let you add these metadata classes. If this feature is important to you or if you know you’re going to invest most of your energy in the Silverlight Business Application part of your solution, you might want to create your Entity Framework model directly in the “.Web” project instead of a separate project. You could still reference CSSCustomerEdit.Web to share the Entity Framework model in another project.

As mentioned, authentication and authorization are out of scope for this article, but it’s possible to punt and still be precise. In the CSSDomainService class, add a placeholder property named “myCompany” to represent the company the user is authorized to edit. For now, hardcode it to 1, but eventually the login process will set it to the right company for the authenticated user.

Edit the CSSDomainService class to reflect the specific use case for the project: the user can update companies but not insert or delete them (an administrator does that in the ASP.NET Dynamic Data Web site), so remove those service methods. Also, the user can only edit the single company they work for, not a list of companies, so change GetCompanies to GetMyCompany. Similarly, change GetStories to GetMyStories and ensure that the user creates stories whose CompanyId is equal to myCompany:

private int myCompany = 1; // TODO: set myCompany during authentication
public Company GetMyCompany()
{
  return this.ObjectContext.Companies.Single(c=>c.Id.Equals(myCompany));
}
...
public IQueryable<Story> GetMyStories()
{
  return this.ObjectContext.Stories.Where(s=>s.CompanyId.Equals(myCompany));
}
public void InsertStory(Story story)
{
  story.CompanyId = myCompany;
  story.Id = -1; // database will replace with next auto-increment value
  ...
}

WCF RIA Services shines in the creation of editable, field-oriented interfaces, but it’s important to start simply and add functionality slowly. The DataGrid and DataForm controls are powerful, but whenever I work too fast or try to add too much functionality at once, I end up messing up and having to backtrack. It’s better to work incrementally and add one UI improvement at a time.

To implement a baseline UI for this example, add references to System.Windows.Controls.Data and System.Windows.Controls.DomainServices in CSSCustomerEdit. Create new views (Silverlight Page items) for Company (singular) and Stories, then mimic the XAML from the existing Home and About views. Edit MainPage.xaml to add new dividers and link buttons (alternatively, just co-opt the existing Home and About views to use for Company and Stories).

In Silverlight development, most of the magic involves editing XAML. In CSSCustomerEdit, add namespace entries, a DomainDataSource and a DataForm for the Company view. In addition, add a DataGrid for the Stories view. In both DataForms, handle the EditEnded event to call MyData.SubmitChanges.Stories.xaml, which should look similar to Figure 9.

image: XAML for the Stories View

Figure 9 XAML for the Stories View

Build it … run it … it works! A rich editing experience that’s ready to evolve (see Figure 10).

image: The Stories View in Action

Figure 10 The Stories View in Action

As before, create a new cloud service project, publish it and test it on Azure. Copy CSSCustomerEditTestPage.aspx to Default.aspx for a cleaner experience, and you’re done.

No ‘One True Way’

Visual Studio and the .NET Framework provide myriad choices for creating solutions that can run on Azure. While it’s tempting to search for the “one true way” to create the next killer app for the cloud, it’s more rewarding to leverage capabilities from multiple technologies to solve complex problems. It’s easier to code, easier to evolve and—thanks to Azure—easier to operate.


Patrick Foley is an ISV architect evangelist for Microsoft, which means he helps software companies succeed in building on the Microsoft platform. Read his blog at pfoley.com.

Thanks to the following technical expert for reviewing this article: Hanu Kommalapati