Search code examples
asp.net-coreiis.net-coreasp.net-core-3.1self-contained

Can an ASP.NET Core v3.1 app really be self contained?


I have a server that currently hosts many .net core v2 services in IIS.

I had a to make a new service. Normally I would just use whatever runtime the server has installed, but I thought, ".Net Core can deploy self contained applications, so I can have v2 services side by side with v3 ones."

I am worried I was wrong.

When I run my self contained application, it gives the following error:

Handler "aspNetCore" has a bad module "AspNetCoreModuleV2" in its module list.

When I look this up I find, that I will need to install the hosting bundle. Which when you go to the .net core site that has it, it shows as the recommended install method for .Net Core (on IIS Machines).

This is where I am starting to get worried. I thought I did not have to install .net core 3 on my server. I thought I could run a self contained application.

I can't install .Net Core v3 without testing that all the existing services that target .Net Core v2 work fine on the .Net Core v3 runtime.

So, it is looking like I will have to go downgrade my service to v2 (yuck, I hate working to go backwards.)

But before I do it, I thought I would ask:
Is there anyway to host an Asp.Net Core v3 Web API service on IIS that only has the .Net Core v2 runtime on it?


Solution

  • Which runtime version to use is defined by your project file, so different runtimes can run in same machine without any issue. Let's say, for instance you have two services: Service1 is built using .net core 2.1 and Service2 is build with .net core 3.1. The project files will look like this:

    Service1.csproj

    <Project Sdk="Microsoft.NET.Sdk.Web">
    
      <PropertyGroup>
        <TargetFramework>netcoreapp2.1</TargetFramework>
      </PropertyGroup>
    

    Service2.csproj

    <Project Sdk="Microsoft.NET.Sdk.Web">
    
      <PropertyGroup>
        <TargetFramework>netcoreapp3.1</TargetFramework>
      </PropertyGroup>
    

    Once you run your application via dotnet run or dotnet ServiceX.dll, the dotnet executable is the host of the application, and selects the correct runtime based on the assembly metadata. The runtime to use is actually written in the compiled DLL.

    Therefore, 2.* and 3.* application can totally coexist in the same machine, provided the required runtimes are installed.

    Read more here: https://learn.microsoft.com/en-us/dotnet/core/versions/selection

    Check this experiment out. On my machine have the following installed: 1) Asp.Net Core Runtime 2.1.14 2) Asp.Net Core Runtime 3.1.2 3) IIS 10.0 4) Asp.Net Core Module (installed with hosting bundle)

    I created 2 applications, one for each runtime:

    dotnet new web -f netcoreapp2.1 -o Service1
    

    and

    dotnet new web -f netcoreapp3.1 -o Service2
    

    I then modified both application Startup.cs like this:

        public class Startup
        {
            public void Configure(IApplicationBuilder app)
            {
                app.Run(async context =>
                {
                    var framework = Assembly
                        .GetEntryAssembly()?
                        .GetCustomAttribute<TargetFrameworkAttribute>()?
                        .FrameworkName;
                    var taskLocation = typeof(Task).Assembly.Location;
                    await context.Response.WriteAsync($@"Hello World from {framework}
    Location of Task assembly: {taskLocation}.
                    ");
                });
            }
        }
    

    I published both services in release: Service1: C:\Users\info\source\repos\Service1> dotnet publish -c Release Microsoft (R) Build Engine version 16.4.0+e901037fe for .NET Core Copyright (C) Microsoft Corporation. All rights reserved.

      Restore completed in 159,32 ms for C:\Users\info\source\repos\Service1\Service1.csproj.
      Service1 -> C:\Users\info\source\repos\Service1\bin\Release\netcoreapp2.1\Service1.dll
      Service1 -> C:\Users\info\source\repos\Service1\bin\Release\netcoreapp2.1\publish\
    

    Service2:

    C:\Users\info\source\repos\Service2> dotnet publish -c Release
    Microsoft (R) Build Engine version 16.4.0+e901037fe for .NET Core
    Copyright (C) Microsoft Corporation. All rights reserved.
    
      Restore completed in 41,98 ms for C:\Users\info\source\repos\Service2\Service2.csproj.
      Service2 -> C:\Users\info\source\repos\Service2\bin\Release\netcoreapp3.1\Service2.dll
      Service2 -> C:\Users\info\source\repos\Service2\bin\Release\netcoreapp3.1\publish\
    

    Under IIS I created two website, one for each service, each pointing at the right output directory

    service1.lvh.me >>> C:\Users\info\source\repos\Service1\bin\Release\netcoreapp2.1\publish\
    
    service2.lvh.me >>> C:\Users\info\source\repos\Service2\bin\Release\netcoreapp3.1\publish\
    

    I then visited each website. Visiting service1.lvh.me I got: enter image description here and visiting service2.lvh.me I got: enter image description here

    As you can see each application is requiring the correct version of the framework, and framework types are loaded from specific folders.

    There is therefore no problem to have different versions of .net core framework running on the same machine, and web applications running over specific version on the same IIS.