Sei sulla pagina 1di 29

10 Good Practices for ASP.

NET MVC Apps

1 of 29

http://www.codemag.com/article/1405071

By Leonardo Esposito

Leonardo Esposito
Dino Esposito is the author of
Programming ASP.NET MVC for
Microsoft Press as well as
Programming ASP.NET 4 and
other bestselling books such as
Microsoft .NET: Architecting
Applications for the Enterprise.

03/01/2016 21:56

10 Good Practices for ASP.NET MVC Apps

2 of 29

http://www.codemag.com/article/1405071

DevProConnections

Magazine,

Dino is a frequent speaker at


industry events all over the world
including Microsoft TechED and
DevConnections. After a decade
of Web development, Dino
jumped
bandwagon

on

the
and

is

mobile
actively

developing for iOs, Android and


WP7.

This article was published


in:

This article was filed under:


ASP.NET ASP.NET MVC
Design Patterns
Development Process
Web Development (general)

When you open up Visual Studio 2013 with the intent of building a new ASP.NET MVC 5
project, you find only one option: an ASP.NET Web Application. This is great, as it
represents a moment of clarity in a whirlpool of similar-looking and confusing options.
So you click and are presented with various options as to the type of project to create.
You want ASP.NET MVC, right? So you pick up the MVC option. What you obtain is a
no-op demo application that was probably meant to give you an idea of what it means
to code for ASP.NET MVC. Even though the result does nothing, the resulting project is

03/01/2016 21:56

10 Good Practices for ASP.NET MVC Apps

3 of 29

http://www.codemag.com/article/1405071

Youll also find several Nuget packages and assemblies referenced that are not required
by the sample application, yet are already there to save time for when you need them in
action. This is not a bad idea in theory, as nearly any ASP.NET website ends up using
jQuery, Bootstrap, Modernizr, Web Optimization, and others. And if you dont like it, you
still have the option of starting with an empty project and adding MVC scaffolding. This
is better, as it delivers a more nimble project even though there are many references
that are useless at first. The truth is that any expert developer has his own favorite initial
layout of the startup project, including must-have packages and scripts.
Although I may be tempted, I dont want to push my own ideal project layout on you.
My purpose, instead, is applying the Occams Razor to the ASP.NET MVC project
templates that you get in Visual Studio 2013. Ill start with the organization of project
folders and proceed through startup code, bundling, HTML layout, controllers, layers,
HTTP endpoints, and multi-device views. Overall, here are ten good practices for sane
ASP.NET MVC 5 development.

#1: Project Folders and Namespaces


Lets say you used the Visual Studio 2013 project template to create a new project. It
works, but its rather bloated. Figure 1 shows the list of unnecessary references detected
by ReSharper.

03/01/2016 21:56

10 Good Practices for ASP.NET MVC Apps

4 of 29

http://www.codemag.com/article/1405071

Figure 1 : Unnecessary references in the ASP.NET MVC project built with the default
Visual Studio 2013 template
Its even more interesting to look at the remaining references. Figure 2 shows what you
really need to have referenced in order to run a nearly dummy ASP.NET MVC
application.

03/01/2016 21:56

10 Good Practices for ASP.NET MVC Apps

5 of 29

http://www.codemag.com/article/1405071

Figure 2 : Strictly required assemblies in a basic ASP.NET MVC 5 project


Heres the minimal collection of Nuget packages you need in ASP.NET MVC.
<packages>
<package id="Microsoft.AspNet.Mvc"
version="5.0.0"
targetFramework="net45" />
<package id="Microsoft.AspNet.Razor"
version="3.0.0"
targetFramework="net45" />
<package id="Microsoft.AspNet.WebPages"
version="3.0.0"
targetFramework="net45" />
</packages>

The project contains the folders listed in Table 1.


When you start adding Nuget packages, some other conventions start appearing such
as the Scripts folder for Modernizr and for jQuery and its plugins. You may also find a
Content folder for Bootstrap style sheets and a separate Fonts folder for Bootstraps
glyph icons.
I find such a project structure rather confusing and usually manage to clean it up a little

03/01/2016 21:56

10 Good Practices for ASP.NET MVC Apps

6 of 29

http://www.codemag.com/article/1405071

either but Ill return to that in a moment.) I sometimes rename Models to ViewModels
and give it a structure similar to Views: one subfolder per controller. In really complex
sites, I also do something even more sophisticated. The Models folder remains as is,
except that two subfolders are addedLInput and View, as shown in Figure 3.

Figure 3 : Content and Models folder internal structure


