Add support for views + SingleFileExe (#24925)
* Add support for views + SingleFileExe
This commit is contained in:
commit
3e8c5c48f0
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Runtime.Loader;
|
||||||
using Microsoft.AspNetCore.Mvc.Core;
|
using Microsoft.AspNetCore.Mvc.Core;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.ApplicationParts
|
namespace Microsoft.AspNetCore.Mvc.ApplicationParts
|
||||||
|
|
@ -16,8 +17,6 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts
|
||||||
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
|
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
|
||||||
public sealed class RelatedAssemblyAttribute : Attribute
|
public sealed class RelatedAssemblyAttribute : Attribute
|
||||||
{
|
{
|
||||||
private static readonly Func<string, Assembly> AssemblyLoadFileDelegate = Assembly.LoadFile;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of <see cref="RelatedAssemblyAttribute"/>.
|
/// Initializes a new instance of <see cref="RelatedAssemblyAttribute"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -50,14 +49,15 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts
|
||||||
throw new ArgumentNullException(nameof(assembly));
|
throw new ArgumentNullException(nameof(assembly));
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetRelatedAssemblies(assembly, throwOnError, File.Exists, AssemblyLoadFileDelegate);
|
var loadContext = AssemblyLoadContext.GetLoadContext(assembly) ?? AssemblyLoadContext.Default;
|
||||||
|
return GetRelatedAssemblies(assembly, throwOnError, File.Exists, new AssemblyLoadContextWrapper(loadContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static IReadOnlyList<Assembly> GetRelatedAssemblies(
|
internal static IReadOnlyList<Assembly> GetRelatedAssemblies(
|
||||||
Assembly assembly,
|
Assembly assembly,
|
||||||
bool throwOnError,
|
bool throwOnError,
|
||||||
Func<string, bool> fileExists,
|
Func<string, bool> fileExists,
|
||||||
Func<string, Assembly> loadFile)
|
AssemblyLoadContextWrapper assemblyLoadContext)
|
||||||
{
|
{
|
||||||
if (assembly == null)
|
if (assembly == null)
|
||||||
{
|
{
|
||||||
|
|
@ -66,7 +66,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts
|
||||||
|
|
||||||
// MVC will specifically look for related parts in the same physical directory as the assembly.
|
// MVC will specifically look for related parts in the same physical directory as the assembly.
|
||||||
// No-op if the assembly does not have a location.
|
// No-op if the assembly does not have a location.
|
||||||
if (assembly.IsDynamic || string.IsNullOrEmpty(assembly.Location))
|
if (assembly.IsDynamic)
|
||||||
{
|
{
|
||||||
return Array.Empty<Assembly>();
|
return Array.Empty<Assembly>();
|
||||||
}
|
}
|
||||||
|
|
@ -78,8 +78,10 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts
|
||||||
}
|
}
|
||||||
|
|
||||||
var assemblyName = assembly.GetName().Name;
|
var assemblyName = assembly.GetName().Name;
|
||||||
var assemblyLocation = assembly.Location;
|
// Assembly.Location may be null for a single-file exe. In this case, attempt to look for related parts in the app's base directory
|
||||||
var assemblyDirectory = Path.GetDirectoryName(assemblyLocation);
|
var assemblyDirectory = string.IsNullOrEmpty(assembly.Location) ?
|
||||||
|
AppContext.BaseDirectory :
|
||||||
|
Path.GetDirectoryName(assembly.Location);
|
||||||
|
|
||||||
var relatedAssemblies = new List<Assembly>();
|
var relatedAssemblies = new List<Assembly>();
|
||||||
for (var i = 0; i < attributes.Length; i++)
|
for (var i = 0; i < attributes.Length; i++)
|
||||||
|
|
@ -91,26 +93,46 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts
|
||||||
Resources.FormatRelatedAssemblyAttribute_AssemblyCannotReferenceSelf(nameof(RelatedAssemblyAttribute), assemblyName));
|
Resources.FormatRelatedAssemblyAttribute_AssemblyCannotReferenceSelf(nameof(RelatedAssemblyAttribute), assemblyName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Assembly relatedAssembly;
|
||||||
var relatedAssemblyLocation = Path.Combine(assemblyDirectory, attribute.AssemblyFileName + ".dll");
|
var relatedAssemblyLocation = Path.Combine(assemblyDirectory, attribute.AssemblyFileName + ".dll");
|
||||||
if (!fileExists(relatedAssemblyLocation))
|
if (fileExists(relatedAssemblyLocation))
|
||||||
{
|
{
|
||||||
if (throwOnError)
|
relatedAssembly = assemblyLoadContext.LoadFromAssemblyPath(relatedAssemblyLocation);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
throw new FileNotFoundException(
|
var relatedAssemblyName = new AssemblyName(attribute.AssemblyFileName);
|
||||||
Resources.FormatRelatedAssemblyAttribute_CouldNotBeFound(attribute.AssemblyFileName, assemblyName, assemblyDirectory),
|
relatedAssembly = assemblyLoadContext.LoadFromAssemblyName(relatedAssemblyName);
|
||||||
relatedAssemblyLocation);
|
|
||||||
}
|
}
|
||||||
else
|
catch when (!throwOnError)
|
||||||
{
|
{
|
||||||
|
// Ignore assembly load failures when throwOnError = false.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var relatedAssembly = loadFile(relatedAssemblyLocation);
|
|
||||||
relatedAssemblies.Add(relatedAssembly);
|
relatedAssemblies.Add(relatedAssembly);
|
||||||
}
|
}
|
||||||
|
|
||||||
return relatedAssemblies;
|
return relatedAssemblies;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class AssemblyLoadContextWrapper
|
||||||
|
{
|
||||||
|
private readonly AssemblyLoadContext _loadContext;
|
||||||
|
|
||||||
|
public AssemblyLoadContextWrapper(AssemblyLoadContext loadContext)
|
||||||
|
{
|
||||||
|
_loadContext = loadContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual Assembly LoadFromAssemblyName(AssemblyName assemblyName)
|
||||||
|
=> _loadContext.LoadFromAssemblyName(assemblyName);
|
||||||
|
|
||||||
|
public virtual Assembly LoadFromAssemblyPath(string assemblyPath)
|
||||||
|
=> _loadContext.LoadFromAssemblyPath(assemblyPath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Reflection.Emit;
|
using System.Reflection.Emit;
|
||||||
|
using System.Runtime.Loader;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.ApplicationParts
|
namespace Microsoft.AspNetCore.Mvc.ApplicationParts
|
||||||
|
|
@ -43,7 +45,6 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts
|
||||||
public void GetRelatedAssemblies_ThrowsIfAssemblyCannotBeFound()
|
public void GetRelatedAssemblies_ThrowsIfAssemblyCannotBeFound()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var expected = $"Related assembly 'DoesNotExist' specified by assembly 'MyAssembly' could not be found in the directory {AssemblyDirectory}. Related assemblies must be co-located with the specifying assemblies.";
|
|
||||||
var assemblyPath = Path.Combine(AssemblyDirectory, "MyAssembly.dll");
|
var assemblyPath = Path.Combine(AssemblyDirectory, "MyAssembly.dll");
|
||||||
var assembly = new TestAssembly
|
var assembly = new TestAssembly
|
||||||
{
|
{
|
||||||
|
|
@ -51,27 +52,32 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts
|
||||||
};
|
};
|
||||||
|
|
||||||
// Act & Assert
|
// Act & Assert
|
||||||
var ex = Assert.Throws<FileNotFoundException>(() => RelatedAssemblyAttribute.GetRelatedAssemblies(assembly, throwOnError: true));
|
Assert.Throws<FileNotFoundException>(() => RelatedAssemblyAttribute.GetRelatedAssemblies(assembly, throwOnError: true));
|
||||||
Assert.Equal(expected, ex.Message);
|
|
||||||
Assert.Equal(Path.Combine(AssemblyDirectory, "DoesNotExist.dll"), ex.FileName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GetRelatedAssemblies_LoadsRelatedAssembly()
|
public void GetRelatedAssemblies_ReadsAssemblyFromLoadContext_IfItAlreadyExists()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var destination = Path.Combine(AssemblyDirectory, "RelatedAssembly.dll");
|
var expected = $"Related assembly 'DoesNotExist' specified by assembly 'MyAssembly' could not be found in the directory {AssemblyDirectory}. Related assemblies must be co-located with the specifying assemblies.";
|
||||||
|
var assemblyPath = Path.Combine(AssemblyDirectory, "MyAssembly.dll");
|
||||||
|
var relatedAssembly = typeof(RelatedAssemblyPartTest).Assembly;
|
||||||
var assembly = new TestAssembly
|
var assembly = new TestAssembly
|
||||||
{
|
{
|
||||||
AttributeAssembly = "RelatedAssembly",
|
AttributeAssembly = "RelatedAssembly"
|
||||||
};
|
};
|
||||||
var relatedAssembly = typeof(RelatedAssemblyPartTest).Assembly;
|
var loadContext = new TestableAssemblyLoadContextWrapper
|
||||||
|
|
||||||
var result = RelatedAssemblyAttribute.GetRelatedAssemblies(assembly, throwOnError: true, file => true, file =>
|
|
||||||
{
|
{
|
||||||
Assert.Equal(file, destination);
|
Assemblies =
|
||||||
return relatedAssembly;
|
{
|
||||||
});
|
["RelatedAssembly"] = relatedAssembly,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = RelatedAssemblyAttribute.GetRelatedAssemblies(assembly, throwOnError: true, file => false, loadContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
Assert.Equal(new[] { relatedAssembly }, result);
|
Assert.Equal(new[] { relatedAssembly }, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -94,5 +100,21 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts
|
||||||
return new[] { attribute };
|
return new[] { attribute };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class TestableAssemblyLoadContextWrapper : RelatedAssemblyAttribute.AssemblyLoadContextWrapper
|
||||||
|
{
|
||||||
|
public TestableAssemblyLoadContextWrapper() : base(AssemblyLoadContext.Default)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Dictionary<string, Assembly> Assemblies { get; } = new Dictionary<string, Assembly>();
|
||||||
|
|
||||||
|
public override Assembly LoadFromAssemblyPath(string assemblyPath) => throw new NotSupportedException();
|
||||||
|
|
||||||
|
public override Assembly LoadFromAssemblyName(AssemblyName assemblyName)
|
||||||
|
{
|
||||||
|
return Assemblies[assemblyName.Name];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@
|
||||||
MicrosoftNETSdkRazorPackageVersion=$(MicrosoftNETSdkRazorPackageVersion);
|
MicrosoftNETSdkRazorPackageVersion=$(MicrosoftNETSdkRazorPackageVersion);
|
||||||
MicrosoftAspNetCoreAppRefPackageVersion=$(MicrosoftAspNetCoreAppRefPackageVersion);
|
MicrosoftAspNetCoreAppRefPackageVersion=$(MicrosoftAspNetCoreAppRefPackageVersion);
|
||||||
MicrosoftAspNetCoreAppRuntimePackageVersion=@(_RuntimePackageVersionInfo->'%(PackageVersion)');
|
MicrosoftAspNetCoreAppRuntimePackageVersion=@(_RuntimePackageVersionInfo->'%(PackageVersion)');
|
||||||
SupportedRuntimeIdentifiers=$(SupportedRuntimeIdentifiers);
|
SupportedRuntimeIdentifiers=$(SupportedRuntimeIdentifiers.Trim());
|
||||||
DefaultNetCoreTargetFramework=$(DefaultNetCoreTargetFramework);
|
DefaultNetCoreTargetFramework=$(DefaultNetCoreTargetFramework);
|
||||||
RepoRoot=$(RepoRoot);
|
RepoRoot=$(RepoRoot);
|
||||||
Configuration=$(Configuration);
|
Configuration=$(Configuration);
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
|
@ -41,6 +42,7 @@ namespace Templates.Test.Helpers
|
||||||
IDictionary<string, string> environmentVariables,
|
IDictionary<string, string> environmentVariables,
|
||||||
bool published,
|
bool published,
|
||||||
bool hasListeningUri = true,
|
bool hasListeningUri = true,
|
||||||
|
bool usePublishedAppHost = false,
|
||||||
ILogger logger = null)
|
ILogger logger = null)
|
||||||
{
|
{
|
||||||
_developmentCertificate = DevelopmentCertificate.Create(workingDirectory);
|
_developmentCertificate = DevelopmentCertificate.Create(workingDirectory);
|
||||||
|
|
@ -59,9 +61,29 @@ namespace Templates.Test.Helpers
|
||||||
|
|
||||||
output.WriteLine("Running ASP.NET Core application...");
|
output.WriteLine("Running ASP.NET Core application...");
|
||||||
|
|
||||||
var arguments = published ? $"exec {dllPath}" : "run --no-build";
|
string process;
|
||||||
|
string arguments;
|
||||||
|
if (published)
|
||||||
|
{
|
||||||
|
if (usePublishedAppHost)
|
||||||
|
{
|
||||||
|
// When publishingu used the app host to run the app. This makes it easy to consistently run for regular and single-file publish
|
||||||
|
process = Path.ChangeExtension(dllPath, OperatingSystem.IsWindows() ? ".exe" : null);
|
||||||
|
arguments = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
process = DotNetMuxer.MuxerPathOrDefault();
|
||||||
|
arguments = $"exec {dllPath}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
process = DotNetMuxer.MuxerPathOrDefault();
|
||||||
|
arguments = "run --no-build";
|
||||||
|
}
|
||||||
|
|
||||||
logger?.LogInformation($"AspNetProcess - process: {DotNetMuxer.MuxerPathOrDefault()} arguments: {arguments}");
|
logger?.LogInformation($"AspNetProcess - process: {process} arguments: {arguments}");
|
||||||
|
|
||||||
var finalEnvironmentVariables = new Dictionary<string, string>(environmentVariables)
|
var finalEnvironmentVariables = new Dictionary<string, string>(environmentVariables)
|
||||||
{
|
{
|
||||||
|
|
@ -69,7 +91,7 @@ namespace Templates.Test.Helpers
|
||||||
["ASPNETCORE_Kestrel__Certificates__Default__Password"] = _developmentCertificate.CertificatePassword,
|
["ASPNETCORE_Kestrel__Certificates__Default__Password"] = _developmentCertificate.CertificatePassword,
|
||||||
};
|
};
|
||||||
|
|
||||||
Process = ProcessEx.Run(output, workingDirectory, DotNetMuxer.MuxerPathOrDefault(), arguments, envVars: finalEnvironmentVariables);
|
Process = ProcessEx.Run(output, workingDirectory, process, arguments, envVars: finalEnvironmentVariables);
|
||||||
|
|
||||||
logger?.LogInformation("AspNetProcess - process started");
|
logger?.LogInformation("AspNetProcess - process started");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -110,14 +110,16 @@ namespace Templates.Test.Helpers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal async Task<ProcessResult> RunDotNetPublishAsync(IDictionary<string, string> packageOptions = null, string additionalArgs = null)
|
internal async Task<ProcessResult> RunDotNetPublishAsync(IDictionary<string, string> packageOptions = null, string additionalArgs = null, bool noRestore = true)
|
||||||
{
|
{
|
||||||
Output.WriteLine("Publishing ASP.NET Core application...");
|
Output.WriteLine("Publishing ASP.NET Core application...");
|
||||||
|
|
||||||
// Avoid restoring as part of build or publish. These projects should have already restored as part of running dotnet new. Explicitly disabling restore
|
// Avoid restoring as part of build or publish. These projects should have already restored as part of running dotnet new. Explicitly disabling restore
|
||||||
// should avoid any global contention and we can execute a build or publish in a lock-free way
|
// should avoid any global contention and we can execute a build or publish in a lock-free way
|
||||||
|
|
||||||
using var result = ProcessEx.Run(Output, TemplateOutputDir, DotNetMuxer.MuxerPathOrDefault(), $"publish --no-restore -c Release /bl {additionalArgs}", packageOptions);
|
var restoreArgs = noRestore ? "--no-restore" : null;
|
||||||
|
|
||||||
|
using var result = ProcessEx.Run(Output, TemplateOutputDir, DotNetMuxer.MuxerPathOrDefault(), $"publish {restoreArgs} -c Release /bl {additionalArgs}", packageOptions);
|
||||||
await result.Exited;
|
await result.Exited;
|
||||||
CaptureBinLogOnFailure(result);
|
CaptureBinLogOnFailure(result);
|
||||||
return new ProcessResult(result);
|
return new ProcessResult(result);
|
||||||
|
|
@ -177,7 +179,7 @@ namespace Templates.Test.Helpers
|
||||||
return new AspNetProcess(Output, TemplateOutputDir, projectDll, environment, published: false, hasListeningUri: hasListeningUri, logger: logger);
|
return new AspNetProcess(Output, TemplateOutputDir, projectDll, environment, published: false, hasListeningUri: hasListeningUri, logger: logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal AspNetProcess StartPublishedProjectAsync(bool hasListeningUri = true)
|
internal AspNetProcess StartPublishedProjectAsync(bool hasListeningUri = true, bool usePublishedAppHost = false)
|
||||||
{
|
{
|
||||||
var environment = new Dictionary<string, string>
|
var environment = new Dictionary<string, string>
|
||||||
{
|
{
|
||||||
|
|
@ -188,8 +190,8 @@ namespace Templates.Test.Helpers
|
||||||
["ASPNETCORE_Logging__Console__FormatterOptions__IncludeScopes"] = "true",
|
["ASPNETCORE_Logging__Console__FormatterOptions__IncludeScopes"] = "true",
|
||||||
};
|
};
|
||||||
|
|
||||||
var projectDll = $"{ProjectName}.dll";
|
var projectDll = Path.Combine(TemplatePublishDir, $"{ProjectName}.dll");
|
||||||
return new AspNetProcess(Output, TemplatePublishDir, projectDll, environment, published: true, hasListeningUri: hasListeningUri);
|
return new AspNetProcess(Output, TemplatePublishDir, projectDll, environment, published: true, hasListeningUri: hasListeningUri, usePublishedAppHost: usePublishedAppHost);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal async Task<ProcessResult> RunDotNetEfCreateMigrationAsync(string migrationName)
|
internal async Task<ProcessResult> RunDotNetEfCreateMigrationAsync(string migrationName)
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@
|
||||||
MicrosoftNETSdkRazorPackageVersion=$(MicrosoftNETSdkRazorPackageVersion);
|
MicrosoftNETSdkRazorPackageVersion=$(MicrosoftNETSdkRazorPackageVersion);
|
||||||
MicrosoftAspNetCoreAppRefPackageVersion=$(MicrosoftAspNetCoreAppRefPackageVersion);
|
MicrosoftAspNetCoreAppRefPackageVersion=$(MicrosoftAspNetCoreAppRefPackageVersion);
|
||||||
MicrosoftAspNetCoreAppRuntimePackageVersion=@(_RuntimePackageVersionInfo->'%(PackageVersion)');
|
MicrosoftAspNetCoreAppRuntimePackageVersion=@(_RuntimePackageVersionInfo->'%(PackageVersion)');
|
||||||
SupportedRuntimeIdentifiers=$(SupportedRuntimeIdentifiers);
|
SupportedRuntimeIdentifiers=$(SupportedRuntimeIdentifiers.Trim());
|
||||||
DefaultNetCoreTargetFramework=$(DefaultNetCoreTargetFramework);
|
DefaultNetCoreTargetFramework=$(DefaultNetCoreTargetFramework);
|
||||||
RepoRoot=$(RepoRoot);
|
RepoRoot=$(RepoRoot);
|
||||||
Configuration=$(Configuration);
|
Configuration=$(Configuration);
|
||||||
|
|
|
||||||
|
|
@ -223,6 +223,77 @@ namespace Templates.Test
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[ConditionalFact(Skip = "https://github.com/dotnet/aspnetcore/issues/25103")]
|
||||||
|
[SkipOnHelix("cert failure", Queues = "OSX.1014.Amd64;OSX.1014.Amd64.Open")]
|
||||||
|
public async Task MvcTemplate_SingleFileExe()
|
||||||
|
{
|
||||||
|
// This test verifies publishing an MVC app as a single file exe works. We'll limit testing
|
||||||
|
// this to a few operating systems to make our lives easier.
|
||||||
|
string runtimeIdentifer;
|
||||||
|
if (OperatingSystem.IsWindows())
|
||||||
|
{
|
||||||
|
runtimeIdentifer = "win-x64";
|
||||||
|
}
|
||||||
|
else if (OperatingSystem.IsLinux())
|
||||||
|
{
|
||||||
|
runtimeIdentifer = "linux-x64";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Project = await ProjectFactory.GetOrCreateProject("mvcsinglefileexe", Output);
|
||||||
|
Project.RuntimeIdentifier = runtimeIdentifer;
|
||||||
|
|
||||||
|
var createResult = await Project.RunDotNetNewAsync("mvc", auth: "Individual", useLocalDB: true);
|
||||||
|
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", Project, createResult));
|
||||||
|
|
||||||
|
var publishResult = await Project.RunDotNetPublishAsync(additionalArgs: $"/p:PublishSingleFile=true -r {runtimeIdentifer}", noRestore: false);
|
||||||
|
Assert.True(0 == publishResult.ExitCode, ErrorMessages.GetFailedProcessMessage("publish", Project, publishResult));
|
||||||
|
|
||||||
|
var pages = new[]
|
||||||
|
{
|
||||||
|
new Page
|
||||||
|
{
|
||||||
|
// Verify a view from the app works
|
||||||
|
Url = PageUrls.HomeUrl,
|
||||||
|
Links = new []
|
||||||
|
{
|
||||||
|
PageUrls.HomeUrl,
|
||||||
|
PageUrls.RegisterUrl,
|
||||||
|
PageUrls.LoginUrl,
|
||||||
|
PageUrls.HomeUrl,
|
||||||
|
PageUrls.PrivacyUrl,
|
||||||
|
PageUrls.DocsUrl,
|
||||||
|
PageUrls.PrivacyUrl
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Page
|
||||||
|
{
|
||||||
|
// Verify a view from a RCL (in this case IdentityUI) works
|
||||||
|
Url = PageUrls.RegisterUrl,
|
||||||
|
Links = new []
|
||||||
|
{
|
||||||
|
PageUrls.HomeUrl,
|
||||||
|
PageUrls.RegisterUrl,
|
||||||
|
PageUrls.LoginUrl,
|
||||||
|
PageUrls.HomeUrl,
|
||||||
|
PageUrls.PrivacyUrl,
|
||||||
|
PageUrls.ExternalArticle,
|
||||||
|
PageUrls.PrivacyUrl
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
using var aspNetProcess = Project.StartPublishedProjectAsync(usePublishedAppHost: true);
|
||||||
|
Assert.False(
|
||||||
|
aspNetProcess.Process.HasExited,
|
||||||
|
ErrorMessages.GetFailedProcessMessageOrEmpty("Run published project", Project, aspNetProcess.Process));
|
||||||
|
|
||||||
|
await aspNetProcess.AssertPagesOk(pages);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[QuarantinedTest("https://github.com/dotnet/aspnetcore/issues/23993")]
|
[QuarantinedTest("https://github.com/dotnet/aspnetcore/issues/23993")]
|
||||||
public async Task MvcTemplate_RazorRuntimeCompilation_BuildsAndPublishes()
|
public async Task MvcTemplate_RazorRuntimeCompilation_BuildsAndPublishes()
|
||||||
|
|
|
||||||
|
|
@ -720,10 +720,12 @@ Copyright (c) .NET Foundation. All rights reserved.
|
||||||
<AllPublishItemsFullPathWithTargetPath Include="@(RazorIntermediateAssembly->'%(FullPath)')">
|
<AllPublishItemsFullPathWithTargetPath Include="@(RazorIntermediateAssembly->'%(FullPath)')">
|
||||||
<TargetPath>%(Filename)%(Extension)</TargetPath>
|
<TargetPath>%(Filename)%(Extension)</TargetPath>
|
||||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||||
|
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||||
</AllPublishItemsFullPathWithTargetPath>
|
</AllPublishItemsFullPathWithTargetPath>
|
||||||
<AllPublishItemsFullPathWithTargetPath Include="@(_RazorDebugSymbolsIntermediatePath->'%(FullPath)')">
|
<AllPublishItemsFullPathWithTargetPath Include="@(_RazorDebugSymbolsIntermediatePath->'%(FullPath)')">
|
||||||
<TargetPath>%(Filename)%(Extension)</TargetPath>
|
<TargetPath>%(Filename)%(Extension)</TargetPath>
|
||||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||||
|
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||||
</AllPublishItemsFullPathWithTargetPath>
|
</AllPublishItemsFullPathWithTargetPath>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue