.NET MVC Must Earn the Price We Pay

Note: This is an article I wrote back in 2016 but stayed in my drafts. Although .NET MVC Core is a significant leap from .NET MVC now, my points still have some merit.

Statically-typed programming languages are not the easiest ones. We see students easily grasp Python yet struggle with Java when introduced with types, declaration statements and all the mumbo jumbo. Compare the Hello World examples for instance:

Java:

public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}

Python:

print(“Hello World”)

Java example introduces us three distinct types: HelloWorld class, “void” and “String[]”, yet with the Python example we don’t even have to know what a type is. Java code unnecessarily looks cumbersome for the function it performs. Sure whole world isn’t about that.

I wrote web code using VBScript when it was the de facto alternative to PHP. It was very similar to Visual Basic but dynamically-typed which meant that a variable could be re-assigned to a value of a different type without any errors. So the code below would work fine:

a = 2            ' Integer
a = "test" ' String
b = a ' String
b = 2 = "test" ' Boolean

It wasn’t strongly-typed per se but had the right checks and measures at the right places like explicit type conversion functions, a separate string concatenation operator, throwing errors etc.

VBScript was terse, easy to read but severly limited. It didn’t even have a built-in hash-table class which almost all programming platforms had out of the box. You had to instantiate a COM object to access similar features.

One of the interesting features of VBScript was ability to change error handling mode on the fly with two statements called and . Those were the artifacts carried from olden BASIC times, when source code had line numbers.

Image for post
Image for post
‘Member Futurama? I ‘member!

If you chose to “resume next” VBScript simply ignored errors and continued. You could still check if there was an error explicitly with an if statement. If you chose the program would halt with an error message at the first error it encountered.

Ignorance is bliss, sometimes

Image for post
Image for post
Errare nihilum est

Ignoring errors has interesting implications in web development. You may not want to do that in your credit card payment processing code. It might even be desirable at times though, especially when your page is composed of many smaller parts. You definitely don’t want a small, unimportant box on the corner of your page to break everything else. That’s why I find the loose error handling semantics in Go language suitable for web development. If you didn’t handle the error the world wouldn’t crash and burn like with exceptions. You want some of that error tolerant attitude in web. So I had used both VBScript statements depending on how critical was the part of the page the code produced. Sometimes even at the function level:

function doSomethingVeryCritical(value)
on error goto 0
' do something very critical here
on error resume next ' hopefully the last guy wanted this
end function

The biggest trouble with “resume next” model was simple syntax errors, mostly typos, thanks to dynamic-typing. I could only figure them out when I actually tested the web page. VBScript didn’t have a nice IDE, just some text editors with syntax highlighting. You didn’t know if the variable name was correct or not. Had you ignored the errors, you couldn’t even tell if there was a problem because that part was simply not rendered. Was it because of an error, or a simple decision? If I didn’t ignore the errors, whole page would break because of a key I pressed accidentally.

In dynamically-typed programming languages with loose error handling, the impact of a simple typo can be catastrophic. At the same time it takes to test that it doesn’t exist is unreasonably long and boring.

Developing Fast Web Applications

I like C# because it feels like what Java should have been from the start. A nice standard library, properties, async, lambdas, LINQ, fast JIT, a state of the art garbage collector. All the good stuff, and both statically-typed and strongly-typed too.

Static-typing is a very good deal. You sacrifice one “compilation” time on your code and suddenly you get all these advantages: faster code, early detection of type incompatibilities, and no typos! Damn I hate typos. Actually I should define “statically-typed” like that in The Straightforward Encyclopedia of Programming:

Statically-typed (concept)
A programming language that is fast and typos are no longer an issue.

C# has been a great language for Windows development for sometime but not so much for web. That’s mostly because of ASP.NET WebForm’s development model. It involved a set of custom components, a domain-specific HTML-like language, and a UI programming model adapted from desktop programming that you had to learn, in addition to HTML, CSS and JavaScript. I’m sure ASP.NET WebForm has seen popular days too but it’s not suitable for web at all.

Luckily, in the year 2009, ASP.NET MVC Framework was released. It’s an entirely different beast albeit a smaller one. It is a model-view-controller mechanism based on what Ruby On Rails introduced. Since its name is too long, I dropped its parts over the years, first “ASP”, then “Framework”. I mostly call it just .NET MVC nowadays.

I like .NET MVC and what it evolves to be. It is steadily turning into a feasible cross-platform technology. It has been running our social platform Ekşi Sözlük on a handful of servers for years, serving about 350 million page views monthly.

But…

That’s not enough!

Did I mention that I did not like typos? One of the downsides of .NET MVC is that it brings several weakly-typed constructs into the web development workflow. Those are:

Route mapping

MVC approach cleverly decouples how your URLs look and how you access them. That way changing a URL-scheme on your web app does not break existing code that needs to produce a version of it. The mapping between a URL and your controllers are called “routing”. You don’t need to remember exact URL layout.

Instead of:

<a href="/some/url/to/my/action">link</a>

You would write:

<a href="@Url.Action("Action", "Controller")">link</a>

So the URL becomes whatever route the method was mapped to. You only had to know which controller and action you had to refer. Your action would look like this:

public class Controller
{
public ActionResult Action()
{
// important stuff
}
}

Basically and strings would refer to the method and the class name respectively. But why do we need to pass them in strings. What if someone, accidentally, makes a .. t y p o?

.NET MVC developers had thought about that and introduced lambda expressions in its early releases. If you made a typo, the compiler would stop with an error. If I remember correctly the syntax looked something like this:

<a href="@Url.Action<Controller>((c) => c.Action())">link</a>