Generally speaking, there are quite a few flavors of models. One is the collection of
classes through which controllers receive data. Populated from the model binding layer,
these classes are used as input parameters of controller methods. I collectively call them
the input model and define them in the Input subfolder. Similarly, classes used to carry
data into the Razor views collectively form the view model and are placed under the
Models/View folder. Both input and view models are then split on a per-controller basis.
One more thing to note is the matching between project folders and namespaces. In
ASP.NET its a choice rather than an enforced rule. So you can freely decide to ignore it
and still be happy, as I did for years. At some pointbut it was several years agoI
realized that maintaining the same structure between namespaces and physical folders
was making a lot of things easier. And when I figured out that code assistant tools were
making renaming and moving classes as easy as click-and-confirm, well, I turned it into
enforcement for any of my successive projects.

03/01/2016 21:56

10 Good Practices for ASP.NET MVC Apps

7 of 29

http://www.codemag.com/article/1405071

#2 Initial Configuration
A lot of Web applications need some initialization code that runs upon startup. This
code is usually invoked explicitly from the Application_Start event handler. An
interesting convention introduced with ASP.NET MVC 4 is the use of xxxConfig classes.
Heres an example that configures MVC routes:
public class RouteConfig
{
public static void RegisterRoutes(
RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new {
controller = "Home",
action = "Index",
id = UrlParameter.Optional
});
}
}

The code in global_asax looks like this:


RouteConfig.RegisterRoutes(RouteTable.Routes);

