diff --git a/Microsoft.Blazor.Server.Test/Microsoft.Blazor.Server.Test.csproj b/Microsoft.Blazor.Server.Test/Microsoft.Blazor.Server.Test.csproj
index 87ad644bcd..ec5898c951 100644
--- a/Microsoft.Blazor.Server.Test/Microsoft.Blazor.Server.Test.csproj
+++ b/Microsoft.Blazor.Server.Test/Microsoft.Blazor.Server.Test.csproj
@@ -13,7 +13,7 @@
-
+
diff --git a/Microsoft.Blazor.Server.Test/ReferencedAssemblyFileProviderTest.cs b/Microsoft.Blazor.Server.Test/ReferencedAssemblyFileProviderTest.cs
index 28faf2a8ec..36eb98c50c 100644
--- a/Microsoft.Blazor.Server.Test/ReferencedAssemblyFileProviderTest.cs
+++ b/Microsoft.Blazor.Server.Test/ReferencedAssemblyFileProviderTest.cs
@@ -2,6 +2,9 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.Blazor.Mono;
+using Mono.Cecil;
+using System;
+using System.IO;
using System.Linq;
using Xunit;
@@ -12,8 +15,10 @@ namespace Microsoft.Blazor.Server.Test
[Fact]
public void RootDirContainsOnlyBinDir()
{
+ var (entrypoint, entrypointData) = GetBclAssemblyForTest("mscorlib");
var provider = new ReferencedAssemblyFileProvider(
- typeof (HostedInAspNet.Client.Program).Assembly,
+ entrypoint,
+ entrypointData,
MonoStaticFileProvider.Instance);
Assert.Collection(provider.GetDirectoryContents("/"), item =>
{
@@ -23,19 +28,89 @@ namespace Microsoft.Blazor.Server.Test
}
[Fact]
- public void FindsEntrypointAssemblyAndReferencedAssemblies()
+ public void FindsReferencedAssemblyGraphSimple()
{
+ var (entrypoint, entrypointData) = GetBclAssemblyForTest("System.Linq.Expressions");
var provider = new ReferencedAssemblyFileProvider(
- typeof(HostedInAspNet.Client.Program).Assembly,
+ entrypoint,
+ entrypointData,
MonoStaticFileProvider.Instance);
var contents = provider.GetDirectoryContents("/bin").OrderBy(i => i.Name).ToList();
Assert.Collection(contents,
- item => { Assert.Equal("/bin/HostedInAspNet.Client.dll", item.PhysicalPath); },
item => { Assert.Equal("/bin/mscorlib.dll", item.PhysicalPath); },
- item => { Assert.Equal("/bin/System.Console.dll", item.PhysicalPath); },
item => { Assert.Equal("/bin/System.Core.dll", item.PhysicalPath); },
item => { Assert.Equal("/bin/System.dll", item.PhysicalPath); },
- item => { Assert.Equal("/bin/System.Runtime.dll", item.PhysicalPath); });
+ item => { Assert.Equal("/bin/System.Linq.Expressions.dll", item.PhysicalPath); });
+ }
+
+ [Fact]
+ public void FindsReferencedAssemblyGraphRealistic()
+ {
+ // Arrange
+ var standaloneAppAssemblyLocation = typeof(StandaloneApp.Program).Assembly.Location;
+ var provider = new ReferencedAssemblyFileProvider(
+ AssemblyDefinition.ReadAssembly(standaloneAppAssemblyLocation),
+ File.ReadAllBytes(standaloneAppAssemblyLocation),
+ MonoStaticFileProvider.Instance);
+ var expectedContents = new[]
+ {
+ /*
+ The current Mono WASM BCL forwards from netstandard.dll to various facade assemblies
+ in which small bits of implementation live, such as System.Xml.XPath.XDocument. So
+ if you reference netstandard, then you also reference System.Xml.XPath.XDocument.dll,
+ even though you're very unlikely to be calling it at runtime. That's why the following
+ list (for a very basic Blazor app) is longer than you'd expect.
+
+ These redundant references could be stripped out during publishing, but it's still
+ unfortunate that in development mode you'd see all these unexpected assemblies get
+ fetched from the server. We should try to get the Mono WASM BCL reorganized so that
+ all the implementation goes into mscorlib.dll, with the facade assemblies existing only
+ in case someone (or some 3rd party assembly) references them directly, but with their
+ implementations 100% forwarding to mscorlib.dll. Then in development you'd fetch far
+ fewer assemblies from the server, and during publishing, illink would remove all the
+ uncalled implementation code from mscorlib.dll anyway.
+ */
+ "/bin/Microsoft.Blazor.dll",
+ "/bin/mscorlib.dll",
+ "/bin/netstandard.dll",
+ "/bin/StandaloneApp.dll",
+ "/bin/System.Console.dll",
+ "/bin/System.Core.dll",
+ "/bin/System.Diagnostics.StackTrace.dll",
+ "/bin/System.dll",
+ "/bin/System.Globalization.Extensions.dll",
+ "/bin/System.Runtime.dll",
+ "/bin/System.Runtime.InteropServices.RuntimeInformation.dll",
+ "/bin/System.Runtime.Serialization.Primitives.dll",
+ "/bin/System.Runtime.Serialization.Xml.dll",
+ "/bin/System.Security.Cryptography.Algorithms.dll",
+ "/bin/System.Security.SecureString.dll",
+ "/bin/System.Xml.XPath.XDocument.dll",
+ };
+
+ // Act
+ var contents = provider.GetDirectoryContents("/bin")
+ .OrderBy(i => i.Name, StringComparer.InvariantCulture).ToList();
+
+ // Assert
+ Assert.Equal(expectedContents.Length, contents.Count);
+ for (var i = 0; i < expectedContents.Length; i++)
+ {
+ Assert.Equal(expectedContents[i], contents[i].PhysicalPath);
+ }
+ }
+
+ private static (AssemblyDefinition, byte[]) GetBclAssemblyForTest(string name)
+ {
+ var possibleFilenames = new[] { $"/bcl/{name}.dll", $"/bcl/Facades/{name}.dll" };
+ var fileInfo = possibleFilenames
+ .Select(MonoStaticFileProvider.Instance.GetFileInfo)
+ .First(item => item.Exists);
+ using (var data = new MemoryStream())
+ {
+ fileInfo.CreateReadStream().CopyTo(data);
+ return (AssemblyDefinition.ReadAssembly(fileInfo.CreateReadStream()), data.ToArray());
+ }
}
}
}
diff --git a/samples/StandaloneApp/Program.cs b/samples/StandaloneApp/Program.cs
index a439e0def1..2da2284002 100644
--- a/samples/StandaloneApp/Program.cs
+++ b/samples/StandaloneApp/Program.cs
@@ -9,7 +9,7 @@ namespace StandaloneApp
{
public static void Main(string[] args)
{
- Console.WriteLine("Hello, world!");
+ Console.WriteLine(Microsoft.Blazor.Test.Message);
}
}
}
diff --git a/samples/StandaloneApp/StandaloneApp.csproj b/samples/StandaloneApp/StandaloneApp.csproj
index d6cd99b14b..2af197f092 100644
--- a/samples/StandaloneApp/StandaloneApp.csproj
+++ b/samples/StandaloneApp/StandaloneApp.csproj
@@ -11,6 +11,7 @@
-->
+
run --project ..\..\src\Microsoft.Blazor.DevHost --no-build serve
diff --git a/src/Microsoft.Blazor.Server/ReferencedAssemblyFileProvider.cs b/src/Microsoft.Blazor.Server/ReferencedAssemblyFileProvider.cs
index 8ec5d26975..0c61342b4b 100644
--- a/src/Microsoft.Blazor.Server/ReferencedAssemblyFileProvider.cs
+++ b/src/Microsoft.Blazor.Server/ReferencedAssemblyFileProvider.cs
@@ -14,20 +14,21 @@ namespace Microsoft.Blazor.Server
{
internal class ReferencedAssemblyFileProvider : InMemoryFileProvider
{
- public ReferencedAssemblyFileProvider(Assembly entrypointAssembly, IFileProvider clientBcl)
- : base(ComputeContents(entrypointAssembly, clientBcl))
+ public ReferencedAssemblyFileProvider(
+ AssemblyDefinition entrypoint,
+ byte[] entrypointData,
+ IFileProvider clientBcl)
+ : base(ComputeContents(entrypoint, entrypointData, clientBcl))
{
}
private static IEnumerable<(string, Stream)> ComputeContents(
- Assembly entrypointAssembly,
+ AssemblyDefinition entrypoint,
+ byte[] entrypointData,
IFileProvider clientBcl)
{
var foundAssemblies = new Dictionary();
- AddWithReferencesRecursive(
- new ReferencedAssembly(AssemblyDefinition.ReadAssembly(entrypointAssembly.Location)),
- clientBcl,
- foundAssemblies);
+ AddWithReferencesRecursive(new ReferencedAssembly(entrypoint, entrypointData), clientBcl, foundAssemblies);
return foundAssemblies.Values.Select(assembly => (
$"/bin/{assembly.Name}.dll",
@@ -72,7 +73,9 @@ namespace Microsoft.Blazor.Server
// (e.g., if it's in the app's bin directory, or a NuGet package)
var nativelyResolved = module.AssemblyResolver.Resolve(referenceName);
return AllowServingAssembly(nativelyResolved)
- ? new ReferencedAssembly(nativelyResolved)
+ ? new ReferencedAssembly(
+ nativelyResolved,
+ File.ReadAllBytes(nativelyResolved.MainModule.FileName))
: null;
}
catch (AssemblyResolutionException)
@@ -128,10 +131,10 @@ namespace Microsoft.Blazor.Server
public byte[] Data { get; }
public AssemblyDefinition Definition { get; }
- public ReferencedAssembly(AssemblyDefinition definition)
+ public ReferencedAssembly(AssemblyDefinition definition, byte[] rawData)
{
Name = definition.Name.Name;
- Data = File.ReadAllBytes(definition.MainModule.FileName);
+ Data = rawData;
Definition = definition;
}
diff --git a/src/Microsoft.Blazor/Test.cs b/src/Microsoft.Blazor/Test.cs
new file mode 100644
index 0000000000..3aafc43123
--- /dev/null
+++ b/src/Microsoft.Blazor/Test.cs
@@ -0,0 +1,10 @@
+// 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.
+
+namespace Microsoft.Blazor
+{
+ public static class Test
+ {
+ public readonly static string Message = "Hello, world!";
+ }
+}