Adding ability to qualify the entry point of the main assembly
This commit is contained in:
parent
1e0836167d
commit
1653e56b98
|
|
@ -5,7 +5,15 @@ using Microsoft.AspNetCore.Blazor.Browser.Rendering;
|
||||||
|
|
||||||
namespace StandaloneApp
|
namespace StandaloneApp
|
||||||
{
|
{
|
||||||
public class Program
|
public class ProgramX
|
||||||
|
{
|
||||||
|
public static void Main(string[] args)
|
||||||
|
{
|
||||||
|
new BrowserRenderer().AddComponent<Home>("app");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ProgramY
|
||||||
{
|
{
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
<!-- Local alternative to <RunArguments>blazor serve</RunArguments> -->
|
<!-- Local alternative to <RunArguments>blazor serve</RunArguments> -->
|
||||||
<RunCommand>dotnet</RunCommand>
|
<RunCommand>dotnet</RunCommand>
|
||||||
<RunArguments>run --project ../../src/Microsoft.AspNetCore.Blazor.DevHost serve</RunArguments>
|
<RunArguments>run --project ../../src/Microsoft.AspNetCore.Blazor.DevHost serve</RunArguments>
|
||||||
|
<StartupObject>StandaloneApp.ProgramY</StartupObject>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,13 @@ async function boot() {
|
||||||
// Read startup config from the <script> element that's importing this file
|
// Read startup config from the <script> element that's importing this file
|
||||||
const allScriptElems = document.getElementsByTagName('script');
|
const allScriptElems = document.getElementsByTagName('script');
|
||||||
const thisScriptElem = document.currentScript || allScriptElems[allScriptElems.length - 1];
|
const thisScriptElem = document.currentScript || allScriptElems[allScriptElems.length - 1];
|
||||||
const entryPoint = thisScriptElem.getAttribute('main');
|
const entryPointDll = thisScriptElem.getAttribute('main');
|
||||||
if (!entryPoint) {
|
if (!entryPointDll) {
|
||||||
throw new Error('Missing "main" attribute on Blazor Config script tag.');
|
throw new Error('Missing "main" attribute on Blazor script tag.');
|
||||||
}
|
}
|
||||||
const entryPointAssemblyName = getAssemblyNameFromUrl(entryPoint);
|
// TODO: should method be a required, non-empty field or just an optional *hint*?
|
||||||
|
const entryPointMethod = thisScriptElem.getAttribute('entry-point');
|
||||||
|
const entryPointAssemblyName = getAssemblyNameFromUrl(entryPointDll);
|
||||||
const referenceAssembliesCommaSeparated = thisScriptElem.getAttribute('references') || '';
|
const referenceAssembliesCommaSeparated = thisScriptElem.getAttribute('references') || '';
|
||||||
const referenceAssemblies = referenceAssembliesCommaSeparated
|
const referenceAssemblies = referenceAssembliesCommaSeparated
|
||||||
.split(',')
|
.split(',')
|
||||||
|
|
@ -19,7 +21,7 @@ async function boot() {
|
||||||
.filter(s => !!s);
|
.filter(s => !!s);
|
||||||
|
|
||||||
// Determine the URLs of the assemblies we want to load
|
// Determine the URLs of the assemblies we want to load
|
||||||
const loadAssemblyUrls = [entryPoint]
|
const loadAssemblyUrls = [entryPointDll]
|
||||||
.concat(referenceAssemblies)
|
.concat(referenceAssemblies)
|
||||||
.map(filename => `/_framework/_bin/${filename}`);
|
.map(filename => `/_framework/_bin/${filename}`);
|
||||||
|
|
||||||
|
|
@ -30,7 +32,7 @@ async function boot() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start up the application
|
// Start up the application
|
||||||
platform.callEntryPoint(entryPointAssemblyName, []);
|
platform.callEntryPoint(entryPointAssemblyName, entryPointMethod, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
boot();
|
boot();
|
||||||
|
|
|
||||||
|
|
@ -45,11 +45,24 @@ export const monoPlatform: Platform = {
|
||||||
return methodHandle;
|
return methodHandle;
|
||||||
},
|
},
|
||||||
|
|
||||||
callEntryPoint: function callEntryPoint(assemblyName: string, args: System_Object[]): void {
|
callEntryPoint: function callEntryPoint(assemblyName: string, methodName: string | null, args: System_Object[]): void {
|
||||||
// TODO: There should be a proper way of running whatever counts as the entrypoint without
|
// TODO: There should be a proper way of running whatever counts as the entrypoint without
|
||||||
// having to specify what method it is, but I haven't found it. The code here assumes
|
// having to specify what method it is, but I haven't found it. The code here assumes
|
||||||
// that the entry point is "<assemblyname>.Program.Main" (i.e., namespace == assembly name).
|
// that the entry point is "<assemblyname>.Program.Main" (i.e., namespace == assembly name).
|
||||||
const entryPointMethod = monoPlatform.findMethod(assemblyName, assemblyName, 'Program', 'Main');
|
if (!methodName)
|
||||||
|
methodName = assemblyName + ".Program::Main";
|
||||||
|
|
||||||
|
var classAndMethod = methodName.split("::");
|
||||||
|
if (classAndMethod.length != 2)
|
||||||
|
throw new Error("malformed entry point method name; could not resolve class name and method name");
|
||||||
|
|
||||||
|
methodName = classAndMethod[1];
|
||||||
|
const nsAndClass = classAndMethod[0];
|
||||||
|
const lastDot = nsAndClass.lastIndexOf(".");
|
||||||
|
// It's possible the entry point method has no namespace
|
||||||
|
const namespace = lastDot > -1 ? classAndMethod[0].substring(0, lastDot) : "";
|
||||||
|
const className = lastDot > -1 ? classAndMethod[0].substring(lastDot + 1) : classAndMethod[0];
|
||||||
|
const entryPointMethod = monoPlatform.findMethod(assemblyName, namespace, className, methodName);
|
||||||
monoPlatform.callMethod(entryPointMethod, null, args);
|
monoPlatform.callMethod(entryPointMethod, null, args);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
export interface Platform {
|
export interface Platform {
|
||||||
start(loadAssemblyUrls: string[]): Promise<void>;
|
start(loadAssemblyUrls: string[]): Promise<void>;
|
||||||
|
|
||||||
callEntryPoint(assemblyName: string, args: System_Object[]);
|
callEntryPoint(assemblyName: string, assemblyMethod: string | null, args: System_Object[]);
|
||||||
findMethod(assemblyName: string, namespace: string, className: string, methodName: string): MethodHandle;
|
findMethod(assemblyName: string, namespace: string, className: string, methodName: string): MethodHandle;
|
||||||
callMethod(method: MethodHandle, target: System_Object | null, args: System_Object[]): System_Object;
|
callMethod(method: MethodHandle, target: System_Object | null, args: System_Object[]): System_Object;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Blazor.Internal.Common.FileProviders;
|
using Microsoft.AspNetCore.Blazor.Internal.Common.FileProviders;
|
||||||
using Microsoft.Extensions.FileProviders;
|
using Microsoft.Extensions.FileProviders;
|
||||||
|
using Mono.Cecil;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
|
|
@ -50,8 +51,17 @@ namespace Microsoft.AspNetCore.Blazor.Build.Core.FileSystem
|
||||||
{
|
{
|
||||||
var template = File.ReadAllText(path);
|
var template = File.ReadAllText(path);
|
||||||
var assemblyName = Path.GetFileNameWithoutExtension(assemblyPath);
|
var assemblyName = Path.GetFileNameWithoutExtension(assemblyPath);
|
||||||
|
var assemblyEntryPoint = string.Empty;
|
||||||
var binFiles = frameworkFileProvider.GetDirectoryContents("/_bin");
|
var binFiles = frameworkFileProvider.GetDirectoryContents("/_bin");
|
||||||
result = new IndexHtmlFileProvider(template, assemblyName, binFiles);
|
|
||||||
|
using (var asmDef = AssemblyDefinition.ReadAssembly(assemblyPath))
|
||||||
|
{
|
||||||
|
var ep = asmDef.EntryPoint;
|
||||||
|
if (ep != null)
|
||||||
|
assemblyEntryPoint = $"{ep.DeclaringType.FullName}::{ep.Name}";
|
||||||
|
}
|
||||||
|
|
||||||
|
result = new IndexHtmlFileProvider(template, assemblyName, assemblyEntryPoint, binFiles);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,16 +15,23 @@ namespace Microsoft.AspNetCore.Blazor.Build.Core.FileSystem
|
||||||
{
|
{
|
||||||
internal class IndexHtmlFileProvider : InMemoryFileProvider
|
internal class IndexHtmlFileProvider : InMemoryFileProvider
|
||||||
{
|
{
|
||||||
public IndexHtmlFileProvider(string htmlTemplate, string assemblyName, IEnumerable<IFileInfo> binFiles)
|
public IndexHtmlFileProvider(
|
||||||
: base(ComputeContents(htmlTemplate, assemblyName, binFiles))
|
string htmlTemplate,
|
||||||
|
string assemblyName,
|
||||||
|
string assemblyEntryPoint,
|
||||||
|
IEnumerable<IFileInfo> binFiles) : base(ComputeContents(htmlTemplate, assemblyName, assemblyEntryPoint, binFiles))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IEnumerable<(string, byte[])> ComputeContents(string htmlTemplate, string assemblyName, IEnumerable<IFileInfo> binFiles)
|
private static IEnumerable<(string, byte[])> ComputeContents(
|
||||||
|
string htmlTemplate,
|
||||||
|
string assemblyName,
|
||||||
|
string assemblyEntryPoint,
|
||||||
|
IEnumerable<IFileInfo> binFiles)
|
||||||
{
|
{
|
||||||
if (htmlTemplate != null)
|
if (htmlTemplate != null)
|
||||||
{
|
{
|
||||||
var html = GetIndexHtmlContents(htmlTemplate, assemblyName, binFiles);
|
var html = GetIndexHtmlContents(htmlTemplate, assemblyName, assemblyEntryPoint, binFiles);
|
||||||
var htmlBytes = Encoding.UTF8.GetBytes(html);
|
var htmlBytes = Encoding.UTF8.GetBytes(html);
|
||||||
yield return ("/index.html", htmlBytes);
|
yield return ("/index.html", htmlBytes);
|
||||||
}
|
}
|
||||||
|
|
@ -48,7 +55,11 @@ namespace Microsoft.AspNetCore.Blazor.Build.Core.FileSystem
|
||||||
/// responsible for completing the Blazor boot process.
|
/// responsible for completing the Blazor boot process.
|
||||||
/// </para>
|
/// </para>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
private static string GetIndexHtmlContents(string htmlTemplate, string assemblyName, IEnumerable<IFileInfo> binFiles)
|
private static string GetIndexHtmlContents(
|
||||||
|
string htmlTemplate,
|
||||||
|
string assemblyName,
|
||||||
|
string assemblyEntryPoint,
|
||||||
|
IEnumerable<IFileInfo> binFiles)
|
||||||
{
|
{
|
||||||
var resultBuilder = new StringBuilder();
|
var resultBuilder = new StringBuilder();
|
||||||
|
|
||||||
|
|
@ -86,6 +97,7 @@ namespace Microsoft.AspNetCore.Blazor.Build.Core.FileSystem
|
||||||
AppendScriptTagWithBootConfig(
|
AppendScriptTagWithBootConfig(
|
||||||
resultBuilder,
|
resultBuilder,
|
||||||
assemblyName,
|
assemblyName,
|
||||||
|
assemblyEntryPoint,
|
||||||
binFiles,
|
binFiles,
|
||||||
tag.Attributes);
|
tag.Attributes);
|
||||||
|
|
||||||
|
|
@ -123,6 +135,7 @@ namespace Microsoft.AspNetCore.Blazor.Build.Core.FileSystem
|
||||||
private static void AppendScriptTagWithBootConfig(
|
private static void AppendScriptTagWithBootConfig(
|
||||||
StringBuilder resultBuilder,
|
StringBuilder resultBuilder,
|
||||||
string assemblyName,
|
string assemblyName,
|
||||||
|
string assemblyEntryPoint,
|
||||||
IEnumerable<IFileInfo> binFiles,
|
IEnumerable<IFileInfo> binFiles,
|
||||||
List<KeyValuePair<string, string>> attributes)
|
List<KeyValuePair<string, string>> attributes)
|
||||||
{
|
{
|
||||||
|
|
@ -136,6 +149,7 @@ namespace Microsoft.AspNetCore.Blazor.Build.Core.FileSystem
|
||||||
attributesDict.Remove("type");
|
attributesDict.Remove("type");
|
||||||
attributesDict["src"] = "/_framework/blazor.js";
|
attributesDict["src"] = "/_framework/blazor.js";
|
||||||
attributesDict["main"] = assemblyNameWithExtension;
|
attributesDict["main"] = assemblyNameWithExtension;
|
||||||
|
attributesDict["entry-point"] = assemblyEntryPoint;
|
||||||
attributesDict["references"] = referencesAttribute;
|
attributesDict["references"] = referencesAttribute;
|
||||||
|
|
||||||
resultBuilder.Append("<script");
|
resultBuilder.Append("<script");
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Blazor.Server.Test
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var instance = new IndexHtmlFileProvider(
|
var instance = new IndexHtmlFileProvider(
|
||||||
null, "fakeassembly", Enumerable.Empty<IFileInfo>());
|
null, "fakeassembly", null, Enumerable.Empty<IFileInfo>());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var file = instance.GetFileInfo("/index.html");
|
var file = instance.GetFileInfo("/index.html");
|
||||||
|
|
@ -33,7 +33,7 @@ namespace Microsoft.AspNetCore.Blazor.Server.Test
|
||||||
// Arrange
|
// Arrange
|
||||||
var htmlTemplate = "test";
|
var htmlTemplate = "test";
|
||||||
var instance = new IndexHtmlFileProvider(
|
var instance = new IndexHtmlFileProvider(
|
||||||
htmlTemplate, "fakeassembly", Enumerable.Empty<IFileInfo>());
|
htmlTemplate, "fakeassembly", null, Enumerable.Empty<IFileInfo>());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var file = instance.GetFileInfo("/index.html");
|
var file = instance.GetFileInfo("/index.html");
|
||||||
|
|
@ -52,7 +52,7 @@ namespace Microsoft.AspNetCore.Blazor.Server.Test
|
||||||
// Arrange
|
// Arrange
|
||||||
var htmlTemplate = "test";
|
var htmlTemplate = "test";
|
||||||
var instance = new IndexHtmlFileProvider(
|
var instance = new IndexHtmlFileProvider(
|
||||||
htmlTemplate, "fakeassembly", Enumerable.Empty<IFileInfo>());
|
htmlTemplate, "fakeassembly", null, Enumerable.Empty<IFileInfo>());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var directory = instance.GetDirectoryContents(string.Empty);
|
var directory = instance.GetDirectoryContents(string.Empty);
|
||||||
|
|
@ -86,7 +86,7 @@ namespace Microsoft.AspNetCore.Blazor.Server.Test
|
||||||
new TestFileInfo("MyApp.ClassLib.dll"),
|
new TestFileInfo("MyApp.ClassLib.dll"),
|
||||||
};
|
};
|
||||||
var instance = new IndexHtmlFileProvider(
|
var instance = new IndexHtmlFileProvider(
|
||||||
htmlTemplate, "MyApp.Entrypoint", dependencies);
|
htmlTemplate, "MyApp.Entrypoint", null, dependencies);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var file = instance.GetFileInfo("/index.html");
|
var file = instance.GetFileInfo("/index.html");
|
||||||
|
|
@ -120,7 +120,7 @@ namespace Microsoft.AspNetCore.Blazor.Server.Test
|
||||||
new TestFileInfo("MyApp.ClassLib.dll"),
|
new TestFileInfo("MyApp.ClassLib.dll"),
|
||||||
};
|
};
|
||||||
var instance = new IndexHtmlFileProvider(
|
var instance = new IndexHtmlFileProvider(
|
||||||
htmlTemplate, "MyApp.Entrypoint", dependencies);
|
htmlTemplate, "MyApp.Entrypoint", null, dependencies);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var file = instance.GetFileInfo("/index.html");
|
var file = instance.GetFileInfo("/index.html");
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ namespace Microsoft.AspNetCore.Blazor.Server.Test
|
||||||
public void FindsReferencedAssemblyGraphRealistic()
|
public void FindsReferencedAssemblyGraphRealistic()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var standaloneAppAssembly = typeof(StandaloneApp.Program).Assembly;
|
var standaloneAppAssembly = typeof(StandaloneApp.ProgramY).Assembly;
|
||||||
var provider = new ReferencedAssemblyFileProvider(
|
var provider = new ReferencedAssemblyFileProvider(
|
||||||
standaloneAppAssembly.GetName().Name,
|
standaloneAppAssembly.GetName().Name,
|
||||||
new ReferencedAssemblyResolver(
|
new ReferencedAssemblyResolver(
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,9 @@ using Xunit;
|
||||||
namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
|
||||||
{
|
{
|
||||||
public class StandaloneAppTest
|
public class StandaloneAppTest
|
||||||
: ServerTestBase<DevHostServerFixture<StandaloneApp.Program>>
|
: ServerTestBase<DevHostServerFixture<StandaloneApp.ProgramY>>
|
||||||
{
|
{
|
||||||
public StandaloneAppTest(BrowserFixture browserFixture, DevHostServerFixture<StandaloneApp.Program> serverFixture)
|
public StandaloneAppTest(BrowserFixture browserFixture, DevHostServerFixture<StandaloneApp.ProgramY> serverFixture)
|
||||||
: base(browserFixture, serverFixture)
|
: base(browserFixture, serverFixture)
|
||||||
{
|
{
|
||||||
Navigate("/", noReload: true);
|
Navigate("/", noReload: true);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue