diff --git a/src/Components/Blazor/Build/src/Tasks/BlazorILLink.cs b/src/Components/Blazor/Build/src/Tasks/BlazorILLink.cs
index 5e0a86d384..d5dc22cde0 100644
--- a/src/Components/Blazor/Build/src/Tasks/BlazorILLink.cs
+++ b/src/Components/Blazor/Build/src/Tasks/BlazorILLink.cs
@@ -66,7 +66,12 @@ namespace Microsoft.AspNetCore.Blazor.Build.Tasks
protected override string GenerateFullPathToTool() => DotNetPath;
- protected override string GenerateCommandLineCommands() => ILLinkPath;
+ protected override string GenerateCommandLineCommands()
+ {
+ var args = new StringBuilder();
+ args.Append(Quote(ILLinkPath));
+ return args.ToString();
+ }
private static string Quote(string path)
{
diff --git a/src/Components/Blazor/Build/src/Tasks/GenerateBlazorBootJson.cs b/src/Components/Blazor/Build/src/Tasks/GenerateBlazorBootJson.cs
index b383d183e4..1984de0a57 100644
--- a/src/Components/Blazor/Build/src/Tasks/GenerateBlazorBootJson.cs
+++ b/src/Components/Blazor/Build/src/Tasks/GenerateBlazorBootJson.cs
@@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+using System;
using System.IO;
using System.Linq;
using System.Reflection;
@@ -27,12 +28,23 @@ namespace Microsoft.AspNetCore.Blazor.Build
public override bool Execute()
{
var entryAssemblyName = AssemblyName.GetAssemblyName(AssemblyPath).Name;
- var assemblies = References.Select(c => Path.GetFileName(c.ItemSpec)).ToArray();
+ var assemblies = References.Select(GetUriPath).OrderBy(c => c, StringComparer.Ordinal).ToArray();
using var fileStream = File.Create(OutputPath);
WriteBootJson(fileStream, entryAssemblyName, assemblies, LinkerEnabled);
return true;
+
+ static string GetUriPath(ITaskItem item)
+ {
+ var outputPath = item.GetMetadata("RelativeOutputPath");
+ if (string.IsNullOrEmpty(outputPath))
+ {
+ outputPath = Path.GetFileName(item.ItemSpec);
+ }
+
+ return outputPath.Replace('\\', '/');
+ }
}
internal static void WriteBootJson(Stream stream, string entryAssemblyName, string[] assemblies, bool linkerEnabled)
diff --git a/src/Components/Blazor/Build/src/targets/Blazor.MonoRuntime.targets b/src/Components/Blazor/Build/src/targets/Blazor.MonoRuntime.targets
index cdbe7169a0..915ec80391 100644
--- a/src/Components/Blazor/Build/src/targets/Blazor.MonoRuntime.targets
+++ b/src/Components/Blazor/Build/src/targets/Blazor.MonoRuntime.targets
@@ -74,7 +74,7 @@
-
+
$(IntermediateOutputPath)blazor\
@@ -94,8 +94,6 @@
- <_BlazorDependencyInput Include="@(ReferenceCopyLocalPaths->WithMetadataValue('Extension','.dll')->'%(FullPath)')" />
-
<_WebAssemblyBCLFolder Include="
$(DotNetWebAssemblyBCLPath);
$(DotNetWebAssemblyBCLFacadesPath);
@@ -104,6 +102,22 @@
<_WebAssemblyBCLAssembly Include="%(_WebAssemblyBCLFolder.Identity)*.dll" />
+
+
+
+ <_BlazorManagedRuntimeAssemby Include="@(RuntimeCopyLocalItems)" />
+
+
+ <_BlazorUserRuntimeAssembly Include="@(ReferencePath->WithMetadataValue('CopyLocal', 'true'))" />
+ <_BlazorUserRuntimeAssembly Include="@(ReferenceDependencyPaths->WithMetadataValue('CopyLocal', 'true'))" />
+
+ <_BlazorManagedRuntimeAssemby Include="@(_BlazorUserRuntimeAssembly)" />
+ <_BlazorManagedRuntimeAssemby Include="@(IntermediateAssembly)" />
+
+
@@ -111,6 +125,27 @@
+
+
+
+ <_BlazorCopyLocalPaths Include="@(ReferenceCopyLocalPaths)" />
+ <_BlazorCopyLocalPaths Remove="@(_BlazorManagedRuntimeAssemby)" />
+
+
+ true
+ $(BlazorRuntimeBinOutputPath)%(_BlazorCopyLocalPaths.DestinationSubDirectory)%(FileName)%(Extension)
+ %(_BlazorCopyLocalPaths.DestinationSubDirectory)%(FileName)%(Extension)
+
+
+
+ true
+ $(BlazorRuntimeBinOutputPath)%(FileName)%(Extension)
+ %(FileName)%(Extension)
+
+
-
+
-
-
-
- $(BlazorRuntimeBinOutputPath)%(FileName)%(Extension)
-
-
@@ -163,8 +192,7 @@
@@ -174,12 +202,15 @@
<_BlazorDependencyAssembly IsLinkable="true" Condition="$([System.String]::Copy('%(Filename)').StartsWith('System.'))" />
<_BlazorDependencyAssembly IsLinkable="true" TypeGranularity="true" Condition="$([System.String]::Copy('%(Filename)').StartsWith('Microsoft.AspNetCore.'))" />
<_BlazorDependencyAssembly IsLinkable="true" TypeGranularity="true" Condition="$([System.String]::Copy('%(Filename)').StartsWith('Microsoft.Extensions.'))" />
+
+ <_BlazorRuntimeCopyLocalItems Include="@(RuntimeCopyLocalItems)" IsLinkable="$([System.String]::Copy('%(FileName)').StartsWith('System.'))" />
<_BlazorAssemblyToLink Include="@(_WebAssemblyBCLAssembly)" />
- <_BlazorAssemblyToLink Include="@(_BlazorDependencyAssembly)" Condition="'%(_BlazorDependencyAssembly.IsLinkable)' == 'true'" />
+ <_BlazorAssemblyToLink Include="@(_BlazorRuntimeCopyLocalItems)" Condition="'%(_BlazorRuntimeCopyLocalItems.IsLinkable)' == 'true'" />
<_BlazorLinkerRoot Include="@(IntermediateAssembly)" />
- <_BlazorLinkerRoot Include="@(_BlazorDependencyAssembly)" Condition="'%(_BlazorDependencyAssembly.IsLinkable)' != 'true'" />
+ <_BlazorLinkerRoot Include="@(_BlazorUserRuntimeAssembly)" />
+ <_BlazorLinkerRoot Include="@(_BlazorRuntimeCopyLocalItems)" Condition="'%(_BlazorRuntimeCopyLocalItems.IsLinkable)' != 'true'" />
@@ -230,29 +261,22 @@
-
-
-
+
+
-
-
-
- $(BlazorRuntimeBinOutputPath)%(FileName)%(Extension)
-
-
-
+
@@ -282,13 +306,12 @@
Inputs="@(BlazorOutputWithTargetPath)"
Outputs="$(BlazorBootJsonIntermediateOutputPath)">
- <_AppReferences Include="@(BlazorOutputWithTargetPath->WithMetadataValue('Extension','.dll'))" />
- <_AppReferences Include="@(BlazorOutputWithTargetPath->WithMetadataValue('Extension','.pdb'))" Condition="'$(BlazorEnableDebugging)' == 'true'" />
+ <_BlazorRuntimeFile Include="@(BlazorOutputWithTargetPath->WithMetadataValue('BlazorRuntimeFile', 'true'))" />
diff --git a/src/Components/Blazor/Build/test/BuildIntegrationTests/BuildIntegrationTest.cs b/src/Components/Blazor/Build/test/BuildIntegrationTests/BuildIntegrationTest.cs
index 1cc39f0d6e..027fe59990 100644
--- a/src/Components/Blazor/Build/test/BuildIntegrationTests/BuildIntegrationTest.cs
+++ b/src/Components/Blazor/Build/test/BuildIntegrationTests/BuildIntegrationTest.cs
@@ -70,5 +70,66 @@ namespace Microsoft.AspNetCore.Blazor.Build
Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "_bin", "standalone.dll");
Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "_bin", "Microsoft.Extensions.Logging.Abstractions.dll"); // Verify dependencies are part of the output.
}
+
+ [Fact]
+ public async Task Build_SatelliteAssembliesAreCopiedToBuildOutput()
+ {
+ // Arrange
+ using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary", "classlibrarywithsatelliteassemblies" });
+ project.AddProjectFileContent(
+@"
+
+ $(DefineConstants);REFERENCE_classlibrarywithsatelliteassemblies
+
+
+
+");
+
+ var result = await MSBuildProcessManager.DotnetMSBuild(project, args: "/restore");
+
+ Assert.BuildPassed(result);
+
+ var buildOutputDirectory = project.BuildOutputDirectory;
+
+ Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "_bin", "standalone.dll");
+ Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "_bin", "classlibrarywithsatelliteassemblies.dll");
+ Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "_bin", "Microsoft.CodeAnalysis.CSharp.dll");
+ Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "_bin", "fr", "Microsoft.CodeAnalysis.CSharp.resources.dll"); // Verify satellite assemblies are present in the build output.
+
+ var bootJsonPath = Path.Combine(buildOutputDirectory, "dist", "_framework", "blazor.boot.json");
+ Assert.FileContains(result, bootJsonPath, "\"Microsoft.CodeAnalysis.CSharp.dll\"");
+ Assert.FileContains(result, bootJsonPath, "\"fr\\/Microsoft.CodeAnalysis.CSharp.resources.dll\"");
+ }
+
+ [Fact]
+ public async Task Build_WithBlazorLinkOnBuildFalse_SatelliteAssembliesAreCopiedToBuildOutput()
+ {
+ // Arrange
+ using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary", "classlibrarywithsatelliteassemblies" });
+ project.AddProjectFileContent(
+@"
+
+ false
+ $(DefineConstants);REFERENCE_classlibrarywithsatelliteassemblies
+
+
+
+");
+
+ var result = await MSBuildProcessManager.DotnetMSBuild(project, args: "/restore");
+
+ Assert.BuildPassed(result);
+
+ var buildOutputDirectory = project.BuildOutputDirectory;
+
+ Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "_bin", "standalone.dll");
+ Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "_bin", "classlibrarywithsatelliteassemblies.dll");
+ Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "_bin", "Microsoft.CodeAnalysis.CSharp.dll");
+ Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "_bin", "fr", "Microsoft.CodeAnalysis.CSharp.resources.dll"); // Verify satellite assemblies are present in the build output.
+
+ var bootJsonPath = Path.Combine(buildOutputDirectory, "dist", "_framework", "blazor.boot.json");
+ Assert.FileContains(result, bootJsonPath, "\"Microsoft.CodeAnalysis.CSharp.dll\"");
+ Assert.FileContains(result, bootJsonPath, "\"fr\\/Microsoft.CodeAnalysis.CSharp.resources.dll\"");
+ }
}
}
diff --git a/src/Components/Blazor/Build/test/BuildIntegrationTests/PublishIntegrationTest.cs b/src/Components/Blazor/Build/test/BuildIntegrationTests/PublishIntegrationTest.cs
index 6995ffde4d..f1f554d3b9 100644
--- a/src/Components/Blazor/Build/test/BuildIntegrationTests/PublishIntegrationTest.cs
+++ b/src/Components/Blazor/Build/test/BuildIntegrationTests/PublishIntegrationTest.cs
@@ -112,6 +112,35 @@ namespace Microsoft.AspNetCore.Blazor.Build
Assert.FileExists(result, publishDirectory, "web.config");
}
+ [Fact]
+ public async Task Publish_SatelliteAssemblies_AreCopiedToBuildOutput()
+ {
+ // Arrange
+ using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary", "classlibrarywithsatelliteassemblies" });
+ project.AddProjectFileContent(
+@"
+
+ $(DefineConstants);REFERENCE_classlibrarywithsatelliteassemblies
+
+
+
+");
+
+ var result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish", args: "/restore");
+
+ Assert.BuildPassed(result);
+
+ var publishDirectory = project.PublishOutputDirectory;
+ var blazorPublishDirectory = Path.Combine(publishDirectory, Path.GetFileNameWithoutExtension(project.ProjectFilePath));
+
+ Assert.FileExists(result, blazorPublishDirectory, "dist", "_framework", "_bin", "Microsoft.CodeAnalysis.CSharp.dll");
+ Assert.FileExists(result, blazorPublishDirectory, "dist", "_framework", "_bin", "fr", "Microsoft.CodeAnalysis.CSharp.resources.dll"); // Verify satellite assemblies are present in the build output.
+
+ var bootJsonPath = Path.Combine(blazorPublishDirectory, "dist", "_framework", "blazor.boot.json");
+ Assert.FileContains(result, bootJsonPath, "\"Microsoft.CodeAnalysis.CSharp.dll\"");
+ Assert.FileContains(result, bootJsonPath, "\"fr\\/Microsoft.CodeAnalysis.CSharp.resources.dll\"");
+ }
+
[Fact]
public async Task Publish_HostedApp_Works()
{
diff --git a/src/Components/Blazor/Build/testassets/classlibrarywithsatelliteassemblies/Class1.cs b/src/Components/Blazor/Build/testassets/classlibrarywithsatelliteassemblies/Class1.cs
new file mode 100644
index 0000000000..944699cdb3
--- /dev/null
+++ b/src/Components/Blazor/Build/testassets/classlibrarywithsatelliteassemblies/Class1.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace classlibrarywithsatelliteassemblies
+{
+ public class Class1
+ {
+ public static void Test()
+ {
+ GC.KeepAlive(typeof(Microsoft.CodeAnalysis.CSharp.CSharpCompilation));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Components/Blazor/Build/testassets/classlibrarywithsatelliteassemblies/classlibrarywithsatelliteassemblies.csproj b/src/Components/Blazor/Build/testassets/classlibrarywithsatelliteassemblies/classlibrarywithsatelliteassemblies.csproj
new file mode 100644
index 0000000000..7081842748
--- /dev/null
+++ b/src/Components/Blazor/Build/testassets/classlibrarywithsatelliteassemblies/classlibrarywithsatelliteassemblies.csproj
@@ -0,0 +1,13 @@
+
+
+
+ netstandard2.1
+ 3.0
+
+
+
+
+
+
+
+
diff --git a/src/Components/Blazor/Build/testassets/standalone/Program.cs b/src/Components/Blazor/Build/testassets/standalone/Program.cs
index 16bfae7e43..3e46e63316 100644
--- a/src/Components/Blazor/Build/testassets/standalone/Program.cs
+++ b/src/Components/Blazor/Build/testassets/standalone/Program.cs
@@ -1,10 +1,14 @@
-
+using System;
+
namespace standalone
{
public class Program
{
public static void Main(string[] args)
{
+#if REFERENCE_classlibrarywithsatelliteassemblies
+ GC.KeepAlive(typeof(classlibrarywithsatelliteassemblies.Class1));
+#endif
}
}
}