| File: ResolveStaticWebAssetsEffectiveTargetFramework.cs | Web Access |
| Project: src\sdk\src\StaticWebAssetsSdk\Tasks\Microsoft.NET.Sdk.StaticWebAssets.Tasks.csproj (Microsoft.NET.Sdk.StaticWebAssets.Tasks) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. #nullable disable using Microsoft.Build.Framework; namespace Microsoft.AspNetCore.StaticWebAssets.Tasks; public class ResolveStaticWebAssetsEffectiveTargetFramework : Task { [Required] public ITaskItem[] TargetFrameworks { get; set; } [Output] public string EffectiveTargetFramework { get; set; } public override bool Execute() { // We inspect the target frameworks available to find out an appropriate candidate to use for computing the list of // static web assets for packing. // Target frameworks have the following pattern {FrameworkIdentifier,FrameworkVersion,PlatformIdentifier?,PlatformVersion?} // for example: net6.0-windows.10.1980 or net-6.0-ios.14.2. // We don't deal with any parsing because that's handled by MSBuild. We also don't care about the platform identifier or the // platform version. The reason is explained below. // Static web assets don't support having different content based on the target framework. If you are multitargeting (for example, // in a Razor Class Library) we consider that all TFMs should produce the same set of static web assets and that we can, as a // result, pick any target framework to act as a representative when we are packing the assets into the package. // If a package is multitargeting across multiple versions of static web assets, (netstandard2.0 and net6.0 for example) we always // use as representative the framework with the highest static web assets version (net6.0 in this case). // Platform identifier and version, don't matter because as mentioned above, the list of assets should be identical in those cases // and we can pick among any of them to act as a representative for packing purposes. var (version, framework) = TargetFrameworks .Select(tf => new FrameworkItem(tf)) .Select(fi => (version: fi.GetStaticWebAssetsVersion(), framework: fi)) .OrderByDescending(p => p.version) .FirstOrDefault(p => p.version > 0); EffectiveTargetFramework = framework?.Moniker; return !Log.HasLoggedErrors; } private sealed class FrameworkItem(ITaskItem item) { public string Moniker { get; set; } = item.ItemSpec; public string TargetFrameworkIdentifier { get; set; } = item.GetMetadata("TargetFrameworkIdentifier"); public string TargetFrameworkVersion { get; set; } = item.GetMetadata("TargetFrameworkVersion"); internal double GetStaticWebAssetsVersion() => (TargetFrameworkIdentifier, TargetFrameworkVersion) switch { (".NETStandard", "2.0") => 1, (".NETStandard", "2.1") => 1, (".NETCoreApp", "3.0") => 1, (".NETCoreApp", "3.1") => 1, // If there is a net5.0 target, prefer that over netstandard because it supports scoped CSS (".NETCoreApp", "5.0") => 1.1, (".NETCoreApp", "6.0") => 2, (".NETCoreApp", "7.0") => 2, // Any future netcoreapp or netstandard will be version 2. If in the future we make additional changes to static web assets // that require a new version, some of our tests will fail to point out we need to change this value. (".NETCoreApp", _) => 2, (".NETStandard", _) => 2, // For anything that we don't know, we return 0. This filters out things like full framework as we won't // consider them. (_, _) => 0, }; } }