ASP.NET has changed dramatically in the past five years. I’ve had the privilege to work on some projects using the newer web stacks, as well as modernize an old project.

I’d been away from the Microsoft ecosystem from around 2006 until 2011, and after working in dynamic languages (javascript, python, lisp), it took me some time to figure out what kind of code the Microsoft ecosystem was happiest with.

I threw a lot of pasta on the wall, and here are a few that seemed to stick.

Libraries

I had the smallest friction with this combination of libraries:

Entity Framework (EF): for database access, schema evolution, and ORM

Ninject: dependency injection (DI) library

ASP.NET MVC: fully featured web framework for serving user interfaces, with a filter/DI system that provides a lot of flexibility

ASP.NET WebApi: fully featured web framework for serving JSON/XML APIs, with a filter/DI system that provides a lot of flexibility. Makes a great backend for javascript frameworks

Moq: mock object library, makes easily fake any interface to minimize test setup/teardown

LocalDb: Microsoft’s answer to sqlite, a file-based database that’s SQL Server compatible but does not require any server or licensing

AutoMapper: quickly copy data from one type to another without a lot of repetitive code

log4net: very flexible logging; I bet it’s one of the oldest active C# open source libraries, I’ve been using it for years

FluentValidation: input validation library; lets you specify complex validation rules for a class

Everything is available via nuget, except for the LocalDb installer. Some of these are warrant further discussion.

Entity Framework (EF)

Very fully featured data access library. There’s a ton of depth here.

Good

define db schemas using C# classes mostly through properties and attributes, able to use inheritance to reduce duplication

specify db schema evolution using tool-assisted explicit migrations; add a new field to one of the DB classes, call Add-Migration NewField-ticket42 , and most of the work is done, including a natural place to add data fixes

, and most of the work is done, including a natural place to add data fixes generate SQL scripts of pending migrations (EF stores some metadata in your database) for deployment

LocalDb support

linq support that builds crazy but reasonably efficient SQL queries that make it easy to select the minimal amount of data you need. You can select a few properties from your db object without fetching a whole row, do joins, etc

provides a database cache; repeated requests to fetch a db object against the same db context are free

transaction support; any operations (including inserting complex relationships) on a db context are pending until you call SaveChanges

can work against existing databases, with some care

Bad

the linq support can be surprising; some things just aren’t allowed and it isn’t always obvious. Thankfully the exceptions are thrown early and have good messages

it’s easy to accidentally load way more data than you want

exception messages for some db errors can be a obtuse or require debugging to examine a property on the exception

really, really, really wants you to run all your DB operations against one instance of the DB context (i.e. per HTTP request). Things get really weird if you try to use a db object between two db context instances

is happier with updates if you load a db object in full, change the properties, then save

it can be tricky to sort out how to add a graph of db objects without fetching the whole DB or calling SaveChanges multiple times to get autoincrement ids. Totally doable, but easy to screw up

multiple times to get autoincrement ids. Totally doable, but easy to screw up EF’s migrations require your db classes to be free of compiler errors, which leads to putting your db classes in a different DLL from the rest of your application. If you change a db class in a way that breaks the rest of your application, unless the db classes in a different assembly, you have to update your entire application before you can figure out the migration. This leads to other weirdness and tough questions like “which assembly should this DTO/interface go in?”

ASP.NET MVC and ASP.NET WebApi

ASP.NET WebApi and ASP.NET MVC are very similar, and the two are being combined in ASP.NET vNext. They can also work together in one web project, albeit with different namespaces. It’ll be nice when ASP.NET vNext unifies these namespaces.

Good

explicitly maps URLs and HTTP verbs to an action method on a controller class

filter system that lets you run code before and after your action

naming convention-based system to choose templates for controller actions, with helpful error messages telling you what names the framework expected

automatically serialize/deserialize between HTTP GET/POST/PUT/DELETE data into C# objects, with hooks to customize the process. Ends up acting a lot like method injection

hooks for how the framework instantiates controllers to let you use a DI library for controller creation

really likes view models; define all the data you want in a template as a class, create it in your controller action, and pass it to the template. Viewmodels are easy to test

the ASP.NET MVC template system has nice helpers like EditorFor and DisplayFor to render UI for view models

and to render UI for view models Since controllers are plain classes, you can new them up in tests and pass in different input without running a web server

