dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.46k stars 10.03k forks source link

Minimal ASP.NET Core AoT Publish through Visual Studio Creates Broken EXE- Failed to load assembly 'Microsoft.AspNetCore' #50694

Open RyanLamansky opened 1 year ago

RyanLamansky commented 1 year ago

Is there an existing issue for this?

Describe the bug

When using Visual Studio (Microsoft Visual Studio Enterprise 2022 (64-bit) - Preview Version 17.8.0 Preview 1.0)'s "Publish" feature, I can't find a way to resolve a specific publish error--and resulting broken executable--regarding Microsoft.AspNetCore.

The exact error (the project is called AspAot):

ILC: Method '[AspAot]Program.<Main>$(string[])' will always throw because: Failed to load assembly 'Microsoft.AspNetCore'

Expected Behavior

No compiler warnings during publish and a working executable.

Steps To Reproduce

Code:

WebApplication.CreateSlimBuilder(); // Not a useful app but is all that's needed to get the error.

Project:

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <InvariantGlobalization>true</InvariantGlobalization>
    <PublishAot>true</PublishAot>
  </PropertyGroup>
</Project>

Exceptions (if any)

ILC: Method '[AspAot]Program.<Main>$(string[])' will always throw because: Failed to load assembly 'Microsoft.AspNetCore'

.NET Version

8.0.100-preview.7.23376.3

Anything else?

The command-line tools do not have this issue: dotnet publish -r win-x64 creates a working executable.

christiannagel commented 1 year ago

I have the same issue with dotnet publish in the WSL, without using Visual Studio: .NET version: 8.0.100-rc.1.23455.8

Start WSL - 2 (I'm using Ubuntu 22.04.2)

  1. dotnet new webapiaot -o test1
  2. Adding this to the csproj file
 <PropertyGroup>
    <ContainerRepository>test1</ContainerRepository>
    <ContainerImageTags>4.4.4;latest</ContainerImageTags>
  </PropertyGroup>
  1. dotnet publish test1.csproj --os linux --arch x64 /t:PublishContainer -c Release

This results in this output:

MSBuild version 17.8.0-preview-23418-03+0125fc9fb for .NET Determining projects to restore... Restored /mnt/c/temp/test1/test1.csproj (in 1.17 sec). /usr/share/dotnet/sdk/8.0.100-rc.1.23455.8/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.RuntimeIdentifierInference.targets(311,5): message NETSDK1057: You are using a preview version of .NET. See: https://aka.ms/dotnet-support-policy [/mnt/c/temp/test1/test1.csproj] test1 -> /mnt/c/temp/aot3/bin/Release/net8.0/linux-x64/test1.dll Generating native code ILC: Method '[test1]Program.

$(string[])' will always throw because: Failed to load assembly 'Microsoft.AspNetCore' test1 -> /mnt/c/temp/test1/bin/Release/net8.0/linux-x64/publish/ Building image 'test1' with tags 4.4.4,latest on top of base image mcr.microsoft.com/dotnet/aspnet:8.0.0-rc.1 Pushed image 'test1:4.4.4' to local registry Pushed image 'test1:latest' to local registry

Running the generated images results in:

Unhandled Exception: System.IO.FileNotFoundException: Could not find file 'Microsoft.AspNetCore'. File name: 'Microsoft.AspNetCore' at Internal.Runtime.TypeLoaderExceptionHelper.CreateFileNotFoundException(ExceptionStringID, String) + 0x4a at Internal.Runtime.CompilerHelpers.ThrowHelpers.ThrowFileNotFoundException(ExceptionStringID, String) + 0x6 at Program.

$(String[] args) + 0x12 at test1!+0x1d4c8c

Bunseijiang commented 1 year ago

me too, using rider.

.net version: 8.0.100-rc.2.23502.2

Code:

using System.Text.Json.Serialization;

var builder = WebApplication.CreateSlimBuilder(args);

builder.Services.ConfigureHttpJsonOptions(options =>
{
    options.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default);
});

var app = builder.Build();

var sampleTodos = new Todo[]
{
    new(1, "Walk the dog"),
    new(2, "Do the dishes", DateOnly.FromDateTime(DateTime.Now)),
    new(3, "Do the laundry", DateOnly.FromDateTime(DateTime.Now.AddDays(1))),
    new(4, "Clean the bathroom"),
    new(5, "Clean the car", DateOnly.FromDateTime(DateTime.Now.AddDays(2)))
};
var todosApi = app.MapGroup("/todos");
todosApi.MapGet("/", () => sampleTodos);
todosApi.MapGet("/{id}", (int id) =>
    sampleTodos.FirstOrDefault(a => a.Id == id) is { } todo
        ? Results.Ok(todo)
        : Results.NotFound());

