Skip to content

Commit 5da3146

Browse files
pranavkmSteveSandersonMS
authored andcommitted
Add an option to allow trimming collation data
1 parent 7cb9b7f commit 5da3146

File tree

8 files changed

+140
-1
lines changed

8 files changed

+140
-1
lines changed

src/Components/WebAssembly/Build/src/targets/Blazor.MonoRuntime.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<_BlazorRuntimeBinOutputPath>$(_BaseBlazorRuntimeOutputPath)_bin\</_BlazorRuntimeBinOutputPath>
1010
<_BlazorRuntimeWasmOutputPath>$(_BaseBlazorRuntimeOutputPath)wasm\</_BlazorRuntimeWasmOutputPath>
1111
<_BlazorBuiltInBclLinkerDescriptor>$(MSBuildThisFileDirectory)BuiltInBclLinkerDescriptor.xml</_BlazorBuiltInBclLinkerDescriptor>
12+
<_BlazorCollationLinkerDescriptor>$(MSBuildThisFileDirectory)CollationLinkerDescriptor.xml</_BlazorCollationLinkerDescriptor>
1213
<_BlazorBootJsonName>blazor.boot.json</_BlazorBootJsonName>
1314
</PropertyGroup>
1415

src/Components/WebAssembly/Build/src/targets/Blazor.MonoRuntime.targets

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,10 @@
218218
<_BlazorLinkerRoot Include="@(_BlazorRuntimeCopyLocalItems)" Condition="'%(_BlazorRuntimeCopyLocalItems.IsLinkable)' != 'true'" />
219219
</ItemGroup>
220220

221+
<!-- When specifically requested, include the linker substitutions file that strips out collation information.-->
222+
<PropertyGroup Condition="'$(BlazorWebAssemblyPreserveCollationData)' == 'false'">
223+
<AdditionalMonoLinkerOptions>$(AdditionalMonoLinkerOptions) --substitutions "$(_BlazorCollationLinkerDescriptor)"</AdditionalMonoLinkerOptions>
224+
</PropertyGroup>
221225
</Target>
222226

223227
<UsingTask TaskName="BlazorCreateRootDescriptorFile" AssemblyFile="$(_BlazorTasksPath)" />
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<linker>
2+
<!-- This file disables exclusions that remove collation data -->
3+
4+
<assembly fullname="mscorlib">
5+
<resource name="collation.cjkCHS.bin" action="remove"/>
6+
<resource name="collation.cjkCHT.bin" action="remove"/>
7+
<resource name="collation.cjkJA.bin" action="remove"/>
8+
<resource name="collation.cjkKO.bin" action="remove"/>
9+
<resource name="collation.cjkKOlv2.bin" action="remove"/>
10+
<resource name="collation.core.bin" action="remove"/>
11+
<resource name="collation.tailoring.bin" action="remove"/>
12+
13+
<type fullname="System.Globalization.CompareInfo">
14+
<method signature="System.Boolean get_IgnoreCaseNotSupported()" body="stub" value="true"/>
15+
</type>
16+
17+
<type fullname="System.Globalization.CompareInfo">
18+
<method signature="System.Boolean get_UseManagedCollation()" body="stub" value="false"/>
19+
</type>
20+
</assembly>
21+
</linker>

