Maintaining Scaffolded Code: A Case Study with Asp.Net Core Identity UI

David W. Gray
7 min readOct 30, 2023

--

I am fundamentally a lazy programmer. This is a good thing. Re-inventing the wheel is not something that holds any appeal for me, although I have worked with quite a few people (including past versions of myself) who have some version of “not invented here” (NIH) syndrome. So, I will use libraries and other tools to solve problems whenever possible.

The problem with Scaffolding

That said, one of my least favorite variations on code reuse is the concept of scaffolding. This is the concept of having a tool generate the code and configuration to implement a project or feature, but then the consumer of that code is responsible for it moving forward. The place where you most likely have seen this used is in initial project generation. For instance, typing npx create-react-app my-appto generate a React app would “scaffold” the application by creating all the code and project files to produce a starter React app. After the initial scaffolding, you are responsible for changing and maintaining that code. There are a lot of good reasons to do this. It gives the programmer the maximum amount of flexibility to move things forward. And any boilerplate code can be part of the template for the scaffolding. But what happens if there is a significant update to the underlying framework, such that the scaffolded code no longer works? You have to either figure out what has changed in the scaffolded code or re-scaffold your application and re-apply all your changes.

In the case of project scaffolding for things like React or ASP.NET applications, there is generally a well-documented release history that includes a migration guide with step-by-step instructions for how to update the scaffolded code. As long as I keep on top of upgrading, I’ve found this to be the easiest way to keep up with changes. However, when the owner of the scaffolding isn’t kind enough to provide sufficiently detailed instructions, there are other ways to go about this process.

I will use ASP.NET Core Identity UI as a concrete example since I just had to do this (again), but the techniques should apply to most scaffolded code. For my project, I upgraded from ASP.NET core 5 through 6 and 7 without noticing any issues and without re-scaffolding. However, I am migrating the entire site from Bootstrap 4 to Bootstrap 5, which is tightly tied into the scaffolded code. So I checked and found Microsoft’s documentation on the change, which showed you how to continue using Bootstrap 4 (which I was already doing) or pointed you to the Bootstrap 5 migration guide to help you figure out how to fix the scaffolded code yourself.

A General Solution

Did I mention that I’m lazy? I do not want to go through and figure out which styles to apply to every tag in thousand¹ lines of code, especially if someone has already done the work. So, how do I easily leverage the fact that Microsoft has updated the scaffolding to reflect Bootstrap 5 changes? The simple answer is to scaffold a new app and diff the changes between the new and the old. It gets slightly more complicated in that I want the scaffolded code to only be different in the important ways and not in things like namespaces and class names specific to my project.

The general method is:

  1. Follow the frameworks’ instructions to scaffold a new project or feature
  2. Make sure to use the same options and names of projects, classes, and namespaces as your original project. If you don’t have good notes on the original run of the scaffolding tool, this can be a bit hit and miss.
  3. Iterate as necessary until your new project/feature matches the old one as closely as possible.

At this point, you should have a project with the current version of the scaffolding where all of the project, class, and namespaces are lined up with my original project. So all you have to do is run a diffing tool on the two directories, and you can see just the things that are different between the two projects. Those changes are either customizations you’ve made to the original scaffolding or migrations from the version that you used to the current version. A good diffing tool will let you move the scaffolding changes from the new scaffolding to the current version of the project, either by the file for files where you didn’t do customizations or by block in places where you did.

A Specific Example Using ASP.NET Core Identity UI

For the Asp.Net Core Identity UI case I:

  1. Followed Microsoft’s documentation to scaffold a new application, taking care to name the project exactly the same as the one I want to compare it to (including case).
  2. Before the “Apply Migrations” step, which is where you run the code for the first time to generate the database I:
    - Replaced all occurrences of IdentityUser with whatever your User class is; in my case, this is ApplicationUser.
    - Created a dummy user class (in my case, ApplicationUser), which derives from IdentityUser, and made sure that it is in the same namespace as in the original project.
    - Refactored ApplicationDbContext (which derives from IdentityDbContext) to the name of the DbContext class that contains your Identity
  3. At this point, I continued with the Apply Migrations, scaffolded the identity framework pages, and ran the app to see that it was doing what I expected. And yes, I can register a new user, etc.

I then ran the Visual Studio Code extension Diff Folders on the relevant subdirectories (project\Areas\Identity\Pages) and was able to quickly port over the new code, which consisted of a bunch of comments and the Bootstrap 5 implementation.

Variation 1: Using a base from your project’s history

What if I am working on a larger project and I’m not the one who made all of the customizations? If I’m lucky, I can find the point in my source control history where the developer checked in the original scaffolding. Then, I can revert a local version of the project to that point and DIFF it with my newly scaffolded project. That will give me just the changes to the scaffolding, which I can then apply to the current version of my project. I’d probably do that by having two versions of the project on my machine: the reverted version and the current version. This is effectively doing a three way merge with my reverted project as the base. I haven’t done three-way merges outside of the context of integration with source control recently, so I don’t have a current recommendation for a tool if you need to go down this path, but I have used Beyond Compare Pro to do similar merges in the past.

Variation 2: Thinking Ahead

Another variation on this technique would be to save the small project that I just created somewhere that I could find the next time I need to do this upgrade. That would act as a base for a three-way diff between the next version of the scaffolding and whatever my project is at that time. But possibly more importantly, it gives me a really easy way to show me what my customizations are.

Variation 3: Generating Scaffolding Twice

A final small variation is that it’s often possible to generate the scaffolding for the version that you used originally. Then you can use that as a base for a three-way merge. This works well if you didn’t have the foresight to save a snapshot of your original scaffolding or if your team didn’t check in a clean change when they did the original scaffolding. It also has the advantage that you’ll be scaffolding two versions at the same time, so you can easily line up the options to give a clean DIFF. In fact, you can even get a good sense of what changed between the versions without going to the trouble of matching names with your current code. You won’t be able to use that as a base in an automated three-way merge, but it has all the other advantages of the techniques described above.

Conclusions

Once I made it through all of the above, I realized that the current version of the ASP.NET templates still uses jQuery validate for forms validation. Which means I still need to pull in jQuery. That’s a pain since part of the motivation for updating to Bootstrap 5 is to eliminate the jQuery dependency. If I figure out a way around that, I’ll post a solution.²

In the meantime, I hope you find the general techniques I presented here useful, and if anyone else is struggling with keeping Asp.Net core identity UI up-to-date and has a better solution, please let me know.

¹ After I got done with this project, I decided to take a quick look at the numbers. I used VS Code Counter to count the number of lines in the generated pages directory the results were 72 files, 3019 code, 603 comment, 519 blank, 4141 total so I wasn’t exaggerating the task.

² I really don’t want to be in charge of maintaining user accounts for my website, so I am looking into other solutions that would get me completely away from this batch of scaffolded code, but I don’t want to block my general site upgrade on landing on a solution to this specific problem and variations on this technique have served me well for over a decade of upgrades on this particular codebase.

--

--

David W. Gray

I am a software engineer, mentor, and dancer. I'm also passionate about speculative fiction, music, climate justice, and disability rights.