app.Run();

public record Todo(int Id, string? Title, DateOnly? DueBy = null, bool IsComplete = false);

[JsonSerializable(typeof(Todo[]))]
internal partial class AppJsonSerializerContext : JsonSerializerContext
{
}

Project:

<PropertyGroup>
        <TargetFramework>net8.0</TargetFramework>
        <Nullable>enable</Nullable>
        <ImplicitUsings>enable</ImplicitUsings>
        <InvariantGlobalization>true</InvariantGlobalization>
        <PublishAot>true</PublishAot>
        <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
    </PropertyGroup>
axzxs2001 commented 12 months ago

Project:

`

net8.0 enable enable true true

Program.cs using System.Text.Json.Serialization; var builder = WebApplication.CreateSlimBuilder(args); builder.Services.ConfigureHttpJsonOptions(options => { options.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default); }); var app = builder.Build(); var sampleTodos = new Todo[] { new(1, "Walk the dog"), new(2, "Do the dishes", DateOnly.FromDateTime(DateTime.Now)), new(3, "Do the laundry", DateOnly.FromDateTime(DateTime.Now.AddDays(1))), new(4, "Clean the bathroom"), new(5, "Clean the car", DateOnly.FromDateTime(DateTime.Now.AddDays(2))) }; var todosApi = app.MapGroup("/todos"); todosApi.MapGet("/", () => sampleTodos); todosApi.MapGet("/{id}", (int id) => sampleTodos.FirstOrDefault(a => a.Id == id) is { } todo ? Results.Ok(todo) : Results.NotFound());

app.Run(); public record Todo(int Id, string? Title, DateOnly? DueBy = null, bool IsComplete = false); [JsonSerializable(typeof(Todo[]))] internal partial class AppJsonSerializerContext : JsonSerializerContext { }`

VisualStudio :

Microsoft Visual Studio Enterprise 2022 (64 位) - Preview 版本 17.9.0 Preview 1.0

error message:

生成开始于 14:10... 1>------ 已启动生成: 项目: WebApplication16, 配置: Release Any CPU ------ 已还原 C:\Users\axzxs\source\repos\WebApplication16\WebApplication16\WebApplication16.csproj (用时 552 毫秒)。 1>WebApplication16 -> C:\Users\axzxs\source\repos\WebApplication16\WebApplication16\bin\Release\net8.0\WebApplication16.dll 2>------ 已启动发布: 项目: WebApplication16, 配置: Release Any CPU ------ 正在连接到 C:\Users\axzxs\source\repos\WebApplication16\WebApplication16\bin\Release\net8.0\publish... 正在确定要还原的项目… 所有项目均是最新的,无法还原。 WebApplication16 -> C:\Users\axzxs\source\repos\WebApplication16\WebApplication16\bin\Release\net8.0\win-x64\WebApplication16.dll "C:\Users\axzxs.nuget\packages\microsoft.dotnet.ilcompiler\8.0.0\build\findvcvarsall.bat" x64 Generating native code "C:\Users\axzxs.nuget\packages\runtime.win-x64.microsoft.dotnet.ilcompiler\8.0.0\tools\ilc" @"obj\Release\net8.0\win-x64\native\WebApplication16.ilc.rsp"

ILC: Method '[WebApplication16]Program.

$(string[])' will always throw because: Failed to load assembly 'Microsoft.AspNetCore'

"C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.36.32532\bin\Hostx64\x64\link.exe" @"obj\Release\net8.0\win-x64\native\link.rsp" WebApplication16 -> C:\Users\axzxs\source\repos\WebApplication16\WebApplication16\obj\Release\net8.0\win-x64\PubTmp\Out\ Web 应用已成功发布 file:///C:/Users/axzxs/source/repos/WebApplication16/WebApplication16/bin/Release/net8.0/publish/

dotnet cli is success:

dotnet publish -r win-x64

EdiWang commented 11 months ago

This is still happening after .NET 8 RTM. Even with a pure default empty project. Just a new project with "ASP.NET Core Web API(native AOT)", change nothing, publish directly (win-64), you will see the error.

eac3f30c70b78cd9f40e92dc7b8b89a

303115ea552cf3d6c4674aecfac5a89

vipwan commented 11 months ago

ine tools do not have this issue: dotnet publish -r win-x64 creates a working executab

--self-contained
eerhardt commented 11 months ago

This is still happening after .NET 8 RTM. Even with a pure default empty project. Just a new project with "ASP.NET Core Web API(native AOT)", change nothing, publish directly (win-64), you will see the error.

303115ea552cf3d6c4674aecfac5a89

