Search code examples
c#asp.net-coreblazorblazor-client-sideblazor-webassembly

Blazor proj from scratch+nuget: "There was no runtime pack for Microsoft.AspNetCore.App available for the specified RuntimeIdentifier 'browser-wasm'"


[Final update 07.12.2020 23:50 --> for everyone seeking for the anwser]

You are probably adding some nuget package which has in fields DEPENDENCIES .NET Core 3.1. For example Serilog.AspNetCore 3.4.0. In this very example you can include Serilog.AspNetCore 3.2.0 because it has in DEPENDENCIES only .NetStandard 2.0. See more explanation in @Ogglas answer.

There is not enough space on earth to ask the one and only question: "Why, o why Microsoft?":) The message is not clearly correlating issue with the solution - this is the lightest euphemism i am capable of making :)

For me, Blazor is very promising but it is still more a beta version. And not only for me. The startblazoring guys are claiming, that Blazor can be fickle sometimes. And I cannot agree more;) I am keeping finger crossed for it. But I suppose it would be a "ready product" only after .NET 6.0.

[Original Topic]

This is so frustrating :)

I hate errors, when I cannot simply interact and understood where it is coming from. I know, I am ignorant, and If I would pay more attention to "how is the blazor app created" I would understand in eye blink.

But for now it is only frustrating. What is? The error message:

Severity Code Description Project File Line Suppression State Error NETSDK1082 There was no runtime pack for Microsoft.AspNetCore.App available for the specified RuntimeIdentifier 'browser-wasm'. TestBlazorAppNoRuntimeError.Client C:\Program Files\dotnet\sdk\5.0.100\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Sdk.FrameworkReferenceResolution.targets 387

Really, what can you fix here?:D Ehhhhh. I understand that .NET 5 is a "new thing". I understand Blazor is a "new thing" But really? It is really easy to "break" ;) (with a message that is saying nothing)

So what did I do?

Did I create very complicated project with hundreds of thousands of files?

No

Did I add hundreds of thousands of nuget packages.

No

All it takes is to create Blazor Webassembly app and add one nuget package to the shared (common) library (FYI: IdentityServer4 package). That is all folks. Kudos if you would now, that this package specificly is causing this issue (because i found out only by mistake):

There was no runtime pack for Microsoft.AspNetCore.App available for the specified RuntimeIdentifier 'browser-wasm'.

Really, there is a great correlation here: between the error message and the package being added (this was sarcasm if anyone missed it:) )

So if you want to reproduce it create create "Blazor Webassembly":

enter image description here

I don't suppose the options chosen are making the difference. But if this is the case - you can see what option I did choose. Then just add IdentityServer4 nuget package to shared library:

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

That is all

If you are too lazy - download this project and check for yourself:

https://ufile.io/751l5wgq

I saw hundreds of SOF topics regarding this message:

There was no runtime pack for Microsoft.AspNetCore.App available for the specified RuntimeIdentifier 'browser-wasm'.

But none of those was so easy to reproduce.

Why I am creating this topic?

Because I did try to implement (by copy-pasting to my solution) what guys did create in Blazor boilerplate here: https://github.com/enkodellc/blazorboilerplate

At the beginning, by mistake, I've added Identity4 NuGet instead of Identity4.storage and that is why I did observe such behavior (such error) and did correlate this package with this error. When I rolled back from Identity4 to Identity4.storage everything was correct once again. But after that I did a lot of code transfer from this repository. And once I've ended, right now, everything is compiling but once again I have:

There was no runtime pack for Microsoft.AspNetCore.App available for the specified RuntimeIdentifier 'browser-wasm'.

And it is driving me crazy. Maybe you would have some idea, how to find out WHAT is causing this error (exactly the same as previously Identity4 nuget package was causing it)

[UPDATE 06.12.2020 12:30]

The question here is more: "Why is it happening and how to locate package causing the issue" I know that I can second guess what is causing this message to appear.

I did a little investigation. This error is showing in this target:

<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>

so I did google ResolveRuntimePackAssets and found this repo and this file:

https://github.com/dotnet/sdk/blob/release/5.0.2xx/src/Tasks/Microsoft.NET.Build.Tasks/ResolveRuntimePackAssets.cs and such code:

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));
    }
}

Looks like the code "causing" the issue (this calls for writing down information in message about: unavailableRuntimePack.ItemSpec - it would be so much easier;))

So right now the only thing is to locate what is filling this: UnavailableRuntimePacks property. I don't see any code doing that so it have to be some reflection. I've located this code which is probably doing it:

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

And this method:

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);
        }
    }
}

After analysing it, the reason why Identity4 (for example) is causing this issue is because runtimePackRuntimeIdentifier is null and wasInGraph was true :) But what does mean, we have to dig a little bit further. The key thing here is the method 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;
}

So here we see that runtimePackRuntimeIdentifier was null because it was not found on: availableRuntimeIdentifiers. And this variable is defined as:

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

So let's see how is it defined (in the code below variable runtimePackForRuntimeIDProcessing is selectedRuntimePack from the above mention)

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;
}

But this is as far as I can go. I don't understand without further investigation how this selectedRuntimePack.RuntimePackRuntimeIdentifiers should be defined. This is the key thing here. Clearly for some reasons IdentityServer4 doesn't belong to selectedRuntimePack.RuntimePackRuntimeIdentifiers and this is the answer I am looking for :)


Solution

  • IdentityServer4 4.1.1 (latest version) is dependent upon .NETCoreApp 3.1

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

    If you create a Blazor WebAssembly App using .NET Core 3.1 it will work in the Server App.

    enter image description here

    However when using .NET Core 3.1 both Client and Shared uses .NET Standard 2.1 and is therefore not compatible. These error messages are a lot clearar though:

    Error Package restore failed. Rolling back package changes for 'BlazorApp.Shared'.

    Error NU1202 Package IdentityServer4 4.1.1 is not compatible with netstandard2.1 (.NETStandard,Version=v2.1). Package IdentityServer4 4.1.1 supports: netcoreapp3.1 (.NETCoreApp,Version=v3.1) BlazorApp.Shared