them up in tests and pass in different input without running a web server lots of plugins and helper libraries on nuget WebApi.HelpPage: automatic API documentation using reflection and XML doc comments FluentValidation.WebApi-Signed: easily run validation rules for incoming data FluentValidation.MVC5-Signed: easily run validation rules for incoming data many more



Bad

MVC wants you to group your files by type, not by feature. This makes your template far away from the (usually) single controller that uses it

no easy way to share templates between different projects

ASP.NET WebApi and ASP.NET MVC have a lot of the same classes in different namespaces. If you’re using them together it can get confusing if you want a System.Web.Http.Filters.IAuthenticationFilter and accidentally autocomplete the wrong using statement and end up with a System.Web.Mvc.Filters.IAuthenticationFilter

statement and end up with a System.Web.Mvc.Filters.IAuthenticationFilter visual studio refactoring tools like “Rename” do NOT change your templates

any code in your templates is technically in a different assembly, so anything in your viewmodel you want to use in a template needs to be public

some built-in MVC helpers look at attributes on your viewmodel for how to render, validate, etc. If you follow that approach, then changing a <label> requires a recompile and a bunch of “go to definition”. Seems like writing HTML in your templates is easier than using the helpers so you can scatter your UI text across your viewmodels. This is probably fine if you need internationalization or localization, but if you don’t then it just feels like extra hoops

Ninject

Pretty straightforward dependency injection library. You tell it what implementation you want for what interface at application start, and then ask it to create all your objects.

class Foo : IFoo { public Foo(IBar b){} } // on app start: var kernel = new Ninject.StandardKernel(); kernel.Bind<IBar>().To<Bar>(); kernel.Bind<IFoo>().To<Foo>(); var foo = kernel.Get<IFoo>(); // new Foo(new Bar())

Good

easy to use

makes it practical to write many small, easily testable classes and not have to wire them up by hand

good error messages

support contexts so you can say “make one DBContext per HTTP request”

tons of options

lots of plugins on nuget: ninject.extensions.conventions: automatically register interfaces/implementations Ninject.Extensions.Factory: create naive factory classes; useful if you long-lived objects Ninject.MockingKernel.Moq: easily use mock objects with ninject for unit testing many more



Bad

depending on what version of ASP.NET MVC/WebApi you’re using, there are different nuget packages and install instructions, take care you’re using the right approach

“go to definition” gets less useful, since it’ll lead you to the interface, not to what ninject is actually instantiating at runtime

reduces the cost of many small classes; you get a long chain of “go to definition” to find the class actually doing the work

LocalDb

This is the dev/test database I’ve always wanted.

Good

can run tests against a full DB. At the beginning of your test run create a new LocalDb file, run all your EF migrations, then run each test case in a DB transaction

great for running dev sites on your workstation without a ton of setup

Bad

sometimes the files get in a weird state and you have to change your connection string to get a new file

I expect some subtle difference between this and a full SQL Server that will bite you if you use proprietary SQL Server features

AutoMapper

I kept going back and forth on this one; sometimes it’s a great time saver, sometimes it’s a huge hassle. Overall I think it’s a win.

Uses reflection to convert code like:

class Whatever { public Foo Copy(Bar b){ return new Foo{ Name = b.Name, Title = b.Title, Message = b.Message } } }

into something like:

class Whatever{ static Whatever(){ Mapper.CreateMap<Bar, Foo>(); } public Foo Copy(Bar b){ return Mapper.Map<Foo>(b); } }

When you have a lot of data transfer objects (DTO)s it can be really common to want to copy fields from one type to another.

Good

reduces annoying boilerplate

can specify explicit mappings when names don’t match

can map collections and nested objects

works with EF and linq to map from your db objects and minimize how much you fetch from the db

you create mappings at application start, and they are cached from then on so you don’t pay a big reflection penalty

Bad

is really much happier when the property names match exactly

gets really finicky about mapping collections from linq

error messages could be better

refactorings like “rename” could introduce runtime errors if you don’t have good test coverage

copying data a lot isn’t a great idea; using more interfaces might eliminate the need

complex mappings that apply to multiple classes are difficult to reuse

FluentValidation

Specify validation rules with a testable, fluent interface:

class FooValidator : FluentValidation.AbstractValidator<Foo> { public FooValidator(){ RuleFor(x => x.Name).NotEmpty(); } } // validate new FooValidator().Validate(new Foo())

Good

easy to test

plugins to automatically validate deserialized MVC or WebApi requests

lots of validation rules

custom validations are straightforward to implement

Bad