Try executing the application in the bin\Release\net8.0\win-x64\publish folder. (Note the win-x64 addition to the folder you are using.

ZenMaxe commented 9 months ago

I Found The Issue! the problem is Visual Studio (and Rider) image

Visual Studio 2022 Preview Output:

PingTest -> C:\Users\hosei\source\repos\PingTest\bin\Release\net8.0\win-x64\PingTest.dll "C:\Users\hosei.nuget\packages\microsoft.dotnet.ilcompiler\8.0.0\build\findvcvarsall.bat" x64 Generating native code "C:\Users\hosei.nuget\packages\runtime.win-x64.microsoft.dotnet.ilcompiler\8.0.0\tools\ilc" @"obj\Release\net8.0\win-x64\native\PingTest.ilc.rsp" ILC: Method '[PingTest]Program.Main(string[])' will always throw because: Failed to load assembly 'Microsoft.AspNetCore' "C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.39.33321\bin\Hostx64\x64\link.exe" @"obj\Release\net8.0\win-x64\native\link.rsp" PingTest -> C:\Users\hosei\source\repos\PingTest\obj\Release\net8.0\win-x64\PubTmp\Out\ Web App was published successfully file:///C:/Users/hosei/source/repos/PingTest/bin/Release/net8.0/publish/

Cmd Output:

C:\Users\hosei\source\repos\PingTest>dotnet publish MSBuild version 17.8.3+195e7f5a3 for .NET Determining projects to restore... Restored C:\Users\hosei\source\repos\PingTest\PingTest.csproj (in 745 ms). PingTest -> C:\Users\hosei\source\repos\PingTest\bin\Release\net8.0\win-x64\PingTest.dll Generating native code PingTest -> C:\Users\hosei\source\repos\PingTest\bin\Release\net8.0\win-x64\publish\

with dotnet cli it's okay beacuse project will publish on target-runetime and it's worked!

AlexStormwood commented 8 months ago

Can confirm, a freshly-made project using the Minimal Web API (AOT) template has this issue for me. Latest versions of all things on the regular public tracks, no insider/preview/beta/etc stuff installed.

And as ZenMaxe notes above, running dotnet publish Projectname.csproj works just fine. There's something in Visual Studio or the VS publishing profile system that is different to dotnet CLI's way of doing things.

Publishing via the CLI also leads to an output file almost 3x the size of Visual Studio's publishing output (3MB vs 8.7MB), so something regarding the trimming/stripping may be at play?

ammfx commented 5 months ago

Changing in Publish - Show all settings dialog - Deployment mode to Self-contained fixes the issue (no build error and correct 9mb exe generated)

chuchu commented 3 months ago

I think @ammfx is right. This worked also for me using the webapiaot project. You can also add this to your csproj file instead.

<SelfContained>True</SelfContained>

It is a bit strange that the dotnet publish command magically adds this, but Visual Studio does not.

I have a bigger project which I converted from ASP.NET MVC to simple Web API with AOT. I have not configured any publish profile in VS but got the "Microsoft.AspNetCore" error after publishing on the command line. Adding the SelfContained settings to the csproj fixed the issue.

Maybe it makes sense to update the AOT Docu and mention the SelfContained settings there. Or at least explain when it is necessary and when not.

eerhardt commented 3 months ago

@vijayrkn - is Visual Studio doing something special here? When setting PublishAot=true, SelfContained is supposed to be defaulted to true.

See

https://github.com/dotnet/sdk/blob/196789faffa0e93c86061e44bb9d1852f10d09bc/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.RuntimeIdentifierInference.targets#L67-L85

Is Visual Studio explicitly setting SelfContained=false?

Is it pointing to the wrong publish output folder? (In this case bin\Release\net8.0\publish should be bin\Release\net8.0\win-x64\publish.

ZenMaxe commented 1 week ago

@vijayrkn - is Visual Studio doing something special here? When setting PublishAot=true, SelfContained is supposed to be defaulted to true.

See

https://github.com/dotnet/sdk/blob/196789faffa0e93c86061e44bb9d1852f10d09bc/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.RuntimeIdentifierInference.targets#L67-L85

Is Visual Studio explicitly setting SelfContained=false?

Is it pointing to the wrong publish output folder? (In this case bin\Release\net8.0\publish should be bin\Release\net8.0\win-x64\publish.

The problem relates to the target runtime.

As noted in my previous comment, using the default publish option, Visual Studio publishes it as "Any CPU." However, if you specify "Self-Contained" or set a specific CPU architecture, the issue is resolved.

I believe this happens because, with AOT, the CPU architecture must be specified during publishing, which Visual Studio doesn’t automatically handle, causing the problem.

Native AOT does have limited support for cross-architecture compilation (Microsoft).