You would pass an expression to specify the action method. Differently from lambdas, expressions are just a tree representation of the code than the runnable code itself. Apparently the repetitive traversal of expression tree involved too much overhead and caching wasn’t possible so they dropped the feature in initial releases.

Fortunately someone created a T4 template solution called T4MVC that converts expressions to controller and action names during compile time. It requires an additional template pass over the compilation so it’s not the fastest solution and configuration can be tricky for customized MVC layouts. I would definitely prefer an out-of-the-box solution to my typo problem.

ViewData

In an MVC architecture the “model” represents the objects you use to pass the data around. When you submit a form the data comes to your controller action in a “model”. When you display a table of values they are passed to the view in a “model”. Because the same term was used for both, programmers also tend to use the same object for both.

The reuse of model objects created a new problem. What if I needed one tiny bit additional but irrelevant data in a view? Say I wanted to show number of unread messages, in addition to whatever I’m displaying. I cannot put it into an existing model of “UserRegistrationForm”. Unread messages makes no sense there.

The correct way is that you create a new model class, which is colloquially called a “ViewModel” and pass the additional data in it along with the existing model. Strongly-typed, perfect, no typos. But we know that like users, programmers tend to take the shorter path too:

Image for post
Image for post

The shorter path here is the construct called “ViewData”. ViewData is a dictionary that you can add anything in it that you like. So you wanted to pass “UnreadMessages” to your view? You would do this in your action method:

public ActionResult Action()
{
var model = ...
ViewData["UnreadMessages"] = unreadMessageCount;
return View(model);
}

In your view you would access the data the same way:

<span class="unread">@ViewData["UnreadMessages"]</span>

As you guessed, any typo would leave the field blank, like VBScript with enabled. Feel the wind of 1999 on your face, when Californication was a hit and airports were quite nice.

ViewBag

MVC team had thought that had been too hard on developers and wanted to make it shorter, so they created ViewBag. ViewBag is analogous to ViewData. Whatever you add to ViewData you can read it from ViewBag and vice versa. But it’s a dynamic object, which The Straightforward Encyclopedia of Programming describes as:

Dynamic object (object type)
An object that doesn’t care about types, compilers or you.

So you access ViewBag’s members like a regular object:

ViewBag.UnreadMessages

But it means nothing. It’s just for programmers who cannot be bothered to type brackets and double-quotes together. Had you made a typo, the compiler wouldn’t know about it. It couldn’t warn you. And differently from ViewData you wouldn’t even know that the compiler wouldn’t know. Because it looks exactly like a strongly-typed object!

ViewBag isn’t only bad because it is a weakly-typed, dictionary-like construct but also because dynamic object access is slower than a regular dictionary access too. It’s slow, innocuous-looking, evil brother of ViewData.

Anonymous Objects

Actually these are the better cousins of dynamic objects used in .NET MVC. Anonymous objects are strongly-typed and used to pass key/value pairs without needing to create an elaborate dictionary or a new class. Let’s say you need to pass HTML attributes to a link:

@Html.ActionLink("caption", "Action", "Controller", 
new { style="display:none" })

If you didn’t use anonymous object, you had to resort to:

@Html.ActionLink("caption", "Action", "Controller",
new Dictionary<string, string>()
{
{ "style", "display:none" }
})

Anonymous object version is much shorter isn’t it? They are called anonymous because their underlying types are given an obscure name by the compiler during compilation. Because they aren’t named until then you cannot reuse those types and access their members directly, only using reflection during runtime.

I’m okay with them because they don’t look like they are strongly typed in the first place. They cannot be reused or accessed anywhere else. Perfect for single shot uses. You don’t need Dictionary object’s fast accesses either because the contents are only enumerated.

Embrace your strength

There are many mature MVC frameworks on weakly-typed languages like PHP, Python, Ruby, etc. Strongly-typed languages like Go and Crystal show promising performance but lack easy to use high-level frameworks.

Let me remind you that compilation-phase to ensure strong-typing takes away niceties of a dynamic, weakly-typed environment, namely faster deployment, smooth learning curve, quick prototyping, faster edit and run cycles. .NET MVC needs to make up for them.

The framework is at the beginning of a new phase of its evolution, previously called ASP.NET MVC vNext and now ASP.NET Core MVC, the cross-platform alternative. I think it’s going to be the standard in a couple of years and we’re all going to forget that a standalone Windows version existed.

That provides an opportunity for .NET MVC team to grasp onto its strongly-typed roots. My three wishes for .NET MVC team’s genie are:

  • Scrap ViewBag. This should be the topmost priority as it currently hurts the development cycle the most.
  • Keep ViewData as it serves a practical purpose. I wish I could come up with an equally straightforward and strongly-typed alternative but I am okay with it being explicitly and visibly weakly-typed unlike ViewBag.
  • Abolish weakly-typed route mapping syntax. Make it strongly-typed without the need for a template pass.

Developers, Developers, Developers

Image for post
Image for post
That’s how you unroll loops

I suggest web developers who are using .NET MVC opt-for ViewData in place of ViewBag. You can even implement properties in a RazorViewBase derivative which wrap-around access to ViewData to make things strongly-typed on the view side at least. If you can’t do that just collect all the ViewData items in a single class and access it through a single key. That would reduce the possibility of a typo. If that sounds like a chore, stick to ViewData itself. For strongly-typed routing give T4MVC a shot. See if its overhead on compilation is acceptable.

Remember that these investments have lingering benefits. Your grand kids will thank you for them. They will still hate you for destroying the global climate though so let’s just call it a consolation prize

Writing Street Coder (https://www.manning.com/books/street-coder) · Ex-Software Engineer at Microsoft · Founder of eksisozluk.com · Demoscene old-timer

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store