For consistency, you can use the same pattern to add your own classes that take care of
application-specific initialization tasks. More often than not, initialization tasks populate
some ASP.NET MVC internal dictionaries, such as the RouteTable.Routes dictionary of
the last snippet (just after the heading for #2).For testability purposes, I highly
recommend that xxxConfig methods are publicly callable methods that get system
collections injected. As an example, heres how you can arrange unit tests on MVC
routes.
[TestMethod]
public void Test_If_Given_Route_Works()
{
// Arrange
var routes = new RouteCollection();

03/01/2016 21:56

10 Good Practices for ASP.NET MVC Apps

8 of 29

http://www.codemag.com/article/1405071

// Act & Assert whether the right route was found


var expectedRoute = "{controller}/{action}/{id}";
routeData = GetRouteDataFor("~/product/id/123",
routes); Assert.AreEqual(((Route) routeData.Route).Url,
expectedRoute);}

Note that the code snippet doesnt include the full details of the code for custom
GetRouteDataFor method. Anyway, the method uses a mocking framework to mock
HttpContextBase and then invokes method GetRouteData on RouteCollection
passing the mocked context.
var routeData = routes.GetRouteData(httpContextMock);

Many developers just dont like the underscore convention in the name of some
ASP.NET folders, particularly the App_Start folder. Is it safe to rename this folder to
something like Config? The answer is: its generally safe but it actually depends on what
you do in the project.
The possible sore point is the use of the WebActivator Nuget package in the project,
either direct or through packages that have dependencies on it. WebActivator is a
package specifically created to let other Nuget packages easily add startup and
shutdown code to a Web application without making any direct changes to global.asax.
WebActivator was created only for the purposes of making Nuget packages seamlessly
extend existing Web applications. As WebActivator relies on an App_Start folder,
renaming it may cause you some headaches if you extensively add/refresh Nuget
packages that depend on WebActivator. Except for this, there are no problems in
renaming App_Start to whatever you like most.

#3 Bundling and Minifying CSS Files


Too many requests from a single HTML page may cause significant delays and affect the
overall time-to-last-byte metrics for a site. Bundling is therefore the process of grouping
distinct resources such as CSS files into a single downloadable resource. In this way,
multiple and logically distinct CSS files can be downloaded through a single HTTP
request.
Minification, on the other hand, is the process that removes all unnecessary characters
from a text-based resource without altering the expected functionality. Minification

03/01/2016 21:56

10 Good Practices for ASP.NET MVC Apps

9 of 29

http://www.codemag.com/article/1405071

been added mostly for readability purposes, including long descriptive member names.
Although bundling and minification can be applied together, they remain independent
processes. On a production site, theres usually no reason not to bundle minified CSS
and script files. The only exception is for large and very common resources that might
be served through a Content Delivery Network (CDN). The jQuery library is a great
example.
Bundling requires the Microsoft ASP.NET Web Optimization Framework available as a
Nuget package. Downloading the Optimization Framework also adds a few more
references to the project. In particular, they are WebGrease and Microsoft Infrastructure.
These, in turn, bring their own dependencies for the final graph, shown in Figure 4.

Figure 4 : Graph of Nuget dependencies for bundling and minification


Bundles are created programmatically during the application startup in global.asax. Also
in this case, you can use the xxxConfig pattern and add some BundlesConfig class to the
App_Startup folder. The BundleConfig class contains at least one method with code very
close to the following snippet.
public static void RegisterBundles(
BundleCollection bundles)
{
bundles.Add(new StyleBundle("~/Content/Styles")
.Include("~/Content/Styles/bootstrap.css",
"~/Content/Styles/myapp.css"));
}

03/01/2016 21:56

10 Good Practices for ASP.NET MVC Apps

10 of 29

http://www.codemag.com/article/1405071

within the project where the source code to bundle is located. The argument passed to
the StyleBundle class constructor instead is the public name of the bundle and the URL
through which it will be retrieved from pages. There are quite a few ways to indicate the
CSS files to bundle. In addition to listing them explicitly, you can use a wildcard
expression:
bundles.Add(new Bundle("~/css")
.Include("~/content/styles/*.css");

Once CSS bundles are defined invoking them is as easy as using the Styles object:
@Styles.Render("~/Bundles/Css")

As you can figure from the last two snippets, ASP.NET optimization extensions come
with two flavors of bundle classes: the Bundle class and the StyleBundle class. The
former only does bundling; the latter does both bundling and minification. Minification
occurs through the services of an additional class. The default CSS minifier class is
CssMinify and it is based on some logic packaged in WebGrease. Switching to a different
minifier is easy too. All you do is using a different constructor on the StyleBundle class.
You use the constructor with two arguments, the second of which is your own
implementation of IBundleTransform.

#4 Bundling and Minifying Script Files


Bundling and minification apply to script files in much the same way as bundling and
minifying CSS files. The only minor difference is that for frequently used script files (such
as jQuery) you might want to use a CDN for even better performance. In operational
terms, bundling and minifying script files requires the same process and logic as CSS
files. You use the Bundle class if youre only concerned about packing multiple files
together so that they are captured in a single download and cached on the client.
Otherwise, if you also want minifying, you use the ScriptBundle class.
bundles.Add(new ScriptBundle("~/Bundles/Core")
.Include(
"~/Content/Scripts/myapp-1.0.0.js",
"~/Content/Scripts/knockout-3.0.0.js")
);

03/01/2016 21:56

10 Good Practices for ASP.NET MVC Apps

11 of 29

Like

StyleBundle,

ScriptBundle

http://www.codemag.com/article/1405071

also

features

constructor

that

accepts

an

IBundleTransform object as its second argument. This object is expected to bring in


some custom logic for minifying script files. The default minifier comes from WebGrease
and corresponds to the JsMinify class.
Its very common today to arrange very complex and graphically rich Web templates
that are responsive to changes in the browsers window size and that update content on
the client side through direct access to the local DOM. All this can happen if you have a
lot of script files. Its not, for the most part, JavaScript code that you write yourself. Its
general-purpose JavaScript that forms a framework or a library. In a nutshell, you often
end up composing your client-side logic by sewing together multiple pieces, each of
which represents a distinct download.
Considering the general recommendation of using as few script endpoints as
possibleand bundling does help a lot in that regardthe optimal position of the
<script> tags in the body of the HTML page is an open debate. For quite some time, the
common practice was to put <script> elements at the end of the document body. This
practice was promoted by Yahoo and aimed at avoiding roadblocks during the
rendering of the page. By design, in fact, every time the browser encounters a <script>
tag, it stops until the script has been downloaded (or recovered from the local cache)
and processed.
Its not mandatory that all script files belong at the bottom. Its advisable that you
distinguish the JavaScript thats needed for the page to render from the JavaScript that
serves other purposes. The second flavor of JavaScript can safely load at the bottom.
Well, mostly at the bottom. Consider that as the page renders the user interface in the
browser, users may start interacting with it. In doing so, users may trigger events that
need some of the other JavaScript placed at the bottom of the page and possibly not yet
downloaded and evaluated. If this is your situation, consider keeping input elements
that the user can interact with disabled until its safe to use them. The ready event of
jQuery is an excellent tool to synchronize user interfaces with downloaded scripts.
Finally, consider some techniques to load scripts in parallel so that the overall download
time becomes the longest of all instead of the sum of all downloads. The simplest way
you can do this is through a programmatically created <script> element. You do this
using code, as shown below.
var h = document.getElementsByTagName("HEAD")[0];
var script = document.createElement("script");
script.type = "text/javascript";
script.onreadystatechange = function() {...};

03/01/2016 21:56

10 Good Practices for ASP.NET MVC Apps

12 of 29

http://www.codemag.com/article/1405071

document.src = "...";
h.appendChild(script)

Script elements are appended to the HEAD element so that parallel download begins as
soon as possible. Note that this is the approach that most social Web sites and Google
Analytics use internally. The net effect is that all dynamically created elements are
processed on different JavaScript threads. This approach is also employed by some
popular JavaScript loader frameworks these days.

#5 The Structure of the _Layout File


In ASP.NET MVC, a layout file is what a master page was in classic Web Forms: the
blueprint for multiple pages that are ultimately built out of the provided template. What
should you have in a master view? And in which order?
With the exceptions and variations mentioned a moment ago for parallelizing the
download of multiple scripts, there are two general rules that hold true for the vast
majority of websites. The first rule says: Place all of your CSS in the HEAD element. The
second rule says: Place all of your script elements right before the closing tag of the
<body> element.
There are a few other little things you want to be careful about in the construction of the
layout file(s) for your ASP.NET MVC application. First off, you might want to declare
explicitly that the document contains HTML5 markup. You achieve this by having the
following markup at the very beginning of the layout and subsequently at the beginning
of each derived page.
<!DOCTYPE html>

The DOCTYPE instructs older browsers that dont support specific parts of HTML5 to
behave well and correctly interpret the common parts of HTML while ignoring the
newest parts. Also, you might want to declare the character set in the HEAD block.
<meta charset="UTF-8">

The charset attribute is case-insensitive, meaning that you can indicate the character set
name as UTF-8, utf-8 or otherwise. In general, you dont use other character sets than

03/01/2016 21:56

10 Good Practices for ASP.NET MVC Apps

13 of 29

http://www.codemag.com/article/1405071

character set. For example, you can type it in the <globalization> section of the
web.config file. Having it right in each page just adds clarity. An interesting consequence
of clarifying the character set being used is that you can avoid using HTML entities and
type special characters directly in the source. Canonical examples are the copyright
(&copy;), trademark (&reg;), euro (&euro), dashes (&mdash;), and more. The only HTML
entities you should use are those that provide the text version of reserved markup
characters, such as less-than, greater-than, and ampersand.
Another rather important meta-tag youll want to have is the viewport meta-tag whose
usage dates back to the early days of smartphones. Most mobile browsers can be
assumed to have a rendering area thats much larger than the physical width of the
device. This virtual rendering area is just called the "viewport." The real size of the
internal viewport is browser-specific. However, for most smart phones, its around 900
pixels. Having such a large viewport allows browsers to host nearly any Web page,
leaving users free to pan and zoom to view content, as illustrated in Figure 5.

Figure 5 : The viewport in a browser


The viewport meta-tag is a way for you to instruct the browser about the expected size
of the viewport.

03/01/2016 21:56

10 Good Practices for ASP.NET MVC Apps

14 of 29

http://www.codemag.com/article/1405071

initial-scale=1.0,
maximum-scale=1.0,
user-scalable=no" />

In this example, you tell the browser to define a viewport that is the same width as the
actual device. Furthermore, you specify that the page isnt initially zoomed and worse,
users cant zoom in. Setting the width property to the devices width is fairly common,
but you can also indicate an explicit number of pixels.
In ASP.NET MVC, pay a lot of attention to keeping the layout file as thin as possible. This
means that you should avoid referencing from the layout file CSS and script files that are
referenced by all pages based on the layout. As developers, we certainly find it easier
and quicker to reference resources used by most pages right from the layout file. But
that only produces extra traffic and extra latency. Taken individually, these extra delays
arent significant, except that they sum up and may add one or two extra seconds for the
page to show and be usable.
In ASP.NET MVC, a layout page consists of sections. A section is an area that derived
pages can override. You might want to use this feature to let each page specify CSS and
script (and of course markup) that needs be specific. Each layout must contain at least
the section for the body.
<div class="container">
@RenderBody()
<hr />
<footer>
@DateTime.Now.Year - ASP.NET QuickUp
</footer>
</div>

The markup above indicates that the entire body of the page replaces @RenderBody.
You can define custom sections in a layout file using the following line:
@RenderSection("CustomScripts")

The name of the section is unique but arbitrary and you can have as many sections as
you need with no significant impact on the rendering performance. You just place a
@RenderSection call where you want the derived page to inject ad hoc content. The
example above indicates a section where you expect the page to insert custom script

03/01/2016 21:56

10 Good Practices for ASP.NET MVC Apps

15 of 29

http://www.codemag.com/article/1405071

script blocks, you can proceed as follows:


<script type="text/javascript">
@RenderSection("CustomScripts")
</script>

In this case, overridden sections are expected to contain data that fits in the surrounding
markup; otherwise, a parsing error will be raised. In a derived page, you override a
section like this:
@section CustomScripts
{
alert("Hello");
}

#6 (Dont) Use Twitter Bootstrap


Twitter Bootstrap is quickly becoming the de-facto standard in modern Web
development, especially now that Visual Studio 2013 incorporates it in the default
template for ASP.NET MVC applications. Bootstrap essentially consists of a large
collection of CSS classes that are applicable directly to HTML elements and in some
cases to special chunks of HTML markup. Bootstrap also brings down a few KBs of script
code that extends CSS classes to make changes to the current DOM.
As a matter of fact, with Bootstrap, you can easily arrange the user interface of Web
pages to be responsive and provide advanced navigation and graphical features.
The use of Bootstrap is becoming common and, as popularity grows, also controversial.
There are reasons to go for it and reasons for staying away from it. My gut feeling is that
Bootstrap is just perfect for quick projects where aesthetics are important but not
fundamental, and where you need to provide pages that can be decently viewed from
different devices with the lowest possible costs. Key arguments in favor of Twitter
Bootstrap are its native support for responsive Web design (RWD), deep customizability,
and the not-secondary fact that its extremely fast to learn and use.
Bootstrap was created as an internal project at Twitter and then open-sourced and
shared with the community. When things go this way, there are obvious pros and cons.

03/01/2016 21:56

10 Good Practices for ASP.NET MVC Apps

16 of 29

http://www.codemag.com/article/1405071

breadcrumbs, tabs, accordions, rich buttons, composed input fields, badges and
bubbles, lists, glyphs, and more advanced things, such as responsive images and media,
auto-completion, and modal dialogs. Its all there and definable through contracted
pieces of HTML and CSS classes. Put another way, when you choose Bootstrap, you
choose a higher level markup language than HTML. Its much the same as when you use
jQuery and call it JavaScript. The jQuery library is made of JavaScript but extensively
using it raises the abstraction level of JavaScript.
By the same token, using Bootstrap extensively raises the abstraction level of the
resulting HTML and makes it look like youre writing Bootstrap pages instead of HTML
pages. This is just great for developer-centric Web solutions. Its not good for Web
designers and for more sophisticated projects where Web designers are deeply involved.

When you choose Bootstrap. you choose a higher-level


markup language than HTML. Its much the same as when
you use jQuery and call it JavaScript.

From a Web designers perspective, Twitter Bootstrap is just a Twitter solution and even
theming it differently is perceived like work that takes little creativity. From a pure Web
design perspective, Bootstrap violates accepted (best) practices. In particular, Bootstrap
overrides the HTML semantic and subsequently, presentation is no longer separate from
the content. Not surprisingly, when you change perspective, the same feature may turn
from being a major strength to being a major weakness. Just because Bootstrap
overrides the HTML semantic, it tends to favor an all-or-nothing approach. This may be
problematic for a Web design team that joins an ongoing project where Bootstrap is
being used. In a nutshell, Bootstrap is an architectural decisionand one thats hard to
change on the go. So, yes, it makes presentation tightly bound to content. Whether this
is really an issue for you cant be determined from the outside of the project.
Last but not least, the size of Twitter Bootstrap is an issue. Minified, it counts for about
100K of CSS, 29K of JavaScript plus fonts. You can cut this short by picking exactly the
items you need. The size is not an issue for sites aimed at powerful devices such as a PC,
but Bootstrap for sites aimed at mobile devices may be a bit too much. If youre going
to treat desktop devices differently from mobile devices, you might want to look into the
mobile-only version of Bootstrap that you find at .

03/01/2016 21:56

10 Good Practices for ASP.NET MVC Apps

17 of 29

http://www.codemag.com/article/1405071

#7 Keep Controllers Thin


ASP.NET MVC is often demonstrated in the context of CRUD applications. CRUD is a very
common typology for applications and its a very simple typology indeed. For CRUD
applications, a fat controller that serves any request directly is sometimes acceptable.
When you combine the controller with a repository class for each specific resource you
handle, you get good layering and achieve nifty separation of concerns.
Its essential to note that the Model-View-Controller pattern alone is not a guarantee of
clean code and neatly separated layers. The controller simply ensures that any requests
are routed to a specific method thats responsible for creating the conditions for the
response to be generated and returned. In itself, an action method on a controller class
is the same as a postback event handler in old-fashioned Web Forms applications. Its
more than OK to keep the controller action method tightly coupled to the surrounding
HTTP context and access it from within the controller method intrinsic objects such as
Session, Server, and Request. A critical design goal is keeping the controller methods as
thin as possible. In this way, the controller action methods implement nearly no logic or
very simple workflows (hardly more than one IF or two) and theres no need to test
them.
As each controller method is usually invoked in return to a users gesture, theres some
action to be performed. Which part of your code is responsible for that? In general, a
user action triggers a possibly complex workflow. Its only in a basic CRUD, like the very
basic Music Store tutorial, that workflow subsequent to user actions consists of one
database access that the resource repository carries out. You should consider having an
intermediate layer between controllers and repositories. (See Figure 6.)

03/01/2016 21:56

10 Good Practices for ASP.NET MVC Apps

18 of 29

http://www.codemag.com/article/1405071

Figure 6 : A multi-layer architecture for an ASP.NET MVC application


The extra layer is the application layer and it consists of classes that typically map to
controllers. For example, if you have HomeController, you might also want to have some
HomeService class. Each action in HomeController ends up calling one specific method
in HomeService. Listing 1 shows some minimalistic code to illustrate the pattern.
The Index method invokes the associated worker service to execute any logic. The
service returns a view model object that is passed down to the view engine for the
actual rendering of the selected Razor view. Figure 7 shows instead a modified project
structure that reflects worker services and the application layer of the ASP.NET MVC
application.

03/01/2016 21:56

10 Good Practices for ASP.NET MVC Apps

19 of 29

http://www.codemag.com/article/1405071

Figure 7 : The new project infrastructure for worker services and view models

#8 Membership and Identity


To authenticate a user, you need some sort of a membership system that supplies
methods to manage the account of a user. Building a membership system means writing
the software and the related user interface to create a new account and update or delete
existing accounts. It also means writing the software for editing any information
associated with an account. Over the years, ASP.NET has offered a few different
membership systems.
Historically, the first and still largely used membership system is centered on the
Membership static class. The class doesnt directly contain any logic for any of the
methods it exposes. The actual logic for creating and editing accounts is supplied by a
provider component that manages an internal data store. You select the membership in
the configuration file. ASP.NET comes with a couple of predefined providers that use
SQL Server or Active Directory as the persistence layer. Using predefined providers is
fine, as it binds you to a predefined storage schema and doesnt allow any reuse of
existing membership tables. For this reason, its not unusual that you end up creating
your own membership provider.
Defining a custom membership provider is not difficult at all. All you do is derive a new

03/01/2016 21:56

10 Good Practices for ASP.NET MVC Apps

20 of 29

http://www.codemag.com/article/1405071

ChangePassword. This is where things usually get a bit annoying.


The original interface of the Membership API is way too complicated with too many
methods and too many quirks. People demanded a far simpler membership system.
Microsoft first provided the SimpleMembership provider and with Visual Studio 2013,
what appears to be the definitive solution: ASP.NET Identity.
In the ASP.NET Identity framework, all of the work is coordinated by the authentication
manager. It takes the form of the UserManager<T> class, which basically provides a
faade for signing users in and out.
public class UserManager<T> where T : IUser
{
:
}

The type T identifies the account class to be managed. The IUser interface contains a
very minimal definition of the user, limited to ID and name. The ASP.NET Identity API
provides the predefined IdentityUser type that implements the IUser interface and adds
a few extra properties such as PasswordHash and Roles. In custom applications, you
typically derive your own user type inheriting from IdentityUser. Its important to notice
that getting a new class is not required; you can happily work with native IdentityUser if
you find its structure appropriate.
User data storage happens via the UserStore<T> class. The user store class implements
the IUserStore interface that summarizes the actions allowed on the user store:
public interface IUserStore<T> : where T:IUser
{
Task CreateAsync(T user);
Task DeleteAsync(T user);
Task<T> FindByIdAsync(string userId);
Task<T> FindByNameAsync(string userName);
Task UpdateAsync(T user);
}

As you can see, the user store interface looks a lot like a canonical repository interface,
much like those you might build around a data access layer. The entire infrastructure is
glued together in the account controller class. The skeleton of an ASP.NET MVC account
controller class that is fully based on the ASP.NET Identity API is shown in Listing 2.

03/01/2016 21:56

10 Good Practices for ASP.NET MVC Apps

21 of 29

http://www.codemag.com/article/1405071

user store and the data store is established in the ApplicationDbContext class. Youll find
this class defined by the ASP.NET MVC 5 wizard if you enable authentication in the
Visual Studio 2013 project template.
public class ApplicationDbContext :
IdentityDbContext<IdentityUser>
{
public ApplicationDbContext() :
base("DefaultConnection")
{
}
}

The base IdentityDbContextclass inherits from DbContextand is dependent on Entity


Framework. The class refers to an entry in the web.config file, where the actual
connection string is read. The use of Entity Framework Code First makes the structure of
the database a secondary point. You still need a well-known database structure, but you
can have the code to create one based on existing classes instead of manual creation in
SQL Server Management Studio. In addition, you can use Entity Framework Code First
Migration tools to modify a previously created database as you make changes to the
classes behind it.
Currently, ASP.NET Identity covers only the basic features of membership but its
evolution is not bound to the core ASP.NET Framework. Features that the official
interfaces dont cover yet (such as enumerating users) must be coded manually, which
brings you back to the handcrafted implementation of membership.

#9 Expose HTTP Endpoints


An architecture for Web applications thats becoming increasingly popular is having a
single set of HTTP endpointscollectively known as Web servicesconsumed by all
possible clients. Especially if you have multiple clients (like mobile applications and
various Web frontends) a layer of HTTP endpoints is quite helpful to have. Even if you
only have a single client frontend, a layer of HTTP endpoints is helpful as it allows you to
have a bunch of Ajax-based functionalities integrated in HTML pages. The question is:
How would you define such endpoints?
If you need an APIor even a simple set of HTTP endpointsexposed out of anything

03/01/2016 21:56

10 Good Practices for ASP.NET MVC Apps

22 of 29

http://www.codemag.com/article/1405071

you can simply use a separate ASP.NET MVC controller and make it return JSON.
There are many posts out there calling for a logical difference between Web API
controllers and ASP.NET MVC controllers. Theres no doubt that a difference exists
because overall Web API and ASP.NET MVC have different purposes. Anyway, the
difference becomes quite thin and transparent when you consider it from the
perspective of an ASP.NET MVC application.
With plain ASP.NET MVC, you can easily build an HTTP faade without learning new
things. In ASP.NET MVC, the same controller class can serve JSON data or an HTML view.
However, you can easily keep controllers that return HTML separate from controllers
that only return data. A common practice consists in having an ApiController class in the
project that exposes all endpoints expected to return data. In Web API, you have a
system-provided ApiController class at the top of the hierarchy for controllers. From a
practical perspective, the difference between ASP.NET MVC controllers and Web API
controllers hosted within the same ASP.NET MVC is nearly non-existent. At the same
time, as a developer, its essential that you reason about having some HTTP endpoints
exposed in some way.

Web API and ASP.NET MVC have different purposes.

#10 Use Display Modes


One of the best-selling points of CSS is that it enables designers and developers to keep
presentation and content neatly separated. Once the HTML skeleton is provided, the
application of different CSS style sheets can produce even radically different results and
views. With CSS, you can only hide, resize, and reflow elements. You cant create new
elements and you can add any new logic for new use-cases.
In ASP.NET MVC, a display mode is logically the same as a style sheet except that it
deals with HTML views instead of CSS styles. A display mode is a query expression that
selects a specific view for a given controller action. In much the same way, the Web
browser on the client processes CSS media query expressions and applies the
appropriate style sheet; a display mode in server-side ASP.NET MVC processes a context
condition and selects the appropriate HTML view for a given controller action.

03/01/2016 21:56

10 Good Practices for ASP.NET MVC Apps

23 of 29

http://www.codemag.com/article/1405071

however, is associated with server-side device detection and view routing. By default,
starting with ASP.NET MVC 4, any Razor view can be associated with a mobile-specific
view. The default controller action invoker automatically picks up the mobile-specific
view if the user agent of the current request is recognized as the user agent of a mobile
device. This means that if you have a pair of Razor views such as index.cshtml and
index.mobile.cshtml, the latter will be automatically selected and displayed in lieu of the
former if the requesting device is a mobile device. This behavior occurs out of the box
and leverages display modes. Display modes can be customized to a large extent. Heres
an example:
var tablet = new DefaultDisplayMode("tablet")
{
ContextCondition = (c => IsTablet(c.Request))
};
var desktop = new DefaultDisplayMode("desktop")
{
ContextCondition = (c => return true)
};
displayModes.Clear();
displayModes.Add(tablet);
displayModes.Add(desktop);

The preceding code goes in the Application_Start event of global.asax and clears default
existing display modes and then adds a couple of user-defined modes. A display mode
is associated with a suffix and a context condition. Display modes are evaluated in the
order in which theyre added until a match is found. If a match is foundthat is, if the
context condition holds truethen the suffix is used to complete the name of the view
selected. For example, if the user agent identifies a tablet, then index.cshtml becomes
index.tablet.cshtml. If no such Razor file exists, the view engine falls back to index.cshtml.
Display modes are an extremely powerful rendering mechanism but all this power fades
without a strong mechanism to do good device detection on the server side. ASP.NET
lacks such a mechanism. ASP.NET barely contains a method in the folds of the
HttpRequest object to detect whether a given device is mobile or not. The method is not
known to be reliable and work with just any old device out there. It lacks the ability to
distinguish between smartphones, tablets, Google glasses, smart TVs, and legacy cell
phones. Whether it works in your case is up to you.
If youre looking for a really reliable device detection mechanism, I recommend WURFL,
which comes through a handy Nuget package. For more information on WURFL, you can

03/01/2016 21:56

10 Good Practices for ASP.NET MVC Apps

24 of 29

http://www.codemag.com/article/1405071

Display modes are extremely useful in any scenario where


multiple views for the same action can be selected based
on run time conditions.

Summary
ASP.NET MVC 5 is the latest version of Microsofts popular flavor of the ASP.NET
platform. It doesnt come with a full bag of new goodies for developers but it remains a
powerful platform for Web applications. ASP.NET is continuously catching up with trends
and developments in the Web space and writing a successful ASP.NET MVC application
is a moving target. This article presented ten common practices to build ASP.NET MVC
applications with comfort and ease.

Domain Model
Unless you are creating a plain
CRUD application, the model of
business data (also referred to as
the domain model) is referenced
from a separate assembly and is
created
and
mapped
to
persistence using any of the
known

approaches

in

Entity

Framework, whether Databasefirst, Model-first, or Code-first.

Bundling,

03/01/2016 21:56

10 Good Practices for ASP.NET MVC Apps

25 of 29

http://www.codemag.com/article/1405071

Debug Mode
Bundling and minification are not
a functional feature and are,
rather, a form of optimization. For
this reason, it makes no sense for
you to enable both while in
debug

mode.

For

common

libraries such as jQuery or


Bootstrap, a direct reference to
the minified version is acceptable.
By

default,

bundling

and

minification are disabled until you


compile in release mode. The
code discussed in this article,
therefore, wont work until you
set

debug=false

in

the

web.config file. If you only want


to

check

bundling

and

minification in release mode but


leave debug mode on until
deployment, you can set the
EnableOptimizations property to
true on the BundleTable class.

Ratchet 2.0
Recently, the project codenamed
Ratchet reached version 2.0 and
merged and synced up with
Bootstrap.
considered

Ratchet
the

can

be

mobile-only

version of Bootstrap. It largely


follows the same approach and
design

and

offers

the

same

benefits in terms of raising the


abstraction level of the HTML
being used. The ideal scenario for
Ratchet
HTML5

is mobile sites and


applications, whether

compiled native through Cordova


or pinned to the dashboard of

03/01/2016 21:56

10 Good Practices for ASP.NET MVC Apps

26 of 29

http://www.codemag.com/article/1405071

Listing 1: A layered controller class


public interface IHomeService
{
IndexViewModel GetModelForIndex();
}
public class HomeController : Controller
{
private readonly IHomeService _service;
public HomeController() : this (new HomeService())
{
}
public HomeController(IHomeService service)
{
_service = service;
}
public ActionResult Index()
{
var model = _service.GetModelForIndex();
return View(model);
}
}
public class ViewModelBase
{
public String Title { get; set; }
}
public class IndexViewModel : ViewModelBase
{
// More members here
}

Listing 2. Sample account controller class


public class AccountController : Controller
{
public UserManager<IdentityUser> UserManager { get; set; }
public AccountController(UserManager<IdentityUser> manager)
{
UserManager = manager;
}
public AccountController() : this(
new UserManager<IdentityUser>(
new UserStore<IdentityUser>(new ApplicationDbContext())))
{
}
// Other members here
}

03/01/2016 21:56

10 Good Practices for ASP.NET MVC Apps

27 of 29

http://www.codemag.com/article/1405071

Folder
name

Intended goal

App_Data

Contains data used by the application, such as proprietary files (e.g., XML files) or
local databases

App_Start

Contains initialization code. By default, it simply stores static classes invoked from
within global.asax.

Controllers

Folder conventionally expected to group all controllers used by the application

Models

Folder conventionally expected to contain classes representing the rather


nebulous MVC concept of "model"

Views

Folder conventionally expected to group all Razor views used by the application.
The folder is articulated in subfolders,one per controller

Like what you just read and want more?


Get your free trial subscription to CODE Magazine!

Have addtional technical questions?


Get help from the experts at CODE Magazine - sign up for our free hour of consulting!
Contact CODE Consulting at techhelp@codemag.com.

Got something to say? Leave a comment!

03/01/2016 21:56

10 Good Practices for ASP.NET MVC Apps

28 of 29

http://www.codemag.com/article/1405071

Add a comment...

Josh McKinney
On the Config classes tip (#2), I wonder if instead of method params, taking
constructor params and just having a Configure() or Start() method would be
nicer and more DI friendly than writing actual code to call the config code.
Re: tip #6 (don't use bootstrap), I wonder if this is argument is still relevant if
you use the SASS / LESS versions of bootstrap.
Like Reply

2 Apr 11, 2014 10:10pm

Taha Amin Ali Mubarak High School, Cairo Egypt


#8 which version of ASP.NET Identity?
Like Reply

1 Apr 15, 2014 1:26am

John Sully
I recommend version 2.0 which came out in March 2014.
Like Reply May 19, 2014 10:01am

Michael Gois Director at Timesheet Portal


A great set of concise tips which I am sure will be really helpful once I get
round to implementing them in my code. Thanks!
Like Reply May 28, 2014 2:12pm

Dot NET World


Nice article
Like Reply Jun 11, 2014 2:38pm Edited

Suresh Kutty Works at HCL Technologies


Nice Article
Like Reply Jun 11, 2014 10:41pm

Vedran Mandi Dev Lead at Mogy App


Great article! Sums alot of stuff which one has to learn over a long period of
time and practice.
Like Reply

1 Jun 12, 2014 2:47am

Pravin Kapse Yeshwant Mahavidyalaya Nanded


great,nice article
Like Reply Jun 12, 2014 4:40am

Edward Spencer Contract Software Developer at My Company


Nice article, but your criticism of Twitter bootstrap because of the size of its
CSS is misplaced. The CSS is 100 KB, but that many bytes will not be sent
over the wire. All production webservers will use gzipping (as does the twitter
bootstrap CDN), which means that when using Twitter bootstrap from the
CDN or from a webserver that uses gzipping, only 21.6 KB of CSS is sent
over the wire to the client.

03/01/2016 21:56

10 Good Practices for ASP.NET MVC Apps

29 of 29

http://www.codemag.com/article/1405071

(c) by EPS Software Corp. 1993 - 2016


6605 Cypresswood Dr. - Suite 300 - Spring - TX 77379 - USA
Voice: +1 (832) 717-4445 - Fax: +1 (832) 717-4460 - Email: info@codemag.com

03/01/2016 21:56

Potrebbero piacerti anche