CodeKicks.com
Focus on Microsoft Technologies - Tutorials, Articles, Code Samples.

Monday, October 19, 2009

Developing ASP.NET MVC Applications in Visual Studio

When you install the ASP.NET MVC Framework, what the installer really does is the following:

  • It registers the MVC Framework’s assembly—System.Web.Mvc.dll—in your Global Assembly Cache (GAC), and also puts a copy in \Program Files\Microsoft ASP.NET\ASP.NET MVC 1.0\Assemblies.

  • It installs various templates under Visual Studio’s \Common7\IDE folder, which is how ASP.NET MVC becomes integrated into Visual Studio. These templates include the following:

    • Project templates for creating new ASP.NET MVC web application projects and test projects (in the ProjectTemplates\CSharp\Web\1033 and Test subfolders).

    • Item templates for creating controllers, views, partial views, and master pages from the Add Item menu (in the ItemTemplates\CSharp\Web\MVC subfolder).

    • T4 code-generating templates for prepopulating controllers and views when you create them through the Add Controller or Add View menus (in the ItemTemplates\CSharp\Web\MVC\CodeTemplates subfolder).

  • It adds a few script files for registering the .mvc file name extension with IIS, in case you want to use that (in the \Program Files\Microsoft ASP.NET\ASP.NET MVC 1.0\Scripts folder). However, you won’t usually need to use these scripts: you won’t normally want .mvc to appear in your URLs, and, even if you do, you can simply register URL extensions graphically using IIS Manager,

If you wanted, you could edit the Visual Studio templates and see your changes reflected in the IDE. However, the only ones that are really designed for you to edit are the T4 code-generating templates, and rather than editing the global ones held centrally by Visual Studio, it makes more sense to edit project-specific copies that you can store in your source control system. For more details about Visual Studio’s T4 templating engine, and how to use it in an ASP.NET MVC project, see http://tinyurl.com/T4mvc.

The Default MVC Project Structure

When you use Visual Studio to create a brand-new ASP.NET MVC web application project, it gives you an initial set of folders and files matching those shown in Figure 7-1. Some of these items have special roles hard-coded into the MVC Framework (and are subject to predetermined naming conventions), while others are merely suggestions for how to structure your project. These roles and rules are described in Table 7-1.

Image from book
Figure 7-1: Solution Explorer immediately after creating a new ASP.NET MVC application Click to collapse

Table 7-1: Files and Folders in the Default ASP.NET MVC Web Application Template
Open table as spreadsheet

Folder or File

Intended Purpose

Special Powers and Responsibilities

/App_Data

If you use a file-based database (e.g., a *.mdf file for SQL Server Express Edition, or a *.mdb file for Microsoft Access), this folder is the natural place to put it. It’s safe to put other private data files (e.g., *.xml) here, too, because IIS won’t serve any files from this folder, but you can still access them in your code. Note that you can’t use file-based SQL databases with the full SQL Server editions (i.e., anything other than Express Edition), so in practice, they’re rarely used.

IIS won’t serve its contents to the public. When you have SQL Server Express Edition installed and reference a connection string containing AttachDbFileName=|DataDirectory| MyDatabase.mdf, the system will automatically create and attach a file-based database at /App_Data/MyDatabase.mdf.

/bin

This contains the compiled .NET assembly for your MVC web application, and any other assemblies it references (just like in a traditional ASP.NET WebForms application).

