【问题标题】:Blazor proj from scratch+nuget: "There was no runtime pack for Microsoft.AspNetCore.App available for the specified RuntimeIdentifier 'browser-wasm'"Blazor proj 从头开始​​ + nuget:“没有可用于指定 RuntimeIdentifier 'browser-wasm' 的 Microsoft.AspNetCore.App 运行时包”
【发布时间】:2021-03-15 23:23:53
【问题描述】:

[最终更新 07.12.2020 23:50 --> 供所有寻求答案的人使用]

您可能正在添加一些具有 DEPENDENCIES .NET Core 3.1 字段的 nuget 包。例如 Serilog.AspNetCore 3.4.0。在这个例子中,您可以包含 Serilog.AspNetCore 3.2.0,因为它在 DEPENDENCIES 中只有 .NetStandard 2.0。在@Ogglas 答案中查看更多解释。

地球上没有足够的空间来问一个唯一的问题:“为什么,为什么是微软?”:) 该消息没有明确地将问题与解决方案相关联——这是我能做出的最轻巧的委婉说法: )

对我来说,Blazor 很有前途,但它仍然是一个测试版。而且不仅对我来说。令人兴奋的家伙声称,Blazor 有时会变幻无常。我不能再同意了;)我对此表示赞同。但我想它只有在 .NET 6.0 之后才会成为“现成产品”。

[原创主题]

这太令人沮丧了:)

我讨厌错误,因为我无法简单地互动并理解错误的来源。我知道,我很无知,如果我更加关注“blazor 应用程序是如何创建的”,我眨眼就明白了。

但现在只是令人沮丧。什么是?错误信息:

严重性代码描述项目文件行抑制状态 错误 NETSDK1082 没有可用于指定 RuntimeIdentifier 'browser-wasm' 的 Microsoft.AspNetCore.App 运行时包。 TestBlazorAppNoRuntimeError.Client C:\Program Files\dotnet\sdk\5.0.100\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Sdk.FrameworkReferenceResolution.targets 387

真的,你能在这里解决什么问题?:D 嗯嗯。我知道 .NET 5 是一个“新事物”。我知道 Blazor 是一个“新事物”但真的吗?真的很容易“打破”;)(有一条消息什么都不说)

那我做了什么?

我是否创建了包含数十万个文件的非常复杂的项目?

我是否添加了数十万个 nuget 包。

只需创建 Blazor Webassembly 应用程序并将一个 nuget 包添加到共享(公共)库(仅供参考:IdentityServer4 包)。就这些了。如果你现在愿意的话,这个包确实导致了这个问题(因为我只是错误地发现了):

没有可用于指定 RuntimeIdentifier 'browser-wasm' 的 Microsoft.AspNetCore.App 运行时包。

真的,这里有很大的相关性:错误消息和正在添加的包之间(如果有人错过,这是讽刺:))

因此,如果您想重现它,请创建“Blazor Webassembly”:

我认为所选择的选项不会产生影响。但如果是这种情况 - 你可以看到我选择了什么选项。然后只需将 IdentityServer4 nuget 包添加到共享库:

https://www.nuget.org/packages/IdentityServer4/

就是这样

如果你太懒了 - 下载这个项目并自己检查:

https://ufile.io/751l5wgq

我看到了数百个关于这条消息的 SOF 主题:

没有可用于指定 RuntimeIdentifier 'browser-wasm' 的 Microsoft.AspNetCore.App 运行时包。

但这些都不是那么容易复制的。

我为什么要创建这个主题?

因为我确实尝试实现(通过复制粘贴到我的解决方案)人们在 Blazor 样板中创建的内容: https://github.com/enkodellc/blazorboilerplate

一开始,我错误地添加了 Identity4 NuGet 而不是 Identity4.storage,这就是为什么我确实观察到了这种行为(这样的错误)并将这个包与这个错误相关联。当我从 Identity4 回滚到 Identity4.storage 时,一切都再次正确。但在那之后,我从这个存储库做了很多代码传输。一旦我结束了,现在,一切都在编译,但我又一次:

没有可用于指定 RuntimeIdentifier 'browser-wasm' 的 Microsoft.AspNetCore.App 运行时包。

这让我发疯了。也许您会有一些想法,如何找出导致此错误的原因(与之前的 Identity4 nuget 包导致它完全相同)

[更新 06.12.2020 12:30]

这里的问题更多:“为什么会发生以及如何定位导致问题的包”我知道我可以再次猜测导致此消息出现的原因。

我做了一点调查。此目标中显示此错误:

<ResolveRuntimePackAssets FrameworkReferences="@(FrameworkReference)"
                          ResolvedRuntimePacks="@(ResolvedRuntimePack)"
                          UnavailableRuntimePacks="@(UnavailableRuntimePack)"
                          SatelliteResourceLanguages="$(SatelliteResourceLanguages)"
                          DesignTimeBuild="$(DesignTimeBuild)">
  <Output TaskParameter="RuntimePackAssets" ItemName="RuntimePackAsset" />
</ResolveRuntimePackAssets>

<ItemGroup>
  <ReferenceCopyLocalPaths Include="@(RuntimePackAsset)"
                           Condition="'$(CopyLocalLockFileAssemblies)' == 'true' and ('$(SelfContained)' == 'true' or '%(RuntimePackAsset.RuntimePackAlwaysCopyLocal)' == 'true')" />
</ItemGroup>

所以我谷歌了 ResolveRuntimePackAssets 并找到了这个 repo 和这个文件:

https://github.com/dotnet/sdk/blob/release/5.0.2xx/src/Tasks/Microsoft.NET.Build.Tasks/ResolveRuntimePackAssets.cs 和这样的代码:

foreach (var unavailableRuntimePack in UnavailableRuntimePacks)
{
    if (frameworkReferenceNames.Contains(unavailableRuntimePack.ItemSpec))
    {
        //  This is a runtime pack that should be used, but wasn't available for the specified RuntimeIdentifier
        //  NETSDK1082: There was no runtime pack for {0} available for the specified RuntimeIdentifier '{1}'.
        Log.LogError(Strings.NoRuntimePackAvailable, unavailableRuntimePack.ItemSpec,
            unavailableRuntimePack.GetMetadata(MetadataKeys.RuntimeIdentifier));
    }
}

看起来是“导致”问题的代码(这需要在消息中写下有关:unavailableRuntimePack.ItemSpec 的信息 - 这会容易得多;))

所以现在唯一要做的就是找到填充此内容的内容:UnavailableRuntimePacks 属性。我没有看到任何代码这样做,所以它必须是一些反思。我找到了可能正在执行此操作的代码:

https://github.com/dotnet/sdk/blob/release/5.0.2xx/src/Tasks/Microsoft.NET.Build.Tasks/ProcessFrameworkReferences.cs

还有这个方法:

private void ProcessRuntimeIdentifier(
    string runtimeIdentifier,
    KnownRuntimePack selectedRuntimePack,
    string runtimePackVersion,
    List<string> additionalFrameworkReferencesForRuntimePack,
    HashSet<string> unrecognizedRuntimeIdentifiers,
    List<ITaskItem> unavailableRuntimePacks,
    List<ITaskItem> runtimePacks,
    List<ITaskItem> packagesToDownload,
    string isTrimmable,
    bool addToPackageDownload)
{
    var runtimeGraph = new RuntimeGraphCache(this).GetRuntimeGraph(RuntimeGraphPath);
    var knownFrameworkReferenceRuntimePackRuntimeIdentifiers = selectedRuntimePack.RuntimePackRuntimeIdentifiers.Split(';');

    string runtimePackRuntimeIdentifier = NuGetUtils.GetBestMatchingRid(
            runtimeGraph,
            runtimeIdentifier,
            knownFrameworkReferenceRuntimePackRuntimeIdentifiers,
            out bool wasInGraph);

    if (runtimePackRuntimeIdentifier == null)
    {
        if (wasInGraph)
        {
            //  Report this as an error later, if necessary.  This is because we try to download
            //  all available runtime packs in case there is a transitive reference to a shared
            //  framework we don't directly reference.  But we don't want to immediately error out
            //  here if a runtime pack that we might not need to reference isn't available for the
            //  targeted RID (e.g. Microsoft.WindowsDesktop.App for a linux RID).
            var unavailableRuntimePack = new TaskItem(selectedRuntimePack.Name);
            unavailableRuntimePack.SetMetadata(MetadataKeys.RuntimeIdentifier, runtimeIdentifier);
            unavailableRuntimePacks.Add(unavailableRuntimePack);
        }
        else if (!unrecognizedRuntimeIdentifiers.Contains(runtimeIdentifier))
        {
            //  NETSDK1083: The specified RuntimeIdentifier '{0}' is not recognized.
            Log.LogError(Strings.RuntimeIdentifierNotRecognized, runtimeIdentifier);
            unrecognizedRuntimeIdentifiers.Add(runtimeIdentifier);
        }
    }
    else if (addToPackageDownload)
    {
        foreach (var runtimePackNamePattern in selectedRuntimePack.RuntimePackNamePatterns.Split(';'))
        {
            string runtimePackName = runtimePackNamePattern.Replace("**RID**", runtimePackRuntimeIdentifier);

            if (runtimePacks != null)
            {
                TaskItem runtimePackItem = new TaskItem(runtimePackName);
                runtimePackItem.SetMetadata(MetadataKeys.NuGetPackageId, runtimePackName);
                runtimePackItem.SetMetadata(MetadataKeys.NuGetPackageVersion, runtimePackVersion);
                runtimePackItem.SetMetadata(MetadataKeys.FrameworkName, selectedRuntimePack.Name);
                runtimePackItem.SetMetadata(MetadataKeys.RuntimeIdentifier, runtimePackRuntimeIdentifier);
                runtimePackItem.SetMetadata(MetadataKeys.IsTrimmable, isTrimmable);

                if (selectedRuntimePack.RuntimePackAlwaysCopyLocal)
                {
                    runtimePackItem.SetMetadata(MetadataKeys.RuntimePackAlwaysCopyLocal, "true");
                }

                if (additionalFrameworkReferencesForRuntimePack != null)
                {
                    runtimePackItem.SetMetadata(MetadataKeys.AdditionalFrameworkReferences, string.Join(";", additionalFrameworkReferencesForRuntimePack));
                }

                runtimePacks.Add(runtimePackItem);
            }

            TaskItem packageToDownload = new TaskItem(runtimePackName);
            packageToDownload.SetMetadata(MetadataKeys.Version, runtimePackVersion);

            packagesToDownload.Add(packageToDownload);
        }
    }
}

经过分析,Identity4(例如)导致这个问题的原因是因为 runtimePackRuntimeIdentifier 为 null 并且 wasInGraph 为 true :) 但这是什么意思,我们必须进一步挖掘。这里的关键是GetBestMatchingRid方法:

public static string GetBestMatchingRid(RuntimeGraph runtimeGraph, string runtimeIdentifier,
    IEnumerable<string> availableRuntimeIdentifiers, out bool wasInGraph)
{
    wasInGraph = runtimeGraph.Runtimes.ContainsKey(runtimeIdentifier);

    HashSet<string> availableRids = new HashSet<string>(availableRuntimeIdentifiers);
    foreach (var candidateRuntimeIdentifier in runtimeGraph.ExpandRuntime(runtimeIdentifier))
    {
        if (availableRids.Contains(candidateRuntimeIdentifier))
        {
            return candidateRuntimeIdentifier;
        }
    }

    //  No compatible RID found in availableRuntimeIdentifiers
    return null;
}

所以在这里我们看到runtimePackRuntimeIdentifier 为空,因为在availableRuntimeIdentifiers 上找不到它。而这个变量定义为:

var knownFrameworkReferenceRuntimePackRuntimeIdentifiers = selectedRuntimePack.RuntimePackRuntimeIdentifiers.Split(';');

那么让我们看看它是如何定义的(在下面的代码中,变量runtimePackForRuntimeIDProcessing 是上面提到的selectedRuntimePack

KnownRuntimePack runtimePackForRuntimeIDProcessing;
if (knownFrameworkReference.Name.Equals(knownFrameworkReference.RuntimeFrameworkName, StringComparison.OrdinalIgnoreCase))
{
    //  Only add runtime packs where the framework reference name matches the RuntimeFrameworkName
    //  Framework references for "profiles" will use the runtime pack from the corresponding non-profile framework
    runtimePackForRuntimeIDProcessing = selectedRuntimePack.Value;
    includeInPackageDownload = true;
}
else if (!knownFrameworkReference.RuntimePackRuntimeIdentifiers.Equals(selectedRuntimePack?.RuntimePackRuntimeIdentifiers))
{
    // If the profile has a different set of runtime identifiers than the runtime pack, use the profile.
    runtimePackForRuntimeIDProcessing = knownFrameworkReference.ToKnownRuntimePack();
    includeInPackageDownload = true;
}
else
{
    // For the remaining profiles, don't include them in package download but add them to unavaliable if necessary.
    runtimePackForRuntimeIDProcessing = knownFrameworkReference.ToKnownRuntimePack();
    includeInPackageDownload = false;
}

但这是我能做到的。如果没有进一步调查,我不明白应该如何定义这个selectedRuntimePack.RuntimePackRuntimeIdentifiers。这是这里的关键。显然由于某些原因 IdentityServer4 不属于selectedRuntimePack.RuntimePackRuntimeIdentifiers,这就是我正在寻找的答案:)

【问题讨论】:

  • 当您在 Visual Studio 中运行它时会发生这种情况,对吗?我们不是在谈论部署到服务器之后。
  • 您有重复步骤。去尝试;)但要回答你的问题。不,它不是在部署之后,它是在 VS 2019 16.8.2 中构建的 :) 我什至在 16.9.0 1.0 预览版中尝试过。是一样的。
  • (仅供参考:IdentityServer4 包) 不属于共享项目。仅将其添加到服务器项目中。
  • 您不会在客户端项目中放置 100 个包。共享项目包含在客户端中,因此对于两者:尽可能少地添加,并且只添加您知道没问题的内容。假设它不是并调查 ort 测试。
  • 你是对的,没有完整的文档也没有工具(afaik)。但是一点常识会大有帮助。

标签: c# asp.net-core blazor blazor-client-side blazor-webassembly


【解决方案1】:

正如我在link 中提到的,似乎以下软件包存在问题。因此,从您的项目和 Blazor 项目引用的所有其他项目中删除该包(右键单击项目,选择编辑项目文件,然后删除以下内容):

<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.0" />

在我的情况下(也希望在你的情况下)这个包的唯一用途是使用字段成员JwtBearerDefaults.AuthenticationScheme 获取常量字符串"Bearer"。因此,只需简单地使用 "Bearer" 字符串即可。

【讨论】:

  • 您肯定也遇到过同样的问题。但是您没有收到任何答案为什么以及如何诊断这个包,这导致了这个问题。您通过第二次猜测要删除的包来发现问题。这始终是一种选择,但最终我们是工程师。我们因为知道事情而不是猜测事情而获得报酬;)我想知道是什么导致了这个问题而不是克服它。
  • 所讨论的方法并未针对提高生产力进行优化。作为软件产品的消费者,这不是我们来解决问题和错误的。我们只能报告问题,他们应该解决它。不要在这些问题上浪费你宝贵的时间,这不是工程。把时间和精力放在相关问题上。
  • 对不起,这是我想知道的“我的东西”。这里的问题是(事实证明),在 DEPENDENCIES .Net Core 3.1 中具有的 nuget 包将不起作用:) 疯了,我知道。但现在我会知道,如果我想在 Blazor 项目中包含一些包来检查“依赖项”;)
【解决方案2】:

IdentityServer4 4.1.1(最新版本)依赖于.NETCoreApp 3.1

https://www.nuget.org/packages/IdentityServer4/

如果您使用.NET Core 3.1 创建Blazor WebAssembly App,它将在Server 应用程序中运行。

但是,当使用 .NET Core 3.1 时,ClientShared 都使用 .NET Standard 2.1,因此不兼容。不过,这些错误消息非常清楚:

错误包还原失败。回滚包更改 'BlazorApp.Shared'。

错误 NU1202 包 IdentityServer4 4.1.1 不兼容 netstandard2.1 (.NETStandard,版本=v2.1)。包 IdentityServer4 4.1.1 支持:netcoreapp3.1 (.NETCoreApp,Version=v3.1) BlazorApp.Shared

【讨论】:

  • 我使用的是 .NET 5.0。除此之外,您是正确的。我认为您是最接近解决方案的。事实证明 - 您不能包含带有 .NET CORE 3.1 的包,这些包被标记为依赖于 nuget 包 DEPENDENCIES 部分。另一个很好的例子是 Serilog.AspNetCore 3.4.0 它具有依赖关系 .NETCoreApp 版本 3.1。因此,如果您尝试包含此软件包,则会遇到与我相同的错误。但是您可以包含 Serilog.AspNetCore 3.2.0,因为它依赖于 .NETStandard 2.0 版。我只问一个问题。为什么每次我尝试包含这样的包时它都没有放在我的脸上......
猜你喜欢
  • 2021-01-07
  • 2021-08-17
  • 2022-07-19
  • 2021-03-07
  • 1970-01-01
  • 2023-03-05
  • 2022-10-23
  • 1970-01-01
  • 2022-12-21
相关资源
最近更新 更多