Real-World ASP.NET MVC: Building the NuGet.org Website - Professional ASP.NET MVC 5 (2014)

Professional ASP.NET MVC 5 (2014)

Chapter 17
Real-World ASP.NET MVC: Building the NuGet.org Website

—by Phil Haack and Jon Galloway

What's In This Chapter?

· Source code for the NuGet gallery

· Working with WebActivator

· How to use ASP.NET Dynamic Data

· Using the Error Logging Module and Handler

· Profiling basics

· Accessing data with Code First

· Code First migrations

· Octopus Deploy

· Fluent Automation

· Some helpful NuGet packages

To learn a framework such as ASP.NET MVC, read a book. To learn to use the framework to build a real-world application, read some code. Code from a real-world implementation is a great resource to learn how to make use of the knowledge you learned from books.

The term real-world refers to an application that is actively in use and meets a business need—something you can visit now with your browser. In the heat of battle, with deadlines and changing requirements, a real-world application often looks quite a bit different from the contrived applications you see in books.

This chapter reviews a real-world application, warts and all, built with ASP.NET MVC. In fact, if you read Chapter 10, you are probably already familiar with the application. It is the NuGet Gallery. You can visit it at http://nuget.org/ to get a feeling for the public-facing feature set. Members of the ASP.NET and ASP.NET MVC team continue to be actively involved in its development.

This site is under very active use and development, so this chapter is a snapshot at a point in time. It's a look back at some of the things that have worked best since 2010. Keep in mind that some things will continue to change on the live site and codebase, but the lessons learned are what's important.

MAY THE SOURCE BE WITH YOU

The source code for the NuGet Gallery, the same code that runs http://nuget.org/, is hosted on GitHub at https://github.com/nuget/nugetgallery/. To obtain the source code on your machine, read the instructions in the README on that page.

These instructions are geared toward those who have some basic knowledge of Git and plan to contribute to the NuGet Gallery project. If you simply want to see the source code without futzing around with Git, you can also download a zip file:https://github.com/NuGet/NuGetGallery/archive/master.zip.