IIS expects to find your DLLs here. During compilation, Visual Studio copies any referenced DLLs to this folder (except ones from the system-wide Global Assembly Cache (GAC).

IIS won’t serve its contents to the public.

/Content

This is a place to put static, publicly servable files (e.g., *.css and images).

None—it’s just a suggestion. You can delete it if you want, but you’ll need somewhere to put images and CSS files, and this is a good place for them.

/Controllers

This holds your controller classes (i.e., classes derived from Controller or implementing IController).

None—it’s just a suggestion. It makes no difference whether you put controllers directly into this folder, into a subfolder of it, or anywhere else in the whole project, because they’re all compiled into the same assembly. You can also put controller classes into other referenced projects or assemblies. You can delete this folder’s initial contents (HomeController and AccountController)—they simply demonstrate how you might get started.

/Models

This is a place to put classes representing your domain model. However, in all but the most trivial of applications, it’s better to put your domain model into a totally separate C# class library project instead. You can then either delete /Models or just use it not for full-fledged domain models but for simple presentation models that exist only to transfer data from controllers to views.

None. Feel free to delete it.

/Scripts

This is another place for statically, publicly servable files, but this one is of course intended for JavaScript code files (*.js). The Microsoft*.js files are required to support ASP.NET MVC’s Ajax.* helpers, and the jquery*.js files are of course needed if you want to use jQuery.

None—you can delete this folder, but if you want to use the Ajax.* helpers, you would then need to reference the Microsoft*.js files at some other location.

/Views

This holds views (usually *.aspx files) and partial views (usually *.ascx files).

By convention, views for the controller class XyzController are found inside /Views/Xyz/. The default view for XyzController’s DoSomething() action method should be placed at /Views/Xyz/DoSomething.aspx (or /Views/Xyz/DoSomething.ascx, if it represents a control rather than an entire page). If you’re not using the initially provided HomeController or AccountController, you can delete the corresponding views.

/Views/Shared

This holds view templates that aren’t associated with a specific controller—for example, master pages (*.Master) and any shared views or partial views.

If the framework can’t find /Views/Xyz/DoSomething.aspx (or .ascx), the next place it will look is /Views/Shared/DoSomething.aspx.

/Views/Web.config

This is not your application’s main web.config file. It just contains a directive instructing the web server not to serve any *.aspx files under /Views (because they should be rendered by a controller, not invoked directly like classic WebForms *.aspx files). This file also contains configuration needed to make the standard ASP.NET ASPX page compiler work properly with ASP.NET MVC view template syntax.

Ensures that your application can compile and run correctly (as described in the previous column).

/Default.aspx

This file isn’t really relevant for an ASP.NET MVC application, but is required for compatibility with IIS 6, which needs to find a “default page” for your site. When Default.aspx executes, it simply transfers control to the routing system.

Don’t delete this; otherwise, your application won’t work in IIS 6 (though it would be fine in IIS 7 in Integrated Pipeline mode).

/Global.asax

This defines the global ASP.NET application object. Its code-behind class (/Global.asax.cs) is the place to register your routing configuration, as well as set up any code to run on application initialization or shutdown, or when unhandled exceptions occur. It works exactly like a classic ASP.NET WebForms Global.asax file.

ASP.NET expects to find a file with this name, but won’t serve it to the public.

/Web.config

This defines your application configuration. You’ll hear more about this important file later in the chapter.

ASP.NET (and IIS 7) expects to find a file with this name, but won’t serve it to the public.

Note

You deploy an MVC application by copying much of this folder structure to your web server. For security reasons, IIS won’t serve files whose full paths contain web.config, bin, App_code, App_GlobalResources, App_LocalResources, App_WebReferences, App_Data, or App_Browsers, because IIS 7’s applicationHost.config file contains <hiddenSegments> nodes hiding them. (IIS 6 won’t serve them either, because it has an ISAPI extension called aspnet_filter.dll that is hard-coded to filter them out.) Similarly, IIS is configured to filter out requests for *.asax, *.ascx, *.sitemap, *.resx, *.mdb, *.mdf, *.ldf, *.csproj, and various others.

Those are the files you get by default when creating a new ASP.NET MVC web application, but there are also other folders and files that, if they exist, can have special meanings to the core ASP.NET platform. These are described in Table 7-2.

Table 7-2: Optional Files and Folders That Have Special Meanings
Open table as spreadsheet

Folder or File

Meaning

/App_GlobalResources

/App_LocalResources

Contain resource files used for localizing WebForms pages.

/App_Browsers

Contains .browser XML files that describe how to identify specific web browsers, and what such browsers are capable of (e.g., whether they support JavaScript).

/App_Themes

Contains WebForms “themes” (including .skin files) that influence how WebForms controls are rendered.

These last few are really part of the core ASP.NET platform, and aren’t necessarily so relevant for ASP.NET MVC applications. For more information about these, consult a dedicated ASP.NET platform reference.

Naming Conventions

As you will have noticed by now, ASP.NET MVC prefers convention over configuration.[1.] This means, for example, that you don’t have to configure explicit associations between controllers and their views; you simply follow a certain naming convention and it just works. (To be fair, there’s still a lot of configuration you’ll end up doing in web.config, but that has more to do with IIS and the core ASP.NET platform.) Even though the naming conventions have been mentioned previously, let’s clarify by recapping:

  • Controller classes must have names ending with Controller (e.g., ProductsController). This is hard-coded into DefaultControllerFactory: if you don’t follow the convention, it won’t recognize your class as being a controller, and won’t route any requests to it. Note that if you create your own IControllerFactory you don’t have to follow this convention.

  • View templates (*.aspx, *.ascx), should go into the folder /Views/controllername. Don’t include the trailing string Controller here—views for ProductsController should go into /Views/Products (not/Views/ProductsController).

  • The default view for an action method should be named after the action method. For example, the default view for ProductsController’s List action would go at /Views/Products/List.aspx. Alternatively, you can specify a view name (e.g., by returning View("SomeView")), and then the framework will look for /Views/Product/SomeView.aspx.

  • When the framework can’t find a view called /Views/Products/Xyz.aspx, it will try /Views/Products/Xyz.ascx. If that fails, it tries /Views/Shared/Xyz.aspx and then /Views/Shared/Xyz.ascx. So, you can use /Views/Shared for any views that are shared across multiple controllers.

All of the conventions having to do with view folders and names can be overridden using a custom view engine.

The Initial Application Skeleton

As you can see from Figure 7-1, newborn ASP.NET MVC projects don’t enter the world empty handed. Already built in are controllers called HomeController and AccountController, plus a few associated view templates. Quite a bit of application behavior is already embedded in these files:

  • HomeController can render a Home page and an About page. These pages are generated using a master page and a soothing blue-themed CSS file.

  • AccountController allows visitors to register and log on. This uses Forms Authentication with cookies to keep track of whether each visitor is logged in, and it uses the core ASP.NET membership facility to record the list of registered users. The membership facility will try to create a SQL Server Express file-based database on the fly in your /App_Data folder the first time anyone tries to register or log in. This will fail if you don’t have SQL Server Express installed and running.

  • AccountController also has actions and views that let registered users change their passwords. Again, this uses the ASP.NET membership facility.

The initial application skeleton provides a nice introduction to how ASP.NET MVC applications fit together, and helps people giving demonstrations of the MVC Framework to have something moderately interesting to show as soon as they create a new project.

However, it’s unlikely that you’ll want to keep the default behaviors unless your application really does use the core ASP.NET membership facility to record registered users. You might find that you start most new ASP.NET MVC projects by deleting many of these files.

Debugging MVC Applications and Unit Tests

You can debug an ASP.NET MVC application in exactly the same way you’d debug a traditional ASP.NET WebForms application. Visual Studio 2008’s debugger is essentially the same as its previous incarnations, so if you are already comfortable using it, you can skip over this section.

Launching the Visual Studio Debugger

The easiest way to get a debugger going is simply to press F5 in Visual Studio (or go to Debug Image from book Start Debugging). The first time you do this, you’ll be prompted to enable debugging in the Web.config file, as shown in Figure 7-2.

Image from book
Figure 7-2: Visual Studio’s prompt to enable debugging of WebForms pages

When you select “Modify the Web.config file to enable debugging,” Visual Studio will update the <compilation> node of your Web.config file:

<system.web>
<compilation debug="true">
...
</compilation>
</system.web>


This means that your ASPX and ASCX templates will be compiled with debugging symbols enabled. It doesn’t actually affect your ability to debug controller and action code, but Visual Studio insists on doing it anyway. There’s a separate setting that affects compilation of your .cs files (e.g., controller and action code) in the Visual Studio GUI itself. This is shown in Figure 7-3. Make sure it’s set to Debug (Visual Studio won’t prompt you about it).



Image from book


Figure 7-3: To use the debugger, make sure the project is set to compile in Debug mode.



Note



When deploying to a production web server, you should only deploy code compiled in Release mode. Similarly, you should set <compilation debug="false"> in your production site’s Web.config file, too.



Visual Studio will then launch your application with the debugger connected to its built-in development web server, WebDev.WebServer.exe. All you need to do now is set a breakpoint, as described shortly (in the “Using the Debugger” section).



Attaching the Debugger to IIS


If, instead of using Visual Studio’s built-in web server, you’ve got your application running in IIS on your development PC, you can attach the debugger to IIS. In Visual Studio, press Ctrl+Alt+P (or go to Debug Image from book “Attach to Process”), and find the worker process named w3wp.exe (for IIS 6 or 7) or aspnet_wp.exe (for IIS 5 or 5.1). This screen is shown in Figure 7-4.



Image from book


Figure 7-4: Attaching the Visual Studio debugger to the IIS 6/7 worker process



Note



If you can’t find the worker process, perhaps because you’re running IIS 7 or working through a Remote Desktop connection, you’ll need to check the box labeled “Show processes in all sessions.” Also make sure that the worker process is really running by opening your application in a web browser (and then click Refresh back in Visual Studio). On Windows Vista with UAC enabled, you’ll need to run Visual Studio in elevated mode (it will prompt you about this when you click Attach).



Once you’ve selected the IIS process, click Attach.



Attaching the Debugger to a Test Runner (e.g., NUnit GUI)


If you do a lot of unit testing, you’ll find that you run your code through a test runner, such as NUnit GUI, just as much as you run it through a web server. When a test is inexplicably failing (or inexplicably passing), you can attach the debugger to your test runner in exactly the same way that you’d attach it to IIS. Again, make sure your code is compiled in Debug mode, and then use the Attach to Process dialog (Ctrl+Alt+P), finding your test runner in the Available Processes list (see Figure 7-5).



Image from book


Figure 7-5: Attaching the Visual Studio debugger to NUnit GUI



Notice the Type column showing which processes are running managed code (i.e., .NET code). You can use this as a quick way to identify which process is hosting your code.



Remote Debugging


If you have IIS on other PCs or servers in your Windows domain, and have the relevant debugging permissions set up, you can enter a computer name or IP address in the Qualifier box and debug remotely. If you don’t have a Windows domain, you can change the Transport drop-down to Remote, and then debug across the network (having configured Remote Debugging Monitor on the target machine to allow it).



Using the Debugger


Once Visual Studio’s debugger is attached to a process, you’ll want to interrupt the application’s execution so you can see what it’s doing. So, mark some line of your source code as a breakpoint by right-clicking a line and choosing Breakpoint Image from book “Insert breakpoint” (or press F9, or click in the gray area to the left of the line). You’ll see a red circle appear. When the attached process reaches that line of code, the debugger will halt execution, as shown in Figure 7-6.



Image from book


Figure 7-6: The debugger hitting a breakpoint



The Visual Studio debugger is a powerful tool: you can read and modify the values in variables (by hovering over them or by using the Watch window), manipulate program flow (by dragging the yellow arrow), or execute arbitrary code (by entering it into the Immediate window). You can also read the call stack, the machine code disassembly, the thread list, and other information (by enabling the relevant item in Debug Image from book Windows). A full guide to the debugger is off-topic for this book; however, consult a dedicated Visual Studio resource for more information.



Stepping into the .NET Framework Source Code


There’s one little-known debugger feature that, in 2008, suddenly became a lot more useful. If your application calls code in a third-party assembly, you wouldn’t normally be able to step into that assembly’s source code during debugging (because you don’t have its source code). However, if the third party chooses to publish the source code through a symbol server, you can configure Visual Studio to fetch that source code on the fly and step into it during debugging.



Since January 2008, Microsoft has enabled a public symbol server containing source code for most of the .NET Framework libraries. This means you can step into the source code for System.Web.dll and various other core assemblies, which is extremely useful when you have an obscure problem and not even Google can help. This contains more information than the disassembly you might get from Reflector—you get the original source code, with comments (see Figure 7-7).



Image from book


Figure 7-7: Stepping into Microsoft’s source code for ASP.NET Forms Authentication



To set this up, make sure you have Visual Studio 2008 SP1 installed, and then follow the instructions at referencesource.microsoft.com/serversetup.aspx.



Note



Microsoft has made the ASP.NET MVC Framework’s source code available to download so that you can compile it (and modify it) yourself. However, it has not released the source code to the rest of the .NET Framework libraries in the same way—you can only get that though Microsoft’s symbol server for the purposes of stepping into it while debugging. You can’t download the whole thing, and you can’t modify or compile it yourself.



Stepping into the ASP.NET MVC Source Code


Since you can download the whole ASP.NET MVC Framework source code package, it’s possible to include the System.Web.Mvc source code project in your solution (as if you created it!). This allows you to use Visual Studio’s Go to Declaration command to directly jump any reference in your own source code to the corresponding point in the framework source code, and of course to step into the framework source code when debugging. It can be a huge timesaver when you’re trying to figure out why your application isn’t behaving as expected.



This isn’t too difficult to set up, as long as you know about a few likely problems and how to solve them. The instructions may well change after this book is printed, so I’ve put the guide on my blog at http://tinyurl.com/debugMvc.



[1.] This tactic (and this phrase) is one of the original famous selling points of Ruby on Rails.

Post a Comment