Add better error message when someone does single file publish in ANCM (#10871)
This commit is contained in:
parent
2b2bf067dd
commit
f080c89e89
|
|
@ -64,6 +64,7 @@ HandlerResolver::LoadRequestHandlerAssembly(const IHttpApplication &pApplication
|
||||||
pConfiguration.QueryProcessPath(),
|
pConfiguration.QueryProcessPath(),
|
||||||
pApplication.GetApplicationPhysicalPath(),
|
pApplication.GetApplicationPhysicalPath(),
|
||||||
pConfiguration.QueryArguments(),
|
pConfiguration.QueryArguments(),
|
||||||
|
errorContext,
|
||||||
options));
|
options));
|
||||||
|
|
||||||
location = options->GetDotnetExeLocation();
|
location = options->GetDotnetExeLocation();
|
||||||
|
|
|
||||||
|
|
@ -196,6 +196,7 @@
|
||||||
</Lib>
|
</Lib>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClInclude Include="ErrorContext.h" />
|
||||||
<ClInclude Include="PollingAppOfflineApplication.h" />
|
<ClInclude Include="PollingAppOfflineApplication.h" />
|
||||||
<ClInclude Include="application.h" />
|
<ClInclude Include="application.h" />
|
||||||
<ClInclude Include="BindingInformation.h" />
|
<ClInclude Include="BindingInformation.h" />
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
struct ErrorContext
|
||||||
|
{
|
||||||
|
// TODO consider adding HRESULT here
|
||||||
|
std::string detailedErrorContent;
|
||||||
|
USHORT statusCode;
|
||||||
|
USHORT subStatusCode;
|
||||||
|
std::string generalErrorType;
|
||||||
|
std::string errorReason;
|
||||||
|
};
|
||||||
|
|
@ -28,16 +28,6 @@ typedef int(*hostfxr_set_runtime_property_value_fn)(void* host_context_handle, P
|
||||||
typedef int(*hostfxr_run_app_fn)(void* host_context_handle);
|
typedef int(*hostfxr_run_app_fn)(void* host_context_handle);
|
||||||
typedef int(*hostfxr_close_fn)(void* hostfxr_context_handle);
|
typedef int(*hostfxr_close_fn)(void* hostfxr_context_handle);
|
||||||
|
|
||||||
struct ErrorContext
|
|
||||||
{
|
|
||||||
// TODO consider adding HRESULT here
|
|
||||||
std::string detailedErrorContent;
|
|
||||||
USHORT statusCode;
|
|
||||||
USHORT subStatusCode;
|
|
||||||
std::string generalErrorType;
|
|
||||||
std::string errorReason;
|
|
||||||
};
|
|
||||||
|
|
||||||
class HostFxrErrorRedirector: NonCopyable
|
class HostFxrErrorRedirector: NonCopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ HRESULT HostFxrResolutionResult::Create(
|
||||||
_In_ const std::wstring& pcwzProcessPath,
|
_In_ const std::wstring& pcwzProcessPath,
|
||||||
_In_ const std::wstring& pcwzApplicationPhysicalPath,
|
_In_ const std::wstring& pcwzApplicationPhysicalPath,
|
||||||
_In_ const std::wstring& pcwzArguments,
|
_In_ const std::wstring& pcwzArguments,
|
||||||
|
_In_ ErrorContext& errorContext,
|
||||||
_Out_ std::unique_ptr<HostFxrResolutionResult>& ppWrapper)
|
_Out_ std::unique_ptr<HostFxrResolutionResult>& ppWrapper)
|
||||||
{
|
{
|
||||||
std::filesystem::path knownDotnetLocation;
|
std::filesystem::path knownDotnetLocation;
|
||||||
|
|
@ -42,7 +43,8 @@ HRESULT HostFxrResolutionResult::Create(
|
||||||
pcwzArguments,
|
pcwzArguments,
|
||||||
hostFxrDllPath,
|
hostFxrDllPath,
|
||||||
knownDotnetLocation,
|
knownDotnetLocation,
|
||||||
arguments);
|
arguments,
|
||||||
|
errorContext);
|
||||||
|
|
||||||
LOG_INFOF(L"Parsed hostfxr options: dotnet location: '%ls' hostfxr path: '%ls' arguments:", knownDotnetLocation.c_str(), hostFxrDllPath.c_str());
|
LOG_INFOF(L"Parsed hostfxr options: dotnet location: '%ls' hostfxr path: '%ls' arguments:", knownDotnetLocation.c_str(), hostFxrDllPath.c_str());
|
||||||
for (size_t i = 0; i < arguments.size(); i++)
|
for (size_t i = 0; i < arguments.size(); i++)
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "ErrorContext.h"
|
||||||
|
|
||||||
class HostFxrResolutionResult
|
class HostFxrResolutionResult
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -44,6 +46,7 @@ public:
|
||||||
_In_ const std::wstring& pcwzProcessPath,
|
_In_ const std::wstring& pcwzProcessPath,
|
||||||
_In_ const std::wstring& pcwzApplicationPhysicalPath,
|
_In_ const std::wstring& pcwzApplicationPhysicalPath,
|
||||||
_In_ const std::wstring& pcwzArguments,
|
_In_ const std::wstring& pcwzArguments,
|
||||||
|
_In_ ErrorContext& errorContext,
|
||||||
_Out_ std::unique_ptr<HostFxrResolutionResult>& ppWrapper);
|
_Out_ std::unique_ptr<HostFxrResolutionResult>& ppWrapper);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,8 @@ HostFxrResolver::GetHostFxrParameters(
|
||||||
const std::wstring &applicationArguments,
|
const std::wstring &applicationArguments,
|
||||||
fs::path &hostFxrDllPath,
|
fs::path &hostFxrDllPath,
|
||||||
fs::path &dotnetExePath,
|
fs::path &dotnetExePath,
|
||||||
std::vector<std::wstring> &arguments
|
std::vector<std::wstring> &arguments,
|
||||||
|
ErrorContext& errorContext
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
LOG_INFOF(L"Resolving hostfxr parameters for application: '%ls' arguments: '%ls' path: '%ls'",
|
LOG_INFOF(L"Resolving hostfxr parameters for application: '%ls' arguments: '%ls' path: '%ls'",
|
||||||
|
|
@ -93,7 +94,13 @@ HostFxrResolver::GetHostFxrParameters(
|
||||||
LOG_INFOF(L"Checking application.dll at '%ls'", applicationDllPath.c_str());
|
LOG_INFOF(L"Checking application.dll at '%ls'", applicationDllPath.c_str());
|
||||||
if (!is_regular_file(applicationDllPath))
|
if (!is_regular_file(applicationDllPath))
|
||||||
{
|
{
|
||||||
throw InvalidOperationException(format(L"Application .dll was not found at %s", applicationDllPath.c_str()));
|
errorContext.subStatusCode = 38;
|
||||||
|
errorContext.errorReason = "Application DLL not found. Confirm the application dll is present. Single-file deployments are not supported in IIS.";
|
||||||
|
errorContext.generalErrorType = "ANCM Application DLL Not Found";
|
||||||
|
errorContext.detailedErrorContent = format("Application DLL was not found at %s.", to_multi_byte_string(applicationDllPath, CP_UTF8).c_str());
|
||||||
|
throw InvalidOperationException(
|
||||||
|
format(L"Application DLL was not found at %s. Confirm the application dll is present. Single-file deployments are not supported in IIS.",
|
||||||
|
applicationDllPath.c_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
hostFxrDllPath = executablePath.parent_path() / "hostfxr.dll";
|
hostFxrDllPath = executablePath.parent_path() / "hostfxr.dll";
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "ErrorContext.h"
|
||||||
|
|
||||||
#define READ_BUFFER_SIZE 4096
|
#define READ_BUFFER_SIZE 4096
|
||||||
|
|
||||||
class HostFxrResolver
|
class HostFxrResolver
|
||||||
|
|
@ -23,7 +25,8 @@ public:
|
||||||
const std::wstring &applicationArguments,
|
const std::wstring &applicationArguments,
|
||||||
std::filesystem::path &hostFxrDllPath,
|
std::filesystem::path &hostFxrDllPath,
|
||||||
std::filesystem::path &dotnetExePath,
|
std::filesystem::path &dotnetExePath,
|
||||||
std::vector<std::wstring> &arguments
|
std::vector<std::wstring> &arguments,
|
||||||
|
ErrorContext& errorContext
|
||||||
);
|
);
|
||||||
|
|
||||||
static
|
static
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,6 @@
|
||||||
<ClCompile Include="ConfigUtilityTests.cpp" />
|
<ClCompile Include="ConfigUtilityTests.cpp" />
|
||||||
<ClCompile Include="GlobalVersionTests.cpp" />
|
<ClCompile Include="GlobalVersionTests.cpp" />
|
||||||
<ClCompile Include="Helpers.cpp" />
|
<ClCompile Include="Helpers.cpp" />
|
||||||
<ClCompile Include="hostfxr_utility_tests.cpp" />
|
|
||||||
<ClCompile Include="inprocess_application_tests.cpp" />
|
<ClCompile Include="inprocess_application_tests.cpp" />
|
||||||
<ClCompile Include="main.cpp" />
|
<ClCompile Include="main.cpp" />
|
||||||
<ClCompile Include="StandardOutputRedirectionTest.cpp" />
|
<ClCompile Include="StandardOutputRedirectionTest.cpp" />
|
||||||
|
|
@ -187,4 +186,4 @@
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<IsTestProject>true</IsTestProject>
|
<IsTestProject>true</IsTestProject>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
@ -1,122 +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.
|
|
||||||
|
|
||||||
#include "stdafx.h"
|
|
||||||
#include <filesystem>
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include "HostFxrResolver.h"
|
|
||||||
#include "Environment.h"
|
|
||||||
|
|
||||||
TEST(ParseHostFxrArguments, BasicHostFxrArguments)
|
|
||||||
{
|
|
||||||
std::vector<std::wstring> bstrArray;
|
|
||||||
|
|
||||||
HostFxrResolver::AppendArguments(
|
|
||||||
L"exec \"test.dll\"", // args
|
|
||||||
L"invalid", // physical path to application
|
|
||||||
bstrArray); // args array.
|
|
||||||
|
|
||||||
EXPECT_EQ(2, bstrArray.size());
|
|
||||||
ASSERT_STREQ(L"exec", bstrArray[0].c_str());
|
|
||||||
ASSERT_STREQ(L"test.dll", bstrArray[1].c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(ParseHostFxrArguments, NoExecProvided)
|
|
||||||
{
|
|
||||||
std::vector<std::wstring> bstrArray;
|
|
||||||
|
|
||||||
HostFxrResolver::AppendArguments(
|
|
||||||
L"test.dll", // args
|
|
||||||
L"ignored", // physical path to application
|
|
||||||
bstrArray); // args array.
|
|
||||||
|
|
||||||
EXPECT_EQ(1, bstrArray.size());
|
|
||||||
ASSERT_STREQ(L"test.dll", bstrArray[0].c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(ParseHostFxrArguments, ConvertDllToAbsolutePath)
|
|
||||||
{
|
|
||||||
std::vector<std::wstring> bstrArray;
|
|
||||||
// we need to use existing dll so let's use ntdll that we know exists everywhere
|
|
||||||
auto system32 = Environment::ExpandEnvironmentVariables(L"%WINDIR%\\System32");
|
|
||||||
HostFxrResolver::AppendArguments(
|
|
||||||
L"exec \"ntdll.dll\"", // args
|
|
||||||
system32, // physical path to application
|
|
||||||
bstrArray, // args array.
|
|
||||||
true); // expandDllPaths
|
|
||||||
|
|
||||||
EXPECT_EQ(2, bstrArray.size());
|
|
||||||
ASSERT_STREQ(L"exec", bstrArray[0].c_str());
|
|
||||||
ASSERT_STREQ((system32 + L"\\ntdll.dll").c_str(), bstrArray[1].c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(ParseHostFxrArguments, ProvideNoArgs_InvalidArgs)
|
|
||||||
{
|
|
||||||
std::vector<std::wstring> bstrArray;
|
|
||||||
std::filesystem::path struHostFxrDllLocation;
|
|
||||||
std::filesystem::path struExeLocation;
|
|
||||||
|
|
||||||
EXPECT_THROW(HostFxrResolver::GetHostFxrParameters(
|
|
||||||
L"dotnet", // processPath
|
|
||||||
L"some\\path", // application physical path, ignored.
|
|
||||||
L"", //arguments
|
|
||||||
struHostFxrDllLocation,
|
|
||||||
struExeLocation,
|
|
||||||
bstrArray), // args array.
|
|
||||||
InvalidOperationException);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(GetAbsolutePathToDotnetFromProgramFiles, BackupWorks)
|
|
||||||
{
|
|
||||||
STRU struAbsolutePathToDotnet;
|
|
||||||
BOOL fDotnetInProgramFiles;
|
|
||||||
BOOL is64Bit;
|
|
||||||
BOOL fIsWow64 = FALSE;
|
|
||||||
SYSTEM_INFO systemInfo;
|
|
||||||
IsWow64Process(GetCurrentProcess(), &fIsWow64);
|
|
||||||
if (fIsWow64)
|
|
||||||
{
|
|
||||||
is64Bit = FALSE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GetNativeSystemInfo(&systemInfo);
|
|
||||||
is64Bit = systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is64Bit)
|
|
||||||
{
|
|
||||||
fDotnetInProgramFiles = std::filesystem::is_regular_file(L"C:/Program Files/dotnet/dotnet.exe");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fDotnetInProgramFiles = std::filesystem::is_regular_file(L"C:/Program Files (x86)/dotnet/dotnet.exe");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto dotnetPath = HostFxrResolver::GetAbsolutePathToDotnetFromProgramFiles();
|
|
||||||
if (fDotnetInProgramFiles)
|
|
||||||
{
|
|
||||||
EXPECT_TRUE(dotnetPath.has_value());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
EXPECT_FALSE(dotnetPath.has_value());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(GetHostFxrArguments, InvalidParams)
|
|
||||||
{
|
|
||||||
std::vector<std::wstring> bstrArray;
|
|
||||||
std::filesystem::path struHostFxrDllLocation;
|
|
||||||
std::filesystem::path struExeLocation;
|
|
||||||
|
|
||||||
EXPECT_THROW(HostFxrResolver::GetHostFxrParameters(
|
|
||||||
L"bogus", // processPath
|
|
||||||
L"", // application physical path, ignored.
|
|
||||||
L"ignored", //arguments
|
|
||||||
struHostFxrDllLocation,
|
|
||||||
struExeLocation,
|
|
||||||
bstrArray), // args array.
|
|
||||||
InvalidOperationException);
|
|
||||||
}
|
|
||||||
|
|
@ -195,6 +195,8 @@ IN_PROCESS_APPLICATION::ExecuteApplication()
|
||||||
|
|
||||||
auto context = std::make_shared<ExecuteClrContext>();
|
auto context = std::make_shared<ExecuteClrContext>();
|
||||||
|
|
||||||
|
ErrorContext errorContext; // unused
|
||||||
|
|
||||||
if (s_fMainCallback == nullptr)
|
if (s_fMainCallback == nullptr)
|
||||||
{
|
{
|
||||||
THROW_IF_FAILED(HostFxrResolutionResult::Create(
|
THROW_IF_FAILED(HostFxrResolutionResult::Create(
|
||||||
|
|
@ -202,6 +204,7 @@ IN_PROCESS_APPLICATION::ExecuteApplication()
|
||||||
m_pConfig->QueryProcessPath(),
|
m_pConfig->QueryProcessPath(),
|
||||||
QueryApplicationPhysicalPath(),
|
QueryApplicationPhysicalPath(),
|
||||||
m_pConfig->QueryArguments(),
|
m_pConfig->QueryArguments(),
|
||||||
|
errorContext,
|
||||||
hostFxrResolutionResult
|
hostFxrResolutionResult
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -365,6 +365,24 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.InProcess
|
||||||
EventLogHelpers.VerifyEventLogEvent(deploymentResult, EventLogHelpers.InProcessFailedToFindNativeDependencies(deploymentResult), Logger);
|
EventLogHelpers.VerifyEventLogEvent(deploymentResult, EventLogHelpers.InProcessFailedToFindNativeDependencies(deploymentResult), Logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[ConditionalFact]
|
||||||
|
public async Task SingleExecutable_FailedToFindNativeDependencies()
|
||||||
|
{
|
||||||
|
var deploymentParameters = Fixture.GetBaseDeploymentParameters(Fixture.InProcessTestSite);
|
||||||
|
deploymentParameters.ApplicationType = ApplicationType.Standalone;
|
||||||
|
var deploymentResult = await DeployAsync(deploymentParameters);
|
||||||
|
|
||||||
|
File.Delete(Path.Combine(deploymentResult.ContentRoot, "InProcessWebSite.dll"));
|
||||||
|
if (DeployerSelector.HasNewShim)
|
||||||
|
{
|
||||||
|
await AssertSiteFailsToStartWithInProcessStaticContent(deploymentResult, "HTTP Error 500.38 - ANCM Application DLL Not Found");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await AssertSiteFailsToStartWithInProcessStaticContent(deploymentResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[ConditionalFact]
|
[ConditionalFact]
|
||||||
public async Task TargedDifferenceSharedFramework_FailedToFindNativeDependenciesErrorInResponse()
|
public async Task TargedDifferenceSharedFramework_FailedToFindNativeDependenciesErrorInResponse()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// 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.Diagnostics;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Http.Features;
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue