command.WaitForExit(true)
.Should().Fail()
.And.HaveStdErrContaining($"Showing error dialog for application: '{Path.GetFileName(appExe)}' - error code: 0x{expectedErrorCode}")
- .And.HaveStdErrContaining("To run this application, you need to install a newer version of .NET");
+ .And.HaveStdErrContaining("You must install or update .NET to run this application.")
+ .And.HaveStdErrContaining("App host version:")
+ .And.HaveStdErrContaining("apphost_version=");
}
}
using System;
using System.IO;
using BundleTests.Helpers;
+using Microsoft.DotNet.Cli.Build;
using Microsoft.DotNet.Cli.Build.Framework;
using Microsoft.DotNet.CoreSetup.Test;
using Microsoft.NET.HostModel.Bundle;
private void RunTheApp(string path, TestProjectFixture fixture)
{
- Command.Create(path)
- .EnableTracingAndCaptureOutputs()
- .EnvironmentVariable("DOTNET_ROOT", fixture.BuiltDotnet.BinPath)
- .EnvironmentVariable("DOTNET_ROOT(x86)", fixture.BuiltDotnet.BinPath)
- .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0")
- .Execute()
+ RunTheApp(path, fixture.BuiltDotnet)
.Should()
.Pass()
.And
.HaveStdOutContaining("Wow! We now say hello to the big world and you.");
}
+ private CommandResult RunTheApp(string path, DotNetCli dotnet)
+ {
+ return Command.Create(path)
+ .EnableTracingAndCaptureOutputs()
+ .DotNetRoot(dotnet.BinPath)
+ .MultilevelLookup(false)
+ .Execute();
+ }
+
[InlineData(BundleOptions.None)]
[InlineData(BundleOptions.BundleNativeBinaries)]
[InlineData(BundleOptions.BundleAllContent)]
RunTheApp(singleFile, fixture);
}
+ [Fact]
+ public void Bundle_Framework_dependent_NoBundleEntryPoint()
+ {
+ var fixture = sharedTestState.TestFrameworkDependentFixture.Copy();
+ UseFrameworkDependentHost(fixture);
+ var singleFile = BundleHelper.BundleApp(fixture, BundleOptions.None);
+
+ string dotnetWithMockHostFxr = SharedFramework.CalculateUniqueTestDirectory(Path.Combine(TestArtifact.TestArtifactsPath, "guiErrors"));
+ using (new TestArtifact(dotnetWithMockHostFxr))
+ {
+ Directory.CreateDirectory(dotnetWithMockHostFxr);
+ var dotnetBuilder = new DotNetBuilder(dotnetWithMockHostFxr, sharedTestState.RepoDirectories.BuiltDotnet, "mockhostfxrFrameworkMissingFailure")
+ .RemoveHostFxr()
+ .AddMockHostFxr(new Version(2, 2, 0));
+ var dotnet = dotnetBuilder.Build();
+
+ // Run the bundled app (extract files)
+ RunTheApp(singleFile, dotnet)
+ .Should()
+ .Fail()
+ .And.HaveStdErrContaining("You must install or update .NET to run this application.")
+ .And.HaveStdErrContaining("App host version:")
+ .And.HaveStdErrContaining("apphost_version=");
+ }
+ }
+
[InlineData(BundleOptions.None)]
[InlineData(BundleOptions.BundleNativeBinaries)]
[InlineData(BundleOptions.BundleAllContent)]
}
[Fact]
- private void Can_Run_App_With_StatiHost()
+ private void Can_Run_App_With_StaticHost()
{
var fixture = sharedTestState.TestFixture.Copy();
}
[Fact]
- private void Can_Run_SingleFile_App_With_StatiHost()
+ private void Can_Run_SingleFile_App_With_StaticHost()
{
var fixture = sharedTestState.TestFixture.Copy();
return false;
}
- pal::string_t get_runtime_not_found_message()
+ pal::string_t get_apphost_details_message()
{
- pal::string_t msg = INSTALL_NET_DESKTOP_ERROR_MESSAGE _X("\n\n")
- _X("Architecture: ");
+ pal::string_t msg = _X("Architecture: ");
msg.append(get_arch());
msg.append(_X("\n")
_X("App host version: ") _STRINGIFY(COMMON_HOST_PKG_VER) _X("\n\n"));
return msg;
}
+ pal::string_t get_runtime_not_found_message()
+ {
+ pal::string_t msg = INSTALL_NET_DESKTOP_ERROR_MESSAGE _X("\n\n");
+ msg.append(get_apphost_details_message());
+ return msg;
+ }
+
void show_error_dialog(const pal::char_t *executable_name, int error_code)
{
pal::string_t gui_errors_disabled;
dialogMsg = pal::string_t(INSTALL_OR_UPDATE_NET_ERROR_MESSAGE _X("\n\n"));
pal::string_t line;
pal::stringstream_t ss(g_buffered_errors);
+ bool foundCustomMessage = false;
while (std::getline(ss, line, _X('\n')))
{
const pal::char_t prefix[] = _X("Framework: '");
{
dialogMsg.append(line);
dialogMsg.append(_X("\n\n"));
+ foundCustomMessage = true;
}
else if (utils::starts_with(line, custom_prefix, true))
{
dialogMsg.erase();
dialogMsg.append(line.substr(utils::strlen(custom_prefix)));
dialogMsg.append(_X("\n\n"));
+ foundCustomMessage = true;
}
else if (try_get_url_from_line(line, url))
{
break;
}
}
+
+ if (!foundCustomMessage)
+ dialogMsg.append(get_apphost_details_message());
}
else if (error_code == StatusCode::BundleExtractionFailure)
{
#define CURHOST_EXE
#endif
-void need_newer_framework_error()
+void need_newer_framework_error(const pal::string_t& dotnet_root, const pal::string_t& host_path)
{
- pal::string_t url = get_download_url();
- trace::error(_X(" _ To run this application, you need to install a newer version of .NET Core."));
- trace::error(_X(""));
- trace::error(_X(" - %s&apphost_version=%s"), url.c_str(), _STRINGIFY(COMMON_HOST_PKG_VER));
+ trace::error(
+ INSTALL_OR_UPDATE_NET_ERROR_MESSAGE
+ _X("\n\n")
+ _X("App: %s\n")
+ _X("Architecture: %s\n")
+ _X("App host version: %s\n")
+ _X(".NET location: %s\n")
+ _X("\n")
+ _X("Learn about runtime installation:\n")
+ DOTNET_APP_LAUNCH_FAILED_URL
+ _X("\n\n")
+ _X("Download the .NET runtime:\n")
+ _X("%s&apphost_version=%s"),
+ host_path.c_str(),
+ get_arch(),
+ _STRINGIFY(COMMON_HOST_PKG_VER),
+ dotnet_root.c_str(),
+ get_download_url().c_str(),
+ _STRINGIFY(COMMON_HOST_PKG_VER));
}
#if defined(CURHOST_EXE)
{
// An outdated hostfxr can only be found for framework-related apps.
trace::error(_X("The required library %s does not support single-file apps."), fxr.fxr_path().c_str());
- need_newer_framework_error();
+ need_newer_framework_error(fxr.dotnet_root(), host_path);
rc = StatusCode::FrameworkMissingFailure;
}
}
rc = hostfxr_main_startupinfo(argc, argv, host_path_cstr, dotnet_root_cstr, app_path_cstr);
- // This check exists to provide an error message for UI apps when running 3.0 apps on 2.0 only hostfxr, which doesn't support error writer redirection.
+ // This check exists to provide an error message for apps when running 3.0 apps on 2.0 only hostfxr, which doesn't support error writer redirection.
+ // Note that this is not only for UI apps - on Windows we always write errors to event log as well (regardless of UI) and it uses
+ // the same mechanism of redirecting error writers.
if (trace::get_error_writer() != nullptr && rc == static_cast<int>(StatusCode::FrameworkMissingFailure) && set_error_writer == nullptr)
{
- need_newer_framework_error();
+ need_newer_framework_error(fxr.dotnet_root(), host_path);
}
}
#if !defined(FEATURE_STATIC_HOST)