diff --git a/Microsoft.Blazor.Server.Test/ReferencedAssemblyFileProviderTest.cs b/Microsoft.Blazor.Server.Test/ReferencedAssemblyFileProviderTest.cs index 5ef483f062..f421482f4c 100644 --- a/Microsoft.Blazor.Server.Test/ReferencedAssemblyFileProviderTest.cs +++ b/Microsoft.Blazor.Server.Test/ReferencedAssemblyFileProviderTest.cs @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.Blazor.Mono; -using Microsoft.Blazor.Server.ClientFilesystem; +using Microsoft.Blazor.Server.FrameworkFiles; using Mono.Cecil; using System; using System.IO; diff --git a/samples/HostedInAspNet.Client/wwwroot/index.html b/samples/HostedInAspNet.Client/wwwroot/index.html index e1545dd042..943ee7c116 100644 --- a/samples/HostedInAspNet.Client/wwwroot/index.html +++ b/samples/HostedInAspNet.Client/wwwroot/index.html @@ -6,6 +6,5 @@

Hello

- diff --git a/samples/HostedInAspNet.Server/Startup.cs b/samples/HostedInAspNet.Server/Startup.cs index 1729f0bce0..c8f4237729 100644 --- a/samples/HostedInAspNet.Server/Startup.cs +++ b/samples/HostedInAspNet.Server/Startup.cs @@ -22,10 +22,11 @@ namespace HostedInAspNet.Server if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); - app.UseBlazorDevelopmentServer("../HostedInAspNet.Client"); } - app.UseBlazor(clientAssemblyPath: typeof(Client.Program).Assembly.Location); + app.UseBlazor( + assemblyPath: typeof(Client.Program).Assembly.Location, + staticFilesRoot: "../HostedInAspNet.Client/wwwroot"); } } } diff --git a/samples/MonoSanity/Startup.cs b/samples/MonoSanity/Startup.cs index baa1b9db57..78b3751565 100644 --- a/samples/MonoSanity/Startup.cs +++ b/samples/MonoSanity/Startup.cs @@ -11,8 +11,10 @@ namespace MonoSanity public void Configure(IApplicationBuilder app, IHostingEnvironment env) { app.UseDeveloperExceptionPage(); - app.UseFileServer(); - app.UseBlazor(clientAssemblyPath: typeof(MonoSanityClient.Examples).Assembly.Location); + app.UseFileServer(new FileServerOptions { EnableDefaultFiles = true }); + app.UseBlazor( + assemblyPath: typeof(MonoSanityClient.Examples).Assembly.Location, + staticFilesRoot: null); } } } diff --git a/samples/StandaloneApp/wwwroot/index.html b/samples/StandaloneApp/wwwroot/index.html index 048bb1aa3f..83ab2a0396 100644 --- a/samples/StandaloneApp/wwwroot/index.html +++ b/samples/StandaloneApp/wwwroot/index.html @@ -6,7 +6,5 @@

Hello