src/Components/WebAssembly/Build/test/BuildIntegrationTests/Assert.cs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -534,7 +534,7 @@ private static IEnumerable<string> GetDeclaredTypeNames(string assemblyPath)
534534
{
535535
using (var file = File.OpenRead(assemblyPath))
536536
{
537-
var peReader = new PEReader(file);
537+
using var peReader = new PEReader(file);
538538
var metadataReader = peReader.GetMetadataReader();
539539
return metadataReader.TypeDefinitions.Where(t => !t.IsNil).Select(t =>
540540
{
@@ -544,6 +544,44 @@ private static IEnumerable<string> GetDeclaredTypeNames(string assemblyPath)
544544
}
545545
}
546546

547+
public static void AssemblyContainsResource(MSBuildResult result, string assemblyPath, string resourceName)
548+
{
549+
if (result == null)
550+
{
551+
throw new ArgumentNullException(nameof(result));
552+
}
553+
554+
assemblyPath = Path.Combine(result.Project.DirectoryPath, Path.Combine(assemblyPath));
555+
556+
var resources = GetAssemblyResourceNames(assemblyPath);
557+
Assert.Contains(resourceName, resources);
558+
}
559+
560+
public static void AssemblyDoesNotContainResource(MSBuildResult result, string assemblyPath, string resourceName)
561+
{
562+
if (result == null)
563+
{
564+
throw new ArgumentNullException(nameof(result));
565+
}
566+
567+
assemblyPath = Path.Combine(result.Project.DirectoryPath, Path.Combine(assemblyPath));
568+
569+
var resources = GetAssemblyResourceNames(assemblyPath);
570+
Assert.DoesNotContain(resourceName, resources);
571+
}
572+
573+
private static IEnumerable<string> GetAssemblyResourceNames(string assemblyPath)
574+
{
575+
using var file = File.OpenRead(assemblyPath);
576+
using var peReader = new PEReader(file);
577+
var metadataReader = peReader.GetMetadataReader();
578+
return metadataReader.ManifestResources.Where(r => !r.IsNil).Select(r =>
579+
{
580+
var resource = metadataReader.GetManifestResource(r);
581+
return metadataReader.GetString(resource.Name);
582+
}).ToArray();
583+
}
584+
547585
public static void AssemblyHasAttribute(MSBuildResult result, string assemblyPath, string fullTypeName)
548586
{
549587
if (result == null)

src/Components/WebAssembly/Build/test/BuildIntegrationTests/PublishIntegrationTest.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ public async Task Publish_WithDefaultSettings_Works()
6060
serviceWorkerPath: Path.Combine("serviceworkers", "my-service-worker.js"),
6161
serviceWorkerContent: "// This is the production service worker",
6262
assetsManifestPath: "custom-service-worker-assets.js");
63+
64+
// When publishing without linker, we expect to have collation information present in mscorlib.dll
65+
Assert.AssemblyContainsResource(result, Path.Combine(blazorPublishDirectory, "_framework", "_bin", "mscorlib.dll"), "collation.cjkCHS.bin");
6366
}
6467

6568
[Fact]
@@ -99,6 +102,31 @@ public async Task Publish_InRelease_Works()
99102
// Verify web.config
100103
Assert.FileExists(result, publishDirectory, "web.config");
101104
Assert.FileCountEquals(result, 1, publishDirectory, "*", SearchOption.TopDirectoryOnly);
105+
106+
// When publishing with linker, we expect to have collation information present in mscorlib.dll
107+
Assert.AssemblyContainsResource(result, Path.Combine(blazorPublishDirectory, "_framework", "_bin", "mscorlib.dll"), "collation.cjkCHS.bin");
108+
}
109+
110+
[Fact]
111+
public async Task Publish_LinkerEnabledAndBlazorWebAssemblyPreserveCollationDataSet_CollationInformationIsPreserved()
112+
{
113+
// Arrange
114+
using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary" });
115+
project.Configuration = "Release";
116+
project.AddProjectFileContent(
117+
@"<PropertyGroup>
118+
<BlazorWebAssemblyPreserveCollationData>false</BlazorWebAssemblyPreserveCollationData>
119+
</PropertyGroup>");
120+
var result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish");
121+
122+
Assert.BuildPassed(result);
123+
124+
var publishDirectory = project.PublishOutputDirectory;
125+
126+
var blazorPublishDirectory = Path.Combine(publishDirectory, "wwwroot");
127+
128+
// When publishing with BlazorWebAssemblyPreserveCollationData=false, collation information should be stripped out.
129+
Assert.AssemblyDoesNotContainResource(result, Path.Combine(blazorPublishDirectory, "_framework", "_bin", "mscorlib.dll"), "collation.cjkCHS.bin");
102130
}
103131

104132
[Fact]
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using BasicTestApp;
5+
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure;
6+
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures;
7+
using Microsoft.AspNetCore.E2ETesting;
8+
using OpenQA.Selenium;
9+
using Xunit;
10+
using Xunit.Abstractions;
11+
12+
namespace Microsoft.AspNetCore.Components.E2ETest.Tests
13+
{
14+
public class WebAssemblyStringComparisonTest : ServerTestBase<ToggleExecutionModeServerFixture<Program>>
15+
{
16+
public WebAssemblyStringComparisonTest(
17+
BrowserFixture browserFixture,
18+
ToggleExecutionModeServerFixture<Program> serverFixture,
19+
ITestOutputHelper output)
20+
: base(browserFixture, serverFixture, output)
21+
{
22+
}
23+
24+
[Fact]
25+
public void InvariantCultureWorksAsExpected()
26+
{
27+
Navigate(ServerPathBase, noReload: false);
28+
Browser.MountTestComponent<StringComparisonComponent>();
29+
30+
var result = Browser.Exists(By.Id("results"));
31+
32+
Assert.Equal("Ordinal: False Invariant: True", result.Text);
33+
}
34+
}
35+
}

src/Components/test/testassets/BasicTestApp/Index.razor

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
<option value="BasicTestApp.RouterTest.NavigationManagerComponent">NavigationManager Test</option>
7272
<option value="BasicTestApp.RouterTest.TestRouter">Router</option>
7373
<option value="BasicTestApp.RouterTest.TestRouterWithAdditionalAssembly">Router with additional assembly</option>
74+
<option value="BasicTestApp.StringComparisonComponent">StringComparison</option>
7475
<option value="BasicTestApp.SvgComponent">SVG</option>
7576
<option value="BasicTestApp.SvgWithChildComponent">SVG with child component</option>
7677
<option value="BasicTestApp.TextOnlyComponent">Plain text</option>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
@{
2+
// This test verifies that invariant cultue works correctly in WebAssembly environments. The test case is based on the discussions here: https://stackoverflow.com/a/20085219
3+
var string1 = "Strasse";
4+
var string2 = "Straße";
5+
6+
var ordinalComparison = string1.Equals(string2, StringComparison.Ordinal);
7+
var invariantComparison = string1.Equals(string2, StringComparison.InvariantCulture);
8+
}
9+
10+
<div id="results">Ordinal: @ordinalComparison Invariant: @invariantComparison</div>
11+

0 commit comments

Comments
 (0)