From WebForms to MVC, the first 10 minutes
June 26, 2018 · 6 minute read
What’s this? A post about WebForms?
Is it 2002 all over again? Is GeoCities still going strong? Are we all about to invest endless hours building SOAP services and learning XML?
No, no we’re not.
But, just because it feels like everyone is off building shiny new apps using ASP.NET Core 2.x the truth is there are still plenty of us spending at least some of our days working with “legacy” (and sometimes not so legacy) apps built using WebForms.
And if you’re trying to move to something else at this moment in time you’d be forgiven for feeling overwhelmed.
The web is awash with information covering every topic you could possibly imagine (and then some)…
- SPAs (Angular, React etc)
- MVC 5
- MVC Core
- Razor Pages
- .NET Framework
- .NET Core
Where do you start?
We’ve got to start somewhere so let’s begin with performing a common WebForms task using ASP.NET Core MVC…
If you’re new to MVC you could be forgiven for feeling confused.
There’s a lot of terminology to get to grips with, where Webforms had one or two moving parts MVC has several.
But when you take a step back and explore what WebForms is doing under the hood it becomes easier to translate that to MVC.
Change label text via a Postback
WebForms did its best to act like a Windows app which happened to run in the browser but in reality it uses a little smoke and mirrors to hide what it’s actually up to.
Here’s an example.
Create a page with your button and label, something like this…
<form id="form1" runat="server">
<div>
<asp:Button ID="btnChangeLabel" runat="server"
OnClick="btnChangeLabel_Click"
Text="Boring, give me another greeting" />
<asp:Label ID="lblGreeting" runat="server">
Welcome one and all
</asp:Label>
</div>
</form>
Create a handler to handle the button click event, set the new property value for the label and voila, the label is updated when you click the button.
protected void btnChangeLabel_Click(object sender, EventArgs e)
{
this.lblGreeting.Text = "Hello, this is the changed greeting :-)";
}
Unpicking the abstraction
This might look and feel like a windows app running on the desktop but “under the hood” ASP.NET is simply making GET and POST requests from the browser to the server.
Yep, it’s doing exactly what every other web application ever written does, make requests to the server.
Here’s what’s actually happening.
You request /SimpleLabel in the browser
Your browser makes an HTTP GET request
ASP.NET handles the GET request and routes to the corresponding WebForm (SimpleLabel.aspx)
ASP.NET renders html for the label/button controls and returns it to the browser
The rendered html includes a form which will be submitted when the button is clicked
You click the button
The browser makes an HTTP POST request to the server (submits the form)
The "btnChangeLabel_Click" event handler runs, changing the label's text
ASP.NET re-renders the html (with the new value for the label) and returns it to the browser
You see the new value in the browser
So you see, it’s not actually magic, just an HTTP GET and an HTTP POST.
How does MVC do it?
Now let’s take the exact same requirement and do it with MVC.
The main difference is that you are no longer quite so abstracted away from the HTTP requests and HTML markup that your app is ultimately going to use.
Instead of a WebForm with ASP.NET controls, you need a view with (mostly) standard HTML tags.
Index.cshtml
@model SimpleLabelModel
<form method="post">
<input type="submit" value="Boring, give me another greeting" />
<span>@Model.Greeting</span>
</form>
The only non-html part of this markup is the first line and the subsequent reference to @Model.Greeting
which is Razor syntax to enable you to take data coming from the server and mix it up with your HTML.
Now we have our button and a greeting, but how do we get to this in a browser?
We can’t, not without a controller to handle requests (from the browser) to our application.
SimpleLabelController.cs
[Route("[controller]")]
public class SimpleLabelController : Controller
{
[HttpGet("")]
public IActionResult Get()
{
var model = new SimpleLabelModel { Greeting = "Welcome one and all" };
return View("Index", model);
}
}
Now we’re getting somewhere, a request to go to /simplelabel
in the browser will be routed to our Get
action where we return our view (index.cshtml).
We also return an instance of our view’s model (SimpleLabelModel) which (if you’re interested) looks like this.
SimpleLabelModel.cs
public class SimpleLabelModel
{
public string Greeting { get; set; }
}
Remember this line in the view?
<span>@Model.Greeting</span>
That ensures the value we just set in the Model (“Welcome one and all”) is displayed as a span in the rendered HTML.
Now what about handling that button click?
The button will submit the form, which will post back to /simple-label
but wait, we don’t have any controller action to handle it!
SimpleLabelController.cs
[Route("[controller]")]
public class SimpleLabelController : Controller
{
// GET method omitted for brevity
[HttpPost("")]
public IActionResult WelcomeMe()
{
var model = new SimpleLabelModel
{
Greeting = "Hello, this is the changed greeting :-)"
};
return View("Index", model);
}
}
And there you have it! Click the button, the browser submits the form (via a POST) and the corresponding controller action returns a new instance of the model with our new and improved greeting.
Putting it all together
Here’s the MVC flow then…
You request /SimpleLabel in the browser
Your browser makes an HTTP GET request
ASP.NET handles the GET request and routes to the corresponding Controller Action
ASP.NET renders your html (mixing in values from the model via Razor) and returns it to the browser
The rendered html is the HTML from the view, with the "dynamic data" from the model included.
You click the button
The browser makes an HTTP POST request to the server (submits the form)
The relevant controller action (for the HTTP Post) is called
ASP.NET re-renders the html (with a different model containing a different greeting) and returns it to the browser
You see the new value in the browser
More moving parts
Looking back at this you can see that MVC requires you to handle more moving parts (controllers, views and view models).
But with this increased complexity you also get more freedom to craft your routes, your html, even to start adding javascript to your views where it improves the user experience.
Before you go
Get a handy PDF showing the two flows (WebForms and MVC) next to each other, plus source code for both examples.