What’s Old is New Again – Web Forms meets Blazor
Tags: aspnet, dotnet, blazor
Published: 2020-01-06 21:08:34

---
title: What’s Old is New Again – Web Forms meets Blazor
published: true
date: 2020-01-06 20:55:15 UTC
tags: ASP.NET, dotnet, blazor
canonical_url: https://jeffreyfritz.com/2020/01/whats-old-is-new-again-web-forms-meets-blazor/
---

![](https://jeffreyfritz.com/wp-content/uploads/2020/01/20190507_000103550_iOS.jpg)<figcaption>BLAZOR!</figcaption>

I live for these types of conversations: “Hey, is there a way to upgrade my application to the new framework?” The answer is almost ALWAYS no, because the person asking me has already searched the web and is looking for some secret upgrade technique from me. This time, this conversation, well it was a bit more interesting.

“Hey Jeff, Blazor Server-Side and ASP.NET Web Forms are pretty similar in concepts. They both render code on the server and both have a component-based model. Is there a way we could somehow re-use markup between the two frameworks?” That question not only got my interest, but also started some interest with my colleague Dan Roth. We were planning to go on stage at Microsoft Ignite 2019 and talk about Blazor for Web Form developers… when Dan had the idea: “What if we had a shim, a component library that LOOKED and rendered HTML like the original ASP.NET controls? That could help with migration.”

## The Concept

The idea is simple: ASP.NET Web Forms is not available to develop with .NET Core, but Blazor is. _What if we could make it as simple as possible to copy your ASPX markup into a Blazor project and get the same markup delivered to the browser?_ We don’t want to enable developers to continue to develop with the same model, but to get their applications using the same UI, the same presentation that they’ve been using for years and a path forward. That is the goal.

This would require some components, some shims and maybe some trickery to make the default components from the Web Forms framework work. With that, we set out to try to make something simple as a proof of concept.

## The Proof of Concept

{% youtube 0bQi4tkD3Ck %}
<figcaption> Dan and I talk about the Blazor framework and what it means for Web Forms developers in a segment starting at 2:03:00 from Microsoft Ignite Live 2019 </figcaption>

There are MILLIONS of ASP.NET Web Forms applications out there, and in our sample we showed an application with a few controls in use, but targeted this implementation [(original source available)](https://github.com/csharpfritz/eShopBlazor/blob/finished_demo/src/eShopLegacyWebForms/Default.aspx):

```
<asp:ListView ID="productList" runat="server" 
    ItemPlaceholderID="itemPlaceHolder" ItemType="eShopLib.CatalogItem">
    <EmptyDataTemplate>
        <table>
            <tr>
                <td>No data was returned.</td>
            </tr>
        </table>
    </EmptyDataTemplate>
    <LayoutTemplate>
        <table class="table">
            <thead>
                <tr class="esh-table-header">
                    <th></th>
                    <th>Name</th>
                    <!-- SNIP -->
                </tr>
            </thead>
            <tbody>
                <asp:PlaceHolder runat="server" ID="itemPlaceHolder"></asp:PlaceHolder>
            </tbody>
        </table>
    </LayoutTemplate>
    <ItemTemplate>
        <tr>
            <td>
                <image class="esh-thumbnail" src='/Pics/<%#:Item.PictureFileName%>' />
            </td>
            <td><%#:Item.Name%></td>
            <!-- SNIP -->
        </tr>
    </ItemTemplate>
</asp:ListView>
```

This is a `ListView` being used to present a table of products with Edit, Details, and Delete links on the side. (For this article, I’ve trimmed the width of the table for readability.) Dan replicated the capabilities of this control using a custom Blazor component, also called `ListView` and we used this code to present the same UI but with Blazor [(original source)](https://github.com/csharpfritz/eShopBlazor/blob/finished_demo/src/eShopOnBlazor/Pages/Index.razor):

```
<ListView Items="Model.Data" TItem="CatalogItem">
    <EmptyDataTemplate>
        <tr>
            <td>No data was returned.</td>
        </tr>
    </EmptyDataTemplate>
    <TableHeader>
        <tr class="esh-table-header">
            <th></th>
            <th>Name</th>
            <!-- SNIP -->
        </tr>
    </TableHeader>
    <RowTemplate Context="catalogItem">
        <tr>
            <td>
                <img class="esh-thumbnail" src="@($"/Pics/{catalogItem.PictureFileName}")">
            </td>
            <td>
                <p>@catalogItem.Name</p>
            </td>
            <!-- SNIP -->
        </tr>
    </RowTemplate>
</ListView>
```

The tags are similar, the inner templates behave the same but have different names, and the formatting of the content inside the templates is _ALMOST_ identical save for the change from `<% %>` notation to `@( )`

## What If…

What if we could make this conversion even closer? I took some next steps and improved the capabilities of the `ListView` component so that we could now have this code output the same content as above:

```
<table class="table">
    <thead>
        <tr class="esh-table-header">
            <th></th>
            <th>Name</th>
            <!-- SNIP -->
        </tr>
    </thead>
    <tbody>
      <ListView @ref="productList" runat="server" Context="Item"
          ItemPlaceholderID="itemPlaceHolder" ItemType="eShopLib.CatalogItem">
          <EmptyDataTemplate>
                  <tr>
                      <td>No data was returned.</td>
                  </tr>
          </EmptyDataTemplate>
          <ItemTemplate>
              <tr>
                  <td>
                      <image class="esh-thumbnail" src='/Pics/@Item.PictureFileName' />
                  </td>
                  <td>@Item.Name</td>
                  <!-- SNIP -->
              </tr>
          </ItemTemplate>
      </ListView>
    </tbody>
</table>
```

Now we’re talking! By moving the `LayoutTemplate` content outside the `ListView` component, the rest of the `ItemTemplate` looks very similar. Almost all of the attributes on the `ListView` component are the SAME, with the only exception is the id attribute being renamed to `@ref`. The only addition is the `Context` attribute so that the `Item` object could be used in our templates.

## What Next?

We think there’s an opportunity to make open source components to help facilitate this type of copy and paste conversion from simple Web Forms and controls. We’re just at the beginning of this process, but have opened a [project on GitHub](https://github.com/FritzAndFriends/BlazorWebFormsComponents) to analyze and work through these controls. This is NOT a Microsoft supported project, but rather a concept that I and my community of friends are working through to see what benefit it could have.

I have been diligently working on these components live on [my Twitch stream](https://twitch.tv/csharpfritz), and have taken time off camera to work on documentation, samples, and some general clean up work.

The `LiveView`, `Repeater`, and `DataList` are all under construction as of the writing of this article. Simple ModelBinding to read and present data, data binding by specifying a `DataSource` all works with these controls. We’ve even added obsolete warnings if you copy over code that contains `ViewState` or `runat="server"` references.

The components are packaged using [Azure DevOps](https://dev.azure.com/FritzAndFriends/BlazorWebFormsComponents) and deployed [NuGet as the Fritz.BlazorWebFormsComponents package](https://www.nuget.org/packages/Fritz.BlazorWebFormsComponents) If this is something that you are interested in seeing grow and give these older applications new life, please open some issues or send a pull request.