Sharing code between ASP.NET and ASP.NET Core

Ken Schlobohm

With the release of .NET 6 there are even more benefits to using ASP.NET Core. But migrating existing code to ASP.NET Core often sounds like a big investment. Today we’ll share how you can accelerate the migration to ASP.NET Core. There are minor changes you can make today that can make it easier to migrate to ASP.NET Core tomorrow.

Before we begin let’s talk about a real scenario. Let’s talk about how to modify code in a 10-year-old application so that it can be shared with ASP.NET Core. In the next sections we’ll give samples that migrate the ShoppingCartController.cs from the MVC Music Store app that was used to demo ASP.NET MVC3.

The first step to migrating this web app is to create a new ASP.NET Core Web App (Model-View-Controller) project. This template will add support for Controllers and map the default route for Controllers in the Program.cs file. Once we have the new project setup, we’ll remove the default HomeController and the view files for Home/Index and Home/Privacy so we can share content from the MVC3 Music Store web app without conflict.

You can share Controllers

The first thing you can share between the two projects is Controllers. Many teams want the new website to work the same as the current one. And when we say “the same” we mean “the same”. If you fix a bug in one project, then you need that same fix to show up in both sites. One of the easiest ways to assure this behavior is to share the same file in both projects. Luckily ASP.NET Core uses the new SDK style project files. That means it’s easy to open the csproj file and add some changes because the files are very readable.

To start sharing a Controller class you’ll need to create an <ItemGroup> and add a reference to the existing class. Here’s a sample that shows how to share the ShoppingCartController.cs by updating the csproj file of the ASP.NET Core project.

    <ItemGroup>
        <Compile Include="..MvcMusicStoreControllersShoppingCartController.cs" LinkBase="Controllers" />
    </ItemGroup>

Okay, now the file is included in the project but you may have guessed that the ASP.NET Core project doesn’t compile anymore. In ASP.NET Core the Controller class doesn’t use System.Web.Mvc it uses Microsoft.AspNetCore.Mvc.

Here’s a sample that shows how the ShoppingCartController.cs can use both namespaces to fix that compiler error.

#if NET
using Microsoft.AspNetCore.Mvc;
#else
using System.Web.Mvc;
#endif

There are other places in the ShoppingCartController that would need to be updated but the approach is the same. Using C# preprocessor directives we can make the class flexible enough to compile for both projects.

For scenarios with large sections of code that work differently for ASP.NET Core you may want to create implementation specific files. A good approach is to create a partial class and extract those code blocks to new method(s) that are different between the two web app targets and use the csproj to control which files are included when building the project.

You can share Models

Now that we can share Controllers we’ll want to share the Models they return. In many scenarios this will just start working when we include them by adding another <ItemGroup> to the csproj file. But if your models also reference System.Web then we can use the same approach we just used for Controllers. Start by updating the namespaces so that the same class file can exist in both projects. Keep using the C# precompiler directives to add ASP.NET Core support.

Here’s a sample that shows how to modify the [Bind] attribute.

#if !NET
    [Bind(Exclude="OrderId")]