After you have the source code on your machine, follow the steps in the README (visible online at https://github.com/NuGet/NuGetGallery/) to get started. After verifying prerequisites, the README has you run the build script .\build to verify that your development environment is set up correctly. The script builds the solution and runs all the unit tests. If it succeeds, you're good to go.

Note

The build script assumes that the msbuild.exe is in your path. If it's not, you can either run the build script from a Visual Studio command prompt, or execute the following commands in a command prompt window:

@if exist "%ProgramFiles%\MSBuild\12.0\bin" set

PATH=%ProgramFiles%\MSBuild\12.0\bin;%PATH%

@if exist "%ProgramFiles(x86)%\MSBuild\12.0\bin" set

PATH=%ProgramFiles(x86)%\MSBuild\12.0\bin;%PATH%

Before opening the solution in Visual Studio, make sure you follow the steps to set up the local development website correctly. To simplify testing, the local development instance uses the free localtest.me DNS service. This service includes a wildcard loopback mapping, so all subdomains of localtest.me map to 127.0.0.1 (commonly known as localhost). The development configuration steps for the NuGet Gallery include executing a script (.\tools\Enable-LocalTestMe.ps1) which creates a self-signed SSL certificate fornuget.localtest.me and maps it to your local development instance of the NuGet Gallery code. You can read more about the localtest.me service at http://readme.localtest.me.

When you open the solution in Visual Studio, you'll notice that there are four function areas: Backend, Frontend, Operations, and Core (in the root of the application). These four areas are comprised of a total of seven projects, as shown in Figure 17.1.

Note

The two Facts projects contain all the unit tests for the project.

The unit tests for the NuGet Gallery are written with the XUnit.NET framework—a nice, clean, light, well-designed framework. And I'm not just saying that because a co-author of XUnit.NET, Brad Wilson, is also a co-author of this book, and a former developer on the ASP.NET MVC team. Brad keeps busy.

In XUnit.NET, tests are called “facts” and are denoted by the FactAttribute. This is why the unit test project is named Facts.

image

Figure 17.1

The evolution of the solution structure is very interesting and instructive. In the previous version of this book, there were only two projects: Facts and Website, as shown in Figure 17.2.

image

Figure 17.2

We explained why the solution contained only two projects:

Many ASP.NET MVC applications prematurely split the solution into multiple different class libraries. One reason this happens is a holdover from the very first version of ASP.NET, where a website could not be referenced from a unit test project. People typically created a class library containing all the core logic and referenced that one from the unit test.

This ignores the fact that an ASP.NET MVC project is a class library! It's possible to reference the project from a unit test project just as the Facts project does.

But what about the other reason to separate a solution into multiple projects, separation of concerns? Splitting a solution into multiple projects before the need arises doesn't magically separate concerns. Concerns are separated by paying attention to class responsibilities, not by simply splitting code into more assemblies.

The NuGet team figured that most of the code for the project would be specific to this project and not generally reusable. In cases where we did write code that was more broadly reusable, we placed that code into its own NuGet package and installed the package into this project. The WebBackgrounder library and package is one great example of this.

And yet, now there are four functional areas with seven projects. Was the previous recommendation wrong? Not at all!

First of all, note that the reasons the developers didn't break things apart before are still valid:

· There was no necessity to create separate projects in order to unit test the application code.

· There was no necessity to create separate projects to achieve separation of concerns.

· If you have truly reusable code, instead of just breaking it into another project, why not spin off a separate NuGet package?

Second, note that the team didn't want to break things apart until the need arose; when the need was there, they split things apart based on the requirements of the application. In this case, they had determined that to support the tremendous growth in NuGet Gallery usage, it was time to split the application apart into separate services. Had they broken things apart earlier, it's likely that they would have guessed wrong.

Expand the Website project and you'll see a lot of folders, as shown in Figure 17.3. Each folder represents either a distinct set of functionalities or a type of functionality. For example, the Migrations folder contains all the database migrations (covered later in this chapter).

image

Figure 17.3

These folders contain a lot of functionality, and that doesn't even include all the third-party libraries the project uses. To get a sense of all the various technologies in use, open the packages.config file in the root of the Website project. At the time I write this, 65 NuGet packages are installed, roughly double the amount of packages you'll see in a File New MVC application. That isn't an accurate number of separate products in use because some products are split into multiple NuGet packages, but it gives an indication of how extensively third-party libraries are used. Covering all these products and packages would require an entire book, so I cover just a few notable ones that real-world application issues typically deal with.

WEBACTIVATOR

Many third-party libraries require more than a simple assembly reference to be useful. They sometimes need the application to run a bit of configuration code when the application starts up. In the past, this meant you would need to copy and paste a bit of startup code into the Application_Start method of Global.asax.

WebActivator is a NuGet package that solves the aforementioned issue when combined with NuGet's ability to include source code files in packages along with referenced assemblies. WebActivator makes including a bit of application startup code easy for a NuGet package.

For more details on what WebActivator is, I recommend David Ebbo's blog post at http://blogs.msdn.com/b/davidebb/archive/2010/10/11/light-up-your-nupacks-with-startup-code-and-webactivator.aspx.

The NuGet Gallery Website project includes an App_Start folder, which is the conventional location to place startup code that depends on WebActivator. Listing 17.1 is an example code file that demonstrates how to use WebActivator to run startup and shutdown code.

Listing 17.1: WebActivator Template

[assembly: WebActivator.PreApplicationStartMethod(

typeof(SomeNamespace.AppActivator), "PreStart")]

[assembly: WebActivator.PostApplicationStartMethod(

typeof(SomeNamespace.AppActivator), "PostStart")]

[assembly: WebActivator.ApplicationShutdownMethodAttribute(

typeof(SomeNamespace.AppActivator), "Stop")]

namespace SomeNamespace

{

public static class AppActivator

{

public static void PreStart()

{

// Code that runs before Application_Start.

}

public static void PostStart()

{

// Code that runs after Application_Start.

}

public static void Stop()

{

// Code that runs when the application is shutting down.

}

}

}

The AppActivator.cs within the Website project file contains startup code that configures many of the services that the NuGet Gallery relies on, such as profiling, migrations, background tasks, and the search indexer (Lucene.NET). It's a great example of how to use WebActivator to configure startup services in code.

ASP.NET DYNAMIC DATA

ASP.NET Dynamic Data is a feature that's often been ignored by ASP.NET MVC developers because it's a Web Forms feature. True, it is built on top of Web Forms, but that's really just an implementation detail. ASP.NET MVC and Web Forms are all ASP.NET applications and can be intermingled in productive ways.

For the NuGet Gallery, we decided to use Dynamic Data as an extremely fast way to build out a scaffolded administration UI so that we could edit data in the database via a browser. Eventually, we hope to build out a proper administration section to manage the Gallery, but Dynamic Data works great in a pinch. Because this is an admin page, the details of the UI weren't important to us, though Dynamic Data is certainly customizable if we wanted to build a fancier UI.

To view the admin pages in the site, you need an administrator account. Follow these steps:

1. Ensure the Website project is set as the startup project and press Ctrl+F5 to start it in the browser.

2. Register as a user by clicking the Register Sign In link in the header.

3. Add your user account to the Admins role. To do this, you'll need to add a link to the UserRoles table. You can do this manually (right-click the UserRoles table in Server Explorer, select Show Table Data, and add a row with 1 in each column), or by running the following script against the NuGet Gallery database:

insert into UserRoles(UserKey, RoleKey) values (1,1)

4. Now you can visit the Admin area of the site by appending /Admin to the URL. You'll see the admin dashboard, as shown in Figure 17.4.image

Figure 17.4

5. Click the Database Administration link. You should see a list of every table in the database, as shown in Figure 17.5. Technically, not every table is listed, just those that correspond to an Entity Framework (EF) entity.image

Figure 17.5

6. Clicking the Roles link shows the contents of the Roles table, which should currently hold one role (Admins) with one user (you), as shown in Figure 17.6.image

Figure 17.6

Warning

Dynamic Data isn't easy to set up on EF6 and MVC5. Adding Dynamic Data to an existing ASP.NET MVC application takes a bit of work, especially with EF6, so it's beyond the scope of this book. Using a sample Dynamic Data application and the NuGet Gallery code as a guide, you can get it to work, however. Of course, a simpler alternative is to create a parallel Dynamic Data site (using the new Microsoft.AspNet.DynamicData.EFProvider package for EF6 support) and point it at the same database.

EXCEPTION LOGGING

For new web applications, ELMAH, which stands for Error Logging Module and Handler, is the first package I recommend developers install. When NuGet was first released, every NuGet talk I gave (and nearly every other presentation about NuGet) had a demonstration that installed the ELMAH package. ELMAH logs all unhandled exceptions in your application and saves them. It also provides a UI to list the errors in the log and display them in a nice format, maintaining the details you would see in the dreaded Yellow Screen of Death.

To keep things simple, most demos of ELMAH show installing the main elmah package, which contains a bit of configuration to make ELMAH work using an in-memory database and depends on the elmah.corelibrary package.

Installing the main elmah package works great for a demo, but it doesn't work for a real site because the exception log is stored in memory, which doesn't persist if the application is restarted. Fortunately, ELMAH includes packages for most of the major database vendors as well as one that stores items in XML files.

The NuGet Gallery application logs to SQL Server when running in a development environment, using the elmah.sqlserver package. This package requires a bit of manual configuration. When you install this package into your own project, it adds a script namedElmah.SqlServer.sql in the App_Readme folder of the target project. You'll need to run that script against your SQL Server database to create the tables and stored procedures that ELMAH needs.

In the case of NuGet Gallery, we've long since deleted the App_Readme folder, so you'll find the script in the packages\elmah.sqlserver.1.2\content\App_Readme directory relative to the solution root.

In production, ELMAH logs to Azure Table Storage instead of SQL Server. The code to implement Azure Table Storage logging is in the NuGetGallery.Infrastructure.TableErrorLog class.

By default, ELMAH is only accessible from the local host. This is an important security precaution because anyone who has access to your ELMAH logs can effectively hijack the session for any of your users. See the following blog post for details:www.troyhunt.com/2012/01/aspnet-session-hijacking-with-google.html.

Accessing the exception log remotely is probably one of the reasons you wanted ELMAH in the first place! Not to worry—it just requires a simple bit of configuration. First, secure access to elmah.axd to the users or roles that should have access.

The web.config for NuGet Gallery has an example of this. We restricted access to users who are members of the Admins role.

<location path="elmah.axd">

<system.web>

<httpHandlers>

<add verb="POST,GET,HEAD" path="elmah.axd"

type="Elmah.ErrorLogPageFactory, Elmah" />

</httpHandlers>

<authorization>

<allow roles="Admins" />

<deny users="*" />

</authorization>

</system.web>

<system.webServer>

<handlers>

<add name="Elmah" path="elmah.axd" verb="POST,GET,HEAD"

type="Elmah.ErrorLogPageFactory, Elmah" preCondition="integratedMode" />

</handlers>

</system.webServer>

</location>

Second, after you've properly secured access to elmah.axd, change the security element's allowRemoteAccess attribute to true to enable remote access.

<security allowRemoteAccess="true">

Now you can visit /elmah.axd in your site to see logged unhandled exceptions. If you still can't access elmah.axd, make sure you added your user to the Admins role as previously explained.

You can change the location by modifying the handler path in web.config. For the NuGet Gallery, errors are shown in /Admin/Errors.axd. Browsing to that link (or clicking the Error Logs link in the Admin section) shows the log view, as shown in Figure 17.7.

image

Figure 17.7

PROFILING

NuGet Gallery uses Glimpse (http://getglimpse.com) for profiling. After it's installed and properly configured, Glimpse adds a small overlay at the bottom of every page on your site when you're running in localhost or logged in as an Admin. An example is shown inFigure 17.8.

image

Figure 17.8

The Glimpse heads-up display shows performance information in a concise format. Hovering over the sections (HTTP, Host, and Ajax) expands them to show more detail. For example, hovering over the Host tab causes it to expand and show more information about the server-side operations, as shown in Figure 17.9.

image

Figure 17.9

But that's just the heads-up display. To really see the full power of Glimpse, click the “g” icon in the lower right corner of the screen (see Figure 17.10).

image

Figure 17.10

This causes the Glimpse panel to expand and show much more detailed information about the request. Clicking the Timeline tab shows detailed timing information for each step on the request (see Figure 17.11).

image

Figure 17.11

The details on the Timeline tab might remind you of the timing information you're used to seeing in browser dev tools, but keep in mind that this tab includes server-side information. Having this kind of detailed performance information available for every page request against your production environment is quite powerful (remember, only for Admin users).

Code that uses Entity Framework, an ORM, can make it difficult to know exactly what SQL is generated and run against the database. The SQL tab exposes that information, as shown in Figure 17.12.

image

Figure 17.12

The Routes tab can be especially useful for MVC applications. It shows the entire route table, whether each route matches, and route values.

The Glimpse team put a lot of effort into making Glimpse incredibly easy to install and use. For an MVC 5 application using EF6, just install the Glimpse.MVC5 and Glimpse.EF6 packages.

After installing Glimpse in your project, it becomes available in localhost, but not in production until it's explicitly enabled. The Glimpse website is outstanding, so for more information on enabling Glimpse for remote use (it's secure by default) and further configuring it, I refer you to the Glimpse site: http://getglimpse.com/Docs/#download.

Although Glimpse is pretty easy to just set up and go, you can also configure how it works in explicit detail. For more on how the NuGet Gallery configured Glimpse, see the NuGetGallery.Diagnostics.GlimpseRuntimePolicy class.

DATA ACCESS

The NuGet Gallery uses the “Code First” approach with Entity Framework 5 running against a SQL Azure database. When you run the code locally, it runs against a LocalDB instance.

Code First is heavily convention-based and requires very little configuration by default. Of course, developers tend to be an opinionated lot with strong personal preferences and need to customize everything they touch, and the NuGet team is no different. We replaced a few conventions with our own configuration.

The EntitiesContext class contains our custom configuration for Entity Framework Code First. For example, the following snippet configures the property named Key as the primary key for the User type. If the property name had been Id, or if the KeyAttribute were applied to the property, this line would not be necessary.

modelBuilder.Entity<User>().HasKey(u => u.Key);

One exception to this convention is the WorkItem class, because that class comes from another library.

All the Code First entity classes are located in the Entities folder. Each entity implements a custom IEntity interface. The interface has a single property, Key.

The NuGet Gallery doesn't access the database directly from a DbContext derived class. Instead, all data is accessed via an IEntityRepository<T> interface.

public interface IEntityRepository<T> where T : class, IEntity, new()

{

void CommitChanges();

void DeleteOnCommit(T entity);

T Get(int key);

IQueryable<T> GetAll();

int InsertOnCommit(T entity);

}

This abstraction made writing unit tests for our services much easier. For example, one of the constructor parameters for the UserService class is IEntityRepository<User>. In our unit tests, we can simply pass in a mock or fake implementation of that interface.

However, in the live application, we pass in a concrete EntityRepository<User>. We accomplish that using dependency injection with Ninject, a dependency injection framework covered later in this chapter. All our Ninject bindings are located in the ContainerBindingsclass.

EF CODE–BASED MIGRATIONS

Sharing schema changes to a database is a big challenge when working on an application. In the past, people would write SQL change scripts, check them into the code, and then have to tell everyone which scripts they need to run. It also required a lot of bookkeeping to know which of these scripts had to be run against the production database when the next version of the application was deployed.

EF code–based migrations is a code-driven, structured way of making changes to the database and is included in Entity Framework 4.3 and above.

Although I don't cover all the details of migrations here, I do cover some of the ways we make use of migrations. Expand the Migrations folder to see the list of migrations included in the NuGet Gallery, as shown in Figure 17.13. The migrations are named with a timestamp prefix to ensure they run in order.

image

Figure 17.13

The one named 201110060711357_Initial.cs is the starting point. This file creates the initial set of tables. After that, each migration applies schema changes as we develop the site and make changes.

You use the NuGet Package Manager Console to create migrations. For example, suppose I add a property named Age to the User class. I can open up the Package Manager Console and run the following command:

Add-Migration AddAgeToUser

Add-Migration is the command to add a new migration, and AddAgeToUser is the name of the migration. I try to pick something descriptive so that I remember what the migration does. It generated a file named 201404292258426_AddAgeToUser.cs, with the migration code shown in Listing 17.2.

Listing 17.2: 201404292258426_AddAgeToUser.cs Migration

namespace NuGetGallery.Migrations

{

using System.Data.Entity.Migrations;

public partial class AddAgeToUser : DbMigration

{

public override void Up()

{

AddColumn("Users", "Age", c => c.Int(nullable: false));

}

public override void Down()

{

DropColumn("Users", "Age");

}

}

}

Very cool! It was able to detect changes to my entities and create the appropriate migration for me. Now I'm free to edit that migration if I need to customize it, but for the most part, I didn't have to keep track of every little change as I developed. Of course, there are changes that it can't automatically create a migration for. If you have a property Name and decide to split it into two properties, FirstName and LastName, you'll need to write some custom migration code for that. But for simple changes, this works wonderfully.

As you develop the code, someone else might add a few migrations to the code. Typically, you'll run the Update-Database command to run all migrations that have not been applied to your local database. Likewise, when you deploy the application, you'll need to run the corresponding migrations against the production site.

Previously, the NuGet Gallery codebase ran migrations automatically every time you ran the site. This was done using a DbMigratorPostStart method in AppActivator.cs. The method has the following two lines that do the magic:

var dbMigrator = new DbMigrator(new MigrationsConfiguration());

dbMigrator.Update();

MigrationsConfiguration is a class that derives from DbMigrationsConfiguration and contains custom configuration for Code First migrations. Override the Seed method to create initial seed data which will be run after migrations are run. Make sure that the method checks for the existence of the data before it tries to create it again. The NuGet Gallery, for example, overrides this method and adds the “Admins” role, if it doesn't already exist.

Over time, the NuGet Gallery team moved from running migrations on application start to a controlled manual process. Migrations are now run using the “galops” (short for gallery operations) console. To see the code that executes the migrations, see theRunMigrationsTask class in the NuGetGallery.Operations project. This task has two options: One applies the migrations, whereas the other generates a SQL migration script to be applied directly to the database.

DEPLOYMENTS WITH OCTOPUS DEPLOY

Octopus is a friendly, convention-based deployment automation system for .NET. If that weren't enough, Octopus Deploy runs on NuGet: It uses NuGet to package your deployments.

The overall workflow is as follows:

1. When code is checked in, the continuous integration (CI) server packages it into NuGet packages. In this case, the CI server is running TeamCity.

2. These NuGet packages are added to a NuGet feed.

3. When the release manager wants to push a build, they tell Octopus to get to work.

4. Octopus assembles the NuGet packages and pushes them to a Windows Service (called a Tentacle) running on the target server.

5. The Tentacle deploys and configures the code.

The NuGet Gallery team uses this code to deploy the three server types (Gallery, Search Service, and Work Service) to three environments (dev, int, and prod). Production deployments are done by deploying to the internal servers, doing a manual check, and then using a virtual IP (VIP) swap to point production traffic at the updated servers.

The simplicity of pushing trusted, repeatable deployments has allowed the team to move from deploying at the end of every two-week project iteration to frequent smaller deployments.

The Octopus dashboard is publicly viewable at https://nuget-octopus.cloudapp.net/, as shown in Figure 17.14.

image

Figure 17.14

AUTOMATED BROWSER TESTING WITH FLUENT AUTOMATION

In addition to the xUnit-based unit test projects included in the main NuGet Gallery solution, the NuGet Gallery source contains a separate suite of functional tests (visible here: https://github.com/NuGet/NuGetGallery/tree/master/tests). These functional tests exercise the actual end user functionality using browser automation.

These functional tests are driven using the Fluent Automation library (available on NuGet, of course). Fluent Automation utilizes the “fluent” code style using method chaining to compose tests that are pretty readable. As an example, the following is a functional test method that checks the site login page:

private void LogonHelper(string page)

{

I.Open(UrlHelper.BaseUrl + page);

I.Expect.Url(x => x.AbsoluteUri.Contains(page));

string registerSignIn = "a:contains('Register / Sign in')";

string signOut = "a:contains('Sign out')";

string expectedUserName = "a:contains('NugetTestAccount')";

I.Click(registerSignIn);

I.Expect.Url(x => x.LocalPath.Contains("LogOn"));

I.Enter(EnvironmentSettings.TestAccountName).

In("#SignIn_UserNameOrEmail");

I.Enter(EnvironmentSettings.TestAccountPassword).

In("#SignIn_Password");

I.Click("#signin-link");

I.Expect.Url(x => x.AbsoluteUri.Contains(page));

I.Expect.Count(0).Of(registerSignIn);

I.Expect.Count(1).Of(signOut);

I.Expect.Count(1).Of(expectedUserName);

I.Click(signOut);

I.Expect.Url(x => x.AbsoluteUri.Contains(page));

I.Expect.Count(1).Of(registerSignIn);

I.Expect.Count(0).Of(signOut);

I.Expect.Count(0).Of(expectedUserName);

}

You can read more about Fluent Automation at http://fluent.stirno.com/.

OTHER USEFUL NUGET PACKAGES

As mentioned earlier, the lessons learned and the tools used to build NuGet Gallery could fill a book. The previous sections covered features needed by nearly every web application, such as an admin section, profiling, error logging, and so on.

In this section I quickly cover a smattering of useful packages used in NuGet Gallery that aren't necessarily needed by most applications, but that are very useful when you do need them. Each section begins with the command to install the package.

WebBackgrounder

Install-Package WebBackgrounder

WebBackgrounder (http://nuget.org/packages/WebBackgrounder) is a package for safely running recurring background tasks in an ASP.NET application. ASP.NET and IIS are free to tear down (that is, stop) your application's AppDomain at any time. ASP.NET provides mechanisms to notify code when this happens. WebBackgrounder takes advantage of this to try to safely run a background timer for running tasks that need to recur.

WebBackgrounder is a very early work in progress, but the NuGet Gallery uses it to regularly update download statistics and update the Lucene.NET index. As you might expect, it's configured in AppActivator via the following two methods:

private static void BackgroundJobsPostStart()

{

var jobs = new IJob[] {

new UpdateStatisticsJob(TimeSpan.FromSeconds(10),

() => new EntitiesContext(), timeout: TimeSpan.FromMinutes(5)),

new WorkItemCleanupJob(TimeSpan.FromDays(1),

() => new EntitiesContext(), timeout: TimeSpan.FromDays(4)),

new LuceneIndexingJob(TimeSpan.FromMinutes(10),

timeout: TimeSpan.FromMinutes(2)),

};

var jobCoordinator = new WebFarmJobCoordinator(new EntityWorkItemRepository

(

() => new EntitiesContext()));

_jobManager = new JobManager(jobs, jobCoordinator);

_jobManager.Fail(e => ErrorLog.GetDefault(null).Log(new Error(e)));

_jobManager.Start();

}

private static void BackgroundJobsStop()

{

_jobManager.Dispose();

}

The first method, BackgroundJobsPostStart, creates an array of the various jobs you want to run. Each job includes an interval for how often they should be run. For example, we update download count statistics every 10 seconds.

The next part sets up a job coordinator. If your application only runs on a single server, you can simply use the SingleServerJobCoordinator. Because NuGet Gallery runs on Windows Azure, it's effectively a Web Farm, which requires the WebFarmJobCoordinator to ensure the same job isn't being run on multiple servers at the same time. This allows WebBackgrounder to automatically spread out the work onto multiple machines. This coordinator requires some central “repository” in order to synchronize work.

We decided to use the database because we only have one database per farm (and it is thus centralized), and then installed the WebBackgrounder.EntityFramework package to hook it up.

Over time, these background processes were moved out of the web application, into a separate Azure Worker. The code is still included with the NuGet Gallery for other deployments.

Lucene.NET

Install-Package Lucene.NET

Lucene.NET (http://nuget.org/packages/Lucene.Net) is an open source port of the Apache Lucene search library. It's the most well-known text search engine for .NET. The NuGet Gallery uses it to power package search.

Because it's a port of a Java library, the API and configuration is a bit clunky for those used to .NET APIs. However, after it's configured, it's very powerful and fast.

Configuring it goes way beyond the scope of this book. The NuGet Gallery wraps the Lucene.NET functionality within the LuceneIndexingService class. This provides one example of how to interface with Lucene. Also take a look at the LuceneIndexingJob, which is a WebBackgrounder job scheduled to run every 10 minutes.

Recently, this per-server Lucene.NET search functionality was replaced by a dedicated search service (still running on Lucene.NET). This dedicated search service can maintain a much larger index and return more accurate results. The local Lucene.NET implementation is still included in the NuGet Gallery code for other installations of the site; if the search service URL isn't defined it automatically falls back to the local instance.

You can read more about the evolution of the NuGet Gallery's search services at http://blog.nuget.org/20140411/new-search-on-the-gallery.html. The new search service is available on GitHub at https://github.com/NuGet/NuGet.Services.Search.

AnglicanGeek.MarkdownMailer

Install-Package AnglicanGeek.MarkdownMailer

AnglicanGeek.MarkdownMailer (http://nuget.org/packages/AnglicanGeek.MarkdownMailer) is a simple library for sending e-mails. What's great about this library is you can define the e-mail body once using Markdown syntax and it generates a multi-part e-mail with views for both text and HTML.

The NuGet Gallery uses this to send all its notification e-mails, such as those for new users and password resets. Look at the MessageService class for examples of how the Gallery uses this library.

Ninject

Install-Package Ninject

Many dependency injection (DI) frameworks exist for .NET. The NuGet Gallery team chose Ninject (http://nuget.org/packages/NuGet) as its DI container because of its clean API and speed.

Ninject is the core library. The Ninject.Mvc3 package configures Ninject for an ASP.NET MVC project. It makes getting started with Ninject quick and simple.

As mentioned earlier, all the NuGet Gallery's Ninject bindings are located in the ContainerBindings class. Here's a sample of two bindings plucked from that class:

Bind<ISearchService>().To<LuceneSearchService>().InRequestScope();

Bind<IFormsAuthenticationService>()

.To<FormsAuthenticationService>()

.InSingletonScope();

The first line registers LuceneSearchService as a concrete instance of ISearchService. This allows us to keep our classes loosely coupled. Throughout the codebase, classes reference only the ISearchService interface. This makes supplying a fake during unit tests easy. At run time, Ninject injects a concrete implementation. The InRequestScope ensures that a new instance is created for each request. This is important if the type requires request data in its constructor.

The second binding does the same thing, but the InSingletonScope ensures that there's only one instance of FormsAuthenticationService for the whole application. If a service holds onto any request state, or requires request state in its constructor, make sure to use request scope and not singleton.

SUMMARY

Get any two developers together and they'll probably have a different opinion on how real-world applications should be built. The NuGet Gallery is no exception. Even the developers who work on the Gallery have different opinions.

The NuGet Gallery is just one example of a real-world application out of the infinite possibilities that such applications could take. It's not intended to be a reference application or an example of “This is the one true way to build an ASP.NET MVC application.”

Its only purpose was to meet the need for a gallery to host NuGet packages. And so far, it's doing that very well, though there are a few issues here and there.

However, I think one aspect of building this Gallery is universally applicable to developers. The NuGet team was able to build the Gallery so quickly and with such high quality because we were able to leverage so many useful and well-written community-built packages. Leveraging existing packages will help you build better software faster, so looking through the NuGet Gallery is worth your time. You can find many great packages beyond the ones used by this code.

If you would like to get your hands dirty working on a real-world ASP.NET MVC application, why don't you consider helping out? It's an open source project and the NuGet team welcomes contributors. Just take a look at our issues list,https://github.com/nuget/nugetgallery/issues, or meet us in our JabbR chat