- diff --git a/src/Microsoft.Blazor.Browser/src/Platform/Mono/MonoPlatform.ts b/src/Microsoft.Blazor.Browser/src/Platform/Mono/MonoPlatform.ts index e3093eaa82..3d6ebdad68 100644 --- a/src/Microsoft.Blazor.Browser/src/Platform/Mono/MonoPlatform.ts +++ b/src/Microsoft.Blazor.Browser/src/Platform/Mono/MonoPlatform.ts @@ -133,21 +133,8 @@ function createEmscriptenModuleInstance(loadAssemblyUrls: string[], onReady: () mono_string_get_utf8 = Module.cwrap('mono_wasm_string_get_utf8', 'number', ['number']); mono_string = Module.cwrap('mono_wasm_string_from_js', 'number', ['string']); - // TODO: Stop hard-coding this list, and instead automatically load whatever - // dependencies were detected in ReferencedAssemblyFileProvider - const loadBclAssemblies = [ - 'mscorlib', - 'System', - 'System.Core', - 'System.Console', - 'System.Runtime', - ]; - - var allAssemblyUrls = loadAssemblyUrls - .concat(loadBclAssemblies.map(name => `_framework/_bin/${name}.dll`)); - Module.FS_createPath('/', 'appBinDir', true, true); - allAssemblyUrls.forEach(url => + loadAssemblyUrls.forEach(url => FS.createPreloadedFile('appBinDir', `${getAssemblyNameFromUrl(url)}.dll`, url, true, false, null, onError)); }); diff --git a/src/Microsoft.Blazor.DevHost/Server/Startup.cs b/src/Microsoft.Blazor.DevHost/Server/Startup.cs index 81a1d435a1..4a4c664162 100644 --- a/src/Microsoft.Blazor.DevHost/Server/Startup.cs +++ b/src/Microsoft.Blazor.DevHost/Server/Startup.cs @@ -20,8 +20,9 @@ namespace Microsoft.Blazor.DevHost.Server public void Configure(IApplicationBuilder app) { app.UseDeveloperExceptionPage(); - app.UseBlazorDevelopmentServer("."); - app.UseBlazor(clientAssemblyPath: FindClientAssembly(app).Location); + app.UseBlazor( + assemblyPath: FindClientAssembly(app).Location, + staticFilesRoot: "wwwroot"); } private static Assembly FindClientAssembly(IApplicationBuilder app) diff --git a/src/Microsoft.Blazor.Server/BlazorAppBuilderExtensions.cs b/src/Microsoft.Blazor.Server/BlazorAppBuilderExtensions.cs index 48227cc5c1..7f796faee5 100644 --- a/src/Microsoft.Blazor.Server/BlazorAppBuilderExtensions.cs +++ b/src/Microsoft.Blazor.Server/BlazorAppBuilderExtensions.cs @@ -1,11 +1,14 @@ // 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 Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.StaticFiles; -using Microsoft.Blazor.Server.ClientFilesystem; +using Microsoft.Blazor.Server.FrameworkFiles; +using Microsoft.Blazor.Server.WebRootFiles; +using Microsoft.Extensions.DependencyInjection; using System.Collections.Generic; +using System.IO; using System.Net.Mime; -using System.Reflection; namespace Microsoft.AspNetCore.Builder { @@ -13,12 +16,35 @@ namespace Microsoft.AspNetCore.Builder { public static void UseBlazor( this IApplicationBuilder applicationBuilder, - string clientAssemblyPath) + string assemblyPath, + string staticFilesRoot) { + var frameworkFileProvider = FrameworkFileProvider.Instantiate(assemblyPath); + + if (staticFilesRoot != null) + { + var env = applicationBuilder.ApplicationServices.GetRequiredService(); + var clientWebRoot = Path.GetFullPath(Path.Combine(env.ContentRootPath, staticFilesRoot)); + var webRootFileProvider = WebRootFileProvider.Instantiate( + clientWebRoot, + Path.GetFileNameWithoutExtension(assemblyPath), + frameworkFileProvider.GetDirectoryContents("/_bin")); + + applicationBuilder.UseDefaultFiles(new DefaultFilesOptions + { + FileProvider = webRootFileProvider + }); + + applicationBuilder.UseStaticFiles(new StaticFileOptions + { + FileProvider = webRootFileProvider + }); + } + applicationBuilder.UseStaticFiles(new StaticFileOptions { RequestPath = "/_framework", - FileProvider = ClientFileProvider.Instantiate(clientAssemblyPath), + FileProvider = frameworkFileProvider, ContentTypeProvider = CreateContentTypeProvider(), }); } diff --git a/src/Microsoft.Blazor.Server/DevelopmentServer/DevelopmentServerApplicationBuilderExtensions.cs b/src/Microsoft.Blazor.Server/DevelopmentServer/DevelopmentServerApplicationBuilderExtensions.cs deleted file mode 100644 index 623fafb972..0000000000 --- a/src/Microsoft.Blazor.Server/DevelopmentServer/DevelopmentServerApplicationBuilderExtensions.cs +++ /dev/null @@ -1,38 +0,0 @@ -// 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 Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.FileProviders; -using System.IO; - -namespace Microsoft.AspNetCore.Builder -{ - public static class DevelopmentServerApplicationBuilderExtensions - { - public static void UseBlazorDevelopmentServer( - this IApplicationBuilder applicationBuilder, - string relativeSourcePath) - { - var env = applicationBuilder.ApplicationServices.GetRequiredService(); - var sourcePath = Path.Combine(env.ContentRootPath, relativeSourcePath); - ServeWebRoot(applicationBuilder, sourcePath); - } - - private static void ServeWebRoot(IApplicationBuilder applicationBuilder, string clientAppSourceRoot) - { - var webRootFileProvider = new PhysicalFileProvider( - Path.Combine(clientAppSourceRoot, "wwwroot")); - - applicationBuilder.UseDefaultFiles(new DefaultFilesOptions - { - FileProvider = webRootFileProvider - }); - - applicationBuilder.UseStaticFiles(new StaticFileOptions - { - FileProvider = webRootFileProvider - }); - } - } -} diff --git a/src/Microsoft.Blazor.Server/ClientFilesystem/ClientFileProvider.cs b/src/Microsoft.Blazor.Server/FrameworkFiles/FrameworkFileProvider.cs similarity index 87% rename from src/Microsoft.Blazor.Server/ClientFilesystem/ClientFileProvider.cs rename to src/Microsoft.Blazor.Server/FrameworkFiles/FrameworkFileProvider.cs index 68909bbdae..854ffee3b0 100644 --- a/src/Microsoft.Blazor.Server/ClientFilesystem/ClientFileProvider.cs +++ b/src/Microsoft.Blazor.Server/FrameworkFiles/FrameworkFileProvider.cs @@ -5,11 +5,10 @@ using Microsoft.Blazor.Browser; using Microsoft.Blazor.Mono; using Microsoft.Extensions.FileProviders; using System.IO; -using System.Reflection; -namespace Microsoft.Blazor.Server.ClientFilesystem +namespace Microsoft.Blazor.Server.FrameworkFiles { - internal static class ClientFileProvider + internal static class FrameworkFileProvider { public static IFileProvider Instantiate(string clientAssemblyPath) => new CompositeFileProvider( diff --git a/src/Microsoft.Blazor.Server/ClientFilesystem/ReferencedAssemblyFileProvider.cs b/src/Microsoft.Blazor.Server/FrameworkFiles/ReferencedAssemblyFileProvider.cs similarity index 98% rename from src/Microsoft.Blazor.Server/ClientFilesystem/ReferencedAssemblyFileProvider.cs rename to src/Microsoft.Blazor.Server/FrameworkFiles/ReferencedAssemblyFileProvider.cs index 311b69ac13..f05bca0444 100644 --- a/src/Microsoft.Blazor.Server/ClientFilesystem/ReferencedAssemblyFileProvider.cs +++ b/src/Microsoft.Blazor.Server/FrameworkFiles/ReferencedAssemblyFileProvider.cs @@ -7,7 +7,7 @@ using System.Linq; using Mono.Cecil; using Microsoft.Blazor.Internal.Common.FileProviders; -namespace Microsoft.Blazor.Server.ClientFilesystem +namespace Microsoft.Blazor.Server.FrameworkFiles { internal class ReferencedAssemblyFileProvider : InMemoryFileProvider { diff --git a/src/Microsoft.Blazor.Server/ClientFilesystem/ReferencedAssemblyResolver.cs b/src/Microsoft.Blazor.Server/FrameworkFiles/ReferencedAssemblyResolver.cs similarity index 97% rename from src/Microsoft.Blazor.Server/ClientFilesystem/ReferencedAssemblyResolver.cs rename to src/Microsoft.Blazor.Server/FrameworkFiles/ReferencedAssemblyResolver.cs index 51b4e7191a..0d43c7d004 100644 --- a/src/Microsoft.Blazor.Server/ClientFilesystem/ReferencedAssemblyResolver.cs +++ b/src/Microsoft.Blazor.Server/FrameworkFiles/ReferencedAssemblyResolver.cs @@ -5,7 +5,7 @@ using Microsoft.Extensions.FileProviders; using System.IO; using System.Linq; -namespace Microsoft.Blazor.Server.ClientFilesystem +namespace Microsoft.Blazor.Server.FrameworkFiles { internal class ReferencedAssemblyResolver { diff --git a/src/Microsoft.Blazor.Server/WebRootFiles/IndexHtmlFileProvider.cs b/src/Microsoft.Blazor.Server/WebRootFiles/IndexHtmlFileProvider.cs new file mode 100644 index 0000000000..b19dbfb623 --- /dev/null +++ b/src/Microsoft.Blazor.Server/WebRootFiles/IndexHtmlFileProvider.cs @@ -0,0 +1,58 @@ +// 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 Microsoft.Blazor.Internal.Common.FileProviders; +using System.IO; +using System.Collections.Generic; +using System.Text; +using Microsoft.Extensions.FileProviders; +using System.Linq; + +namespace Microsoft.Blazor.Server.WebRootFiles +{ + internal class IndexHtmlFileProvider : InMemoryFileProvider + { + public IndexHtmlFileProvider(string clientWebRoot, string assemblyName, IEnumerable binFiles) + : base(ComputeContents(clientWebRoot, assemblyName, binFiles)) + { + } + + private static IEnumerable<(string, Stream)> ComputeContents(string clientWebRoot, string assemblyName, IEnumerable binFiles) + { + var html = GetIndexHtmlContents(clientWebRoot, assemblyName, binFiles); + if (html != null) + { + var htmlBytes = Encoding.UTF8.GetBytes(html); + var htmlStream = new MemoryStream(htmlBytes); + yield return ("/index.html", htmlStream); + } + } + + private static string GetIndexHtmlContents(string clientWebRoot, string assemblyName, IEnumerable binFiles) + { + var indexHtmlPath = Path.Combine(clientWebRoot, "index.html"); + if (!File.Exists(indexHtmlPath)) + { + return null; + } + + // TODO: Consider parsing the HTML properly so for example we don't insert into + // the wrong place if there was also '' in a JavaScript string literal + return File.ReadAllText(indexHtmlPath) + .Replace("", CreateBootMarkup(assemblyName, binFiles) + "\n"); + } + + private static string CreateBootMarkup(string assemblyName, IEnumerable binFiles) + { + var assemblyNameWithExtension = $"{assemblyName}.dll"; + var referenceNames = binFiles + .Where(file => !string.Equals(file.Name, assemblyNameWithExtension)) + .Select(file => file.Name); + var referencesAttribute = string.Join(',', referenceNames.ToArray()); + + return $""; + } + } +} diff --git a/src/Microsoft.Blazor.Server/WebRootFiles/WebRootFileProvider.cs b/src/Microsoft.Blazor.Server/WebRootFiles/WebRootFileProvider.cs new file mode 100644 index 0000000000..ed33eb66f0 --- /dev/null +++ b/src/Microsoft.Blazor.Server/WebRootFiles/WebRootFileProvider.cs @@ -0,0 +1,17 @@ +// 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 Microsoft.Extensions.FileProviders; +using System.Collections.Generic; + +namespace Microsoft.Blazor.Server.WebRootFiles +{ + internal static class WebRootFileProvider + { + public static IFileProvider Instantiate( + string clientWebRoot, string assemblyName, IEnumerable binFiles) + => new CompositeFileProvider( + new IndexHtmlFileProvider(clientWebRoot, assemblyName, binFiles), + new PhysicalFileProvider(clientWebRoot)); + } +}