#endif
    public partial class Order
    {
        [ScaffoldColumn(false)]
#if NET
    [BindNever]
#endif
        publicintOrderId{ get; set; }
   …
   …

You can share Views

We can even share views. Using the same approach again we can edit the csproj file to share files like the _Layout.cshtml. And, inside the view you can keep using C# precompiler directives to make the file flexible enough to be used by both projects.

Here’s what it looks like to have a master page with mixed support for Child Actions from ASP.NET and View Components from ASP.NET Core so that we can render the part of the page that knows how many items are in the shopping cart.

@{
    #if NET
        <text>@awaitComponent.InvokeAsync("CartSummary")</text>
    #else
        @Html.RenderAction("CartSummary", "ShoppingCart");
    #endif
}

Wrapping up

The ability to share code also includes static content like CSS, JavaScript and images. Step-by-step you can build flexibility into your web app today to make your migration to ASP.NET Core easier.

If you would like more detailed guidance to migrate the entire ShoppingCartController.cs you can follow a full walkthrough with samples at MvcMusicStoreMigration. The walkthrough will also demonstrate how you can run both ASP.NET and ASP.NET Core from the same IIS Application Pool to incrementally migrate your web app one controller at a time.

For those planning to start work on their ASP.NET Core migration we’ll share a few more tips.

  • Upgrade your NuGet packages so you can use netstandard.
  • Change your class libraries to netstandard so you can share code between ASP.NET and ASP.NET Core.
  • Find references to System.Web in your class libraries build interfaces replace them. Use dependency injection so you can easily switch between ASP.NET and ASP.NET Core features.

You can also find more guidance from our docs at Migrate from ASP.NET to ASP.NET Core.

14 comments

Comments are closed. Login to edit/delete your existing comments

  • Patrick Klaeren

    I’m quite disappointed in the advice in this blog – this post promotes littering your codebase with conditional compilation which is not only (human) error prone but extremely laborious.

    Several things mentioned here would not only lead to large amounts of “sometimes .NET (Core), sometimes .NET Framework” but also lead to necessary code duplication. View components are favoured over RenderAction, for example.

    Being in the process of slowly migrating ASP.NET Framework MVC to ASP.NET Core MVC, I can tell you how we do things:
    – Make a new ASP.NET Core project
    – Pick a controller/action to migrate
    – Mirror controller/action in ASP.NET Core, refactoring to use brand new EF Core, C# vNext features and so on
    – Deprecate ASP.NET Framework variant of controller/action
    – Ensure route is retained to now point to ASP.NET Core

    I don’t recommend anyone follow the task of reusing the same controller in Framework and Core MVC.

    • Cory Crooks

      For this path, are you fronting both apps in IIS simultaneously, and dealing with routing at that level?

    • Danstur

      Agreed, I don’t understand the point of this exercise either.

      Sure you can compile a few controllers as both .NET Core and FX, but then what? You now have a mess of a project and you are still using just the old project in production so you’re definitely not going to find any problems until you actually make the switch.

      And then when you finally want to make the switch you then have to remove all the old netfx specific code.

      So my experience is pretty much the same as yours – moving single controller to a new net core only solution seems much more efficient than this.

  • JesperTreetop

    Include=”..MvcMusicStoreControllersShoppingCartController.cs”

    Looks like Wordрress is being Wordрress once again. This seems to happen on many posts and isn’t very good for things you’re supposed to copy-and-paste.

  • Mirza Shahzad

    Very nice article but i think there should be more details and code to support this blog post.

    By the way i am using second point from your given tips.

    Change your class libraries to netstandard so you can share code between ASP.NET and ASP.NET Core

    We are using reusable packages that we build in .NET standard 2.0 to support .NET Framework 4.8 and .NET Core 3.1 because our most of the apps are in .NET Framework and for new projects we are using .NET Core 3.1 so same code base will be used between both projects. Instead of having in preprocessor inside project we keep it inside the .NET standard library to make project more cleaner and focused on the business layer only instead of project base e.g. EF6 and EF Core for database handling

  • Josh H

    I agree with most of the sentiment of the other comments. It’s clear that Microsoft is trying to help us migrate and that is a good thing.

    Since there are obviously detailed steps of known issues and things to watch for… Why not automate all the insertion of the precondions for us automatically? If you can do that so the code can be kept clean, I would be willing to proceed with the other manual steps.

  • Beau Claar

    This is awesome and all but it’s not an issue with CORE or converting that is keeping us from doing it (large enterprise applications). It is LTS timeframe. We have 10 years on a .NET Framework release on an OS but only 3 with a CORE LTS. We have a shop that has a few large applications but hundreds of smaller web applications that do not share similar information to support.

    …CORE LTS is our problem.

    • Jorge Morales Vidal

      Maybe your concern is about getting official Microsoft support when things go wrong? As far as I remember, in the old times, getting an issue fixed in the old .NET Framework required waiting for several months or years to get a new update through Windows Update or maybe in a new .NET Framework. With .NET Core, .NET 5 and .NET 6, those fixes now appear in weeks or months at most, and the discussion is in the open, in GitHub.

      So I think your problem is not technical related (as upgrading from .NET Core 3.1 to .NET 6 is as easy as updating some properties in the csproj file + upgrading NuGet packages). Could you explain why the short timeframe of 3 years is a big problem in your case?

  • Keith Jackson

    As with Patrick’s comment, I felt I had to write back to this.

    This is awful architectural advice and bad software engineering; I can see a niche use case for this but it adds a level of complexity and complication that you really don’t want in your solution.

    I would advise splitting as much code as you can (except controllers) out of your web project, building a new .net Core / .net 6 web project and moving elements over rewriting as you go.

    Bear in mind the lifespan of your web project as well here.

  • Jiří Zídek

    We have done migration of ASP.NET part this way and important things are
    a) ASP.NET is the easiest part in fact and you can keep parallel dev here
    b) I depends how your 10 years-old-app has been “modern” that time, if you used different paradigm how to separate DB/Logic/Server/Presentation parts, it might be unfeasible; for our WebAPI+ReactJS it was not difficult, since we used quite new WebAPI returning directly Poco
    c) For logic part we used .NET Standard 2.0 approach quite successfully
    d) Most tough was transformation of DB part, since historically we were using Linq2Sql. We went DevArt way, but it was a U-turn, since we still faced backwards incompatibility and memory leaks, so finally it end-up by discontinuing parallel development of this part (which is 70% of app) and effectively it killed old code development.
    Parallel development took more then year and now being just on .NET 6 is like throwing away FFP2 mask !

  • Rajesh Aravapalli

    Does this solution is good enough to come to Microsoft dev blogs? I am disappointed with this blog post which resembles me shiny title for youtube videos to get views.

  • Patrick Patrick

    Bonjour
    Je développe pour l’instant avec ASPNET j’envisage par la suite de migrer vers ASPNET core.
    Pour l’instant je rencontre le problème de “page blanche” lorsque je veux utiliser les modèles ASPNET Crystal Reporting livrés que ce soit avec Visual Studio professionnel 2019 (dont j’ai acheté une licence) où avec VS2017 community essential . (que ma table fasse partie d’une base Access ou Sqlserver).
    Je ne sais pas où poser cette question ?
    D’avance merci
    Patrick – Développeur passionné
    psevry@deltanove.fr