Improve logging architecture; add tests for logging and startup exceptions (#858)
This commit is contained in:
parent
f09edb3b5d
commit
e1ae70166b
|
|
@ -37,6 +37,7 @@ project.lock.json
|
||||||
*.tlog
|
*.tlog
|
||||||
*.CppClean.log
|
*.CppClean.log
|
||||||
*msbuild.log
|
*msbuild.log
|
||||||
|
gtest.log
|
||||||
|
|
||||||
src/*/*/Debug/
|
src/*/*/Debug/
|
||||||
src/*/*/x64/Debug/
|
src/*/*/x64/Debug/
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "InProcessRequestHandler", "
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OutOfProcessRequestHandler", "src\AspNetCoreModuleV2\OutOfProcessRequestHandler\OutOfProcessRequestHandler.vcxproj", "{7F87406C-A3C8-4139-A68D-E4C344294A67}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OutOfProcessRequestHandler", "src\AspNetCoreModuleV2\OutOfProcessRequestHandler\OutOfProcessRequestHandler.vcxproj", "{7F87406C-A3C8-4139-A68D-E4C344294A67}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StartupExceptionWebSite", "test\WebSites\StartupExceptionWebSite\StartupExceptionWebSite.csproj", "{340C59FC-C682-4CBA-81F8-791821EC8EDE}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
|
@ -359,6 +361,16 @@ Global
|
||||||
{7F87406C-A3C8-4139-A68D-E4C344294A67}.Release|x64.Build.0 = Release|x64
|
{7F87406C-A3C8-4139-A68D-E4C344294A67}.Release|x64.Build.0 = Release|x64
|
||||||
{7F87406C-A3C8-4139-A68D-E4C344294A67}.Release|x86.ActiveCfg = Release|Win32
|
{7F87406C-A3C8-4139-A68D-E4C344294A67}.Release|x86.ActiveCfg = Release|Win32
|
||||||
{7F87406C-A3C8-4139-A68D-E4C344294A67}.Release|x86.Build.0 = Release|Win32
|
{7F87406C-A3C8-4139-A68D-E4C344294A67}.Release|x86.Build.0 = Release|Win32
|
||||||
|
{340C59FC-C682-4CBA-81F8-791821EC8EDE}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||||
|
{340C59FC-C682-4CBA-81F8-791821EC8EDE}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{340C59FC-C682-4CBA-81F8-791821EC8EDE}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{340C59FC-C682-4CBA-81F8-791821EC8EDE}.Debug|x86.ActiveCfg = Debug|x86
|
||||||
|
{340C59FC-C682-4CBA-81F8-791821EC8EDE}.Debug|x86.Build.0 = Debug|x86
|
||||||
|
{340C59FC-C682-4CBA-81F8-791821EC8EDE}.Release|Any CPU.ActiveCfg = Release|x86
|
||||||
|
{340C59FC-C682-4CBA-81F8-791821EC8EDE}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{340C59FC-C682-4CBA-81F8-791821EC8EDE}.Release|x64.Build.0 = Release|x64
|
||||||
|
{340C59FC-C682-4CBA-81F8-791821EC8EDE}.Release|x86.ActiveCfg = Release|x86
|
||||||
|
{340C59FC-C682-4CBA-81F8-791821EC8EDE}.Release|x86.Build.0 = Release|x86
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
@ -388,6 +400,7 @@ Global
|
||||||
{48F46909-E76A-4788-BCE1-E543C0E140FE} = {622D35C9-627B-466E-8D15-752968CC79AF}
|
{48F46909-E76A-4788-BCE1-E543C0E140FE} = {622D35C9-627B-466E-8D15-752968CC79AF}
|
||||||
{D57EA297-6DC2-4BC0-8C91-334863327863} = {06CA2C2B-83B0-4D83-905A-E0C74790009E}
|
{D57EA297-6DC2-4BC0-8C91-334863327863} = {06CA2C2B-83B0-4D83-905A-E0C74790009E}
|
||||||
{7F87406C-A3C8-4139-A68D-E4C344294A67} = {06CA2C2B-83B0-4D83-905A-E0C74790009E}
|
{7F87406C-A3C8-4139-A68D-E4C344294A67} = {06CA2C2B-83B0-4D83-905A-E0C74790009E}
|
||||||
|
{340C59FC-C682-4CBA-81F8-791821EC8EDE} = {744ACDC6-F6A0-4FF9-9421-F25C5F2DC520}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {DB4F868D-E1AE-4FD7-9333-69FA15B268C5}
|
SolutionGuid = {DB4F868D-E1AE-4FD7-9333-69FA15B268C5}
|
||||||
|
|
|
||||||
|
|
@ -1,238 +1,247 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<ItemGroup Label="ProjectConfigurations">
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
<ProjectConfiguration Include="Debug|Win32">
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
<Configuration>Debug</Configuration>
|
<Configuration>Debug</Configuration>
|
||||||
<Platform>Win32</Platform>
|
<Platform>Win32</Platform>
|
||||||
</ProjectConfiguration>
|
</ProjectConfiguration>
|
||||||
<ProjectConfiguration Include="Release|Win32">
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
<Configuration>Release</Configuration>
|
<Configuration>Release</Configuration>
|
||||||
<Platform>Win32</Platform>
|
<Platform>Win32</Platform>
|
||||||
</ProjectConfiguration>
|
</ProjectConfiguration>
|
||||||
<ProjectConfiguration Include="Debug|x64">
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
<Configuration>Debug</Configuration>
|
<Configuration>Debug</Configuration>
|
||||||
<Platform>x64</Platform>
|
<Platform>x64</Platform>
|
||||||
</ProjectConfiguration>
|
</ProjectConfiguration>
|
||||||
<ProjectConfiguration Include="Release|x64">
|
<ProjectConfiguration Include="Release|x64">
|
||||||
<Configuration>Release</Configuration>
|
<Configuration>Release</Configuration>
|
||||||
<Platform>x64</Platform>
|
<Platform>x64</Platform>
|
||||||
</ProjectConfiguration>
|
</ProjectConfiguration>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Label="Globals">
|
<PropertyGroup Label="Globals">
|
||||||
<VCProjectVersion>15.0</VCProjectVersion>
|
<VCProjectVersion>15.0</VCProjectVersion>
|
||||||
<ProjectGuid>{55494E58-E061-4C4C-A0A8-837008E72F85}</ProjectGuid>
|
<ProjectGuid>{55494E58-E061-4C4C-A0A8-837008E72F85}</ProjectGuid>
|
||||||
<Keyword>Win32Proj</Keyword>
|
<Keyword>Win32Proj</Keyword>
|
||||||
<RootNamespace>NewCommon</RootNamespace>
|
<RootNamespace>NewCommon</RootNamespace>
|
||||||
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
|
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
<UseDebugLibraries>true</UseDebugLibraries>
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
<PlatformToolset>v141</PlatformToolset>
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
<CharacterSet>Unicode</CharacterSet>
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
<PlatformToolset>v141</PlatformToolset>
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
<CharacterSet>Unicode</CharacterSet>
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
<UseDebugLibraries>true</UseDebugLibraries>
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
<PlatformToolset>v141</PlatformToolset>
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
<CharacterSet>Unicode</CharacterSet>
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
<PlatformToolset>v141</PlatformToolset>
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||||
<CharacterSet>Unicode</CharacterSet>
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
<ImportGroup Label="ExtensionSettings">
|
<ImportGroup Label="ExtensionSettings">
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
<ImportGroup Label="Shared">
|
<ImportGroup Label="Shared">
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
<PropertyGroup Label="UserMacros" />
|
<PropertyGroup Label="UserMacros" />
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<LinkIncremental>true</LinkIncremental>
|
<LinkIncremental>true</LinkIncremental>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
<LinkIncremental>true</LinkIncremental>
|
<LinkIncremental>true</LinkIncremental>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
<LinkIncremental>false</LinkIncremental>
|
<LinkIncremental>false</LinkIncremental>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
<LinkIncremental>false</LinkIncremental>
|
<LinkIncremental>false</LinkIncremental>
|
||||||
<IncludePath>C:\AspNetCoreModule\src\IISLib;$(IncludePath)</IncludePath>
|
<IncludePath>C:\AspNetCoreModule\src\IISLib;$(IncludePath)</IncludePath>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
<WarningLevel>Level4</WarningLevel>
|
<WarningLevel>Level4</WarningLevel>
|
||||||
<TreatWarningAsError>true</TreatWarningAsError>
|
<TreatWarningAsError>true</TreatWarningAsError>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<SDLCheck>false</SDLCheck>
|
<SDLCheck>false</SDLCheck>
|
||||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<ConformanceMode>true</ConformanceMode>
|
<ConformanceMode>true</ConformanceMode>
|
||||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||||
<ShowIncludes>false</ShowIncludes>
|
<ShowIncludes>false</ShowIncludes>
|
||||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||||
<AdditionalIncludeDirectories>..\iislib;</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\iislib;</AdditionalIncludeDirectories>
|
||||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
<WarningLevel>Level4</WarningLevel>
|
<WarningLevel>Level4</WarningLevel>
|
||||||
<TreatWarningAsError>true</TreatWarningAsError>
|
<TreatWarningAsError>true</TreatWarningAsError>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<SDLCheck>false</SDLCheck>
|
<SDLCheck>false</SDLCheck>
|
||||||
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<ConformanceMode>true</ConformanceMode>
|
<ConformanceMode>true</ConformanceMode>
|
||||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||||
<MinimalRebuild>false</MinimalRebuild>
|
<MinimalRebuild>false</MinimalRebuild>
|
||||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||||
<ShowIncludes>false</ShowIncludes>
|
<ShowIncludes>false</ShowIncludes>
|
||||||
<AdditionalIncludeDirectories>..\iislib;</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\iislib;</AdditionalIncludeDirectories>
|
||||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
<WarningLevel>Level4</WarningLevel>
|
<WarningLevel>Level4</WarningLevel>
|
||||||
<TreatWarningAsError>true</TreatWarningAsError>
|
<TreatWarningAsError>true</TreatWarningAsError>
|
||||||
<Optimization>MaxSpeed</Optimization>
|
<Optimization>MaxSpeed</Optimization>
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<SDLCheck>false</SDLCheck>
|
<SDLCheck>false</SDLCheck>
|
||||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<ConformanceMode>true</ConformanceMode>
|
<ConformanceMode>true</ConformanceMode>
|
||||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
<ShowIncludes>false</ShowIncludes>
|
<ShowIncludes>false</ShowIncludes>
|
||||||
<AdditionalIncludeDirectories>..\iislib;</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\iislib;</AdditionalIncludeDirectories>
|
||||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
<WarningLevel>Level4</WarningLevel>
|
<WarningLevel>Level4</WarningLevel>
|
||||||
<TreatWarningAsError>true</TreatWarningAsError>
|
<TreatWarningAsError>true</TreatWarningAsError>
|
||||||
<Optimization>MaxSpeed</Optimization>
|
<Optimization>MaxSpeed</Optimization>
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<SDLCheck>false</SDLCheck>
|
<SDLCheck>false</SDLCheck>
|
||||||
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<ConformanceMode>true</ConformanceMode>
|
<ConformanceMode>true</ConformanceMode>
|
||||||
<AdditionalIncludeDirectories>..\iislib;</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\iislib;</AdditionalIncludeDirectories>
|
||||||
<AdditionalUsingDirectories>
|
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||||
</AdditionalUsingDirectories>
|
<AdditionalUsingDirectories>
|
||||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
</AdditionalUsingDirectories>
|
||||||
<ShowIncludes>false</ShowIncludes>
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
<ShowIncludes>false</ShowIncludes>
|
||||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
</Link>
|
</Link>
|
||||||
<Lib>
|
<Lib>
|
||||||
<AdditionalLibraryDirectories>..\iislib</AdditionalLibraryDirectories>
|
<AdditionalLibraryDirectories>..\iislib</AdditionalLibraryDirectories>
|
||||||
</Lib>
|
</Lib>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="application.h" />
|
<ClInclude Include="application.h" />
|
||||||
<ClInclude Include="fx_ver.h" />
|
<ClInclude Include="NullOutputManager.h" />
|
||||||
<ClInclude Include="hostfxroptions.h" />
|
<ClInclude Include="FileOutputManager.h" />
|
||||||
<ClInclude Include="hostfxr_utility.h" />
|
<ClInclude Include="fx_ver.h" />
|
||||||
<ClInclude Include="iapplication.h" />
|
<ClInclude Include="hostfxroptions.h" />
|
||||||
<ClInclude Include="debugutil.h" />
|
<ClInclude Include="hostfxr_utility.h" />
|
||||||
<ClInclude Include="disconnectcontext.h" />
|
<ClInclude Include="iapplication.h" />
|
||||||
<ClInclude Include="environmentvariablehash.h" />
|
<ClInclude Include="debugutil.h" />
|
||||||
<ClInclude Include="irequesthandler.h" />
|
<ClInclude Include="disconnectcontext.h" />
|
||||||
<ClInclude Include="requesthandler.h" />
|
<ClInclude Include="environmentvariablehash.h" />
|
||||||
<ClInclude Include="requesthandler_config.h" />
|
<ClInclude Include="IOutputManager.h" />
|
||||||
<ClInclude Include="resources.h" />
|
<ClInclude Include="irequesthandler.h" />
|
||||||
<ClInclude Include="SRWLockWrapper.h" />
|
<ClInclude Include="LoggingHelpers.h" />
|
||||||
<ClInclude Include="stdafx.h" />
|
<ClInclude Include="PipeOutputManager.h" />
|
||||||
<ClInclude Include="utility.h" />
|
<ClInclude Include="requesthandler.h" />
|
||||||
</ItemGroup>
|
<ClInclude Include="requesthandler_config.h" />
|
||||||
<ItemGroup>
|
<ClInclude Include="resources.h" />
|
||||||
<ClCompile Include="fx_ver.cxx" />
|
<ClInclude Include="SRWLockWrapper.h" />
|
||||||
<ClCompile Include="hostfxroptions.cpp" />
|
<ClInclude Include="stdafx.h" />
|
||||||
<ClCompile Include="hostfxr_utility.cpp" />
|
<ClInclude Include="sttimer.h" />
|
||||||
<ClCompile Include="requesthandler_config.cpp" />
|
<ClInclude Include="utility.h" />
|
||||||
<ClCompile Include="SRWLockWrapper.cpp" />
|
</ItemGroup>
|
||||||
<ClCompile Include="stdafx.cpp">
|
<ItemGroup>
|
||||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
<ClCompile Include="FileOutputManager.cpp" />
|
||||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
<ClCompile Include="fx_ver.cxx" />
|
||||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
<ClCompile Include="hostfxr_utility.cpp" />
|
||||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
<ClCompile Include="hostfxroptions.cpp" />
|
||||||
</ClCompile>
|
<ClCompile Include="requesthandler_config.cpp" />
|
||||||
<ClCompile Include="utility.cxx" />
|
<ClCompile Include="LoggingHelpers.cpp" />
|
||||||
</ItemGroup>
|
<ClCompile Include="PipeOutputManager.cpp" />
|
||||||
<ItemGroup>
|
<ClCompile Include="SRWLockWrapper.cpp" />
|
||||||
<ProjectReference Include="..\IISLib\IISLib.vcxproj">
|
<ClCompile Include="stdafx.cpp">
|
||||||
<Project>{4787a64f-9a3e-4867-a55a-70cb4b2b2ffe}</Project>
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||||
</ProjectReference>
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||||
</ItemGroup>
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||||
<ItemGroup>
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||||
<CustomBuild Include="aspnetcore_msg.mc">
|
</ClCompile>
|
||||||
<FileType>Document</FileType>
|
<ClCompile Include="utility.cxx" />
|
||||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">mc %(FullPath)</Command>
|
</ItemGroup>
|
||||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Compiling Event Messages ...</Message>
|
<ItemGroup>
|
||||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(Filename).rc;%(Filename).h;MSG0409.bin</Outputs>
|
<ProjectReference Include="..\IISLib\IISLib.vcxproj">
|
||||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">mc %(FullPath)</Command>
|
<Project>{4787a64f-9a3e-4867-a55a-70cb4b2b2ffe}</Project>
|
||||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Compiling Event Messages ...</Message>
|
</ProjectReference>
|
||||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(Filename).rc;%(Filename).h;MSG0409.bin</Outputs>
|
</ItemGroup>
|
||||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">mc %(FullPath)</Command>
|
<ItemGroup>
|
||||||
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Compiling Event Messages ...</Message>
|
<CustomBuild Include="aspnetcore_msg.mc">
|
||||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(Filename).rc;%(Filename).h;MSG0409.bin</Outputs>
|
<FileType>Document</FileType>
|
||||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">mc %(FullPath)</Command>
|
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">mc %(FullPath)</Command>
|
||||||
<Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Compiling Event Messages ...</Message>
|
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Compiling Event Messages ...</Message>
|
||||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(Filename).rc;%(Filename).h;MSG0409.bin</Outputs>
|
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(Filename).rc;%(Filename).h;MSG0409.bin</Outputs>
|
||||||
</CustomBuild>
|
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">mc %(FullPath)</Command>
|
||||||
</ItemGroup>
|
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Compiling Event Messages ...</Message>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(Filename).rc;%(Filename).h;MSG0409.bin</Outputs>
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">mc %(FullPath)</Command>
|
||||||
</ImportGroup>
|
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Compiling Event Messages ...</Message>
|
||||||
|
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(Filename).rc;%(Filename).h;MSG0409.bin</Outputs>
|
||||||
|
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">mc %(FullPath)</Command>
|
||||||
|
<Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Compiling Event Messages ...</Message>
|
||||||
|
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(Filename).rc;%(Filename).h;MSG0409.bin</Outputs>
|
||||||
|
</CustomBuild>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
@ -0,0 +1,184 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
#include "stdafx.h"
|
||||||
|
|
||||||
|
|
||||||
|
FileOutputManager::FileOutputManager()
|
||||||
|
: m_pStdOutFile(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FileOutputManager::~FileOutputManager()
|
||||||
|
{
|
||||||
|
HANDLE handle = NULL;
|
||||||
|
WIN32_FIND_DATA fileData;
|
||||||
|
|
||||||
|
if (m_pStdOutFile != NULL)
|
||||||
|
{
|
||||||
|
m_Timer.CancelTimer();
|
||||||
|
_close(_fileno(m_pStdOutFile));
|
||||||
|
m_pStdOutFile = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete empty log file
|
||||||
|
handle = FindFirstFile(m_struLogFilePath.QueryStr(), &fileData);
|
||||||
|
if (handle != INVALID_HANDLE_VALUE &&
|
||||||
|
fileData.nFileSizeHigh == 0 &&
|
||||||
|
fileData.nFileSizeLow == 0) // skip check of nFileSizeHigh
|
||||||
|
{
|
||||||
|
FindClose(handle);
|
||||||
|
// no need to check whether the deletion succeeds
|
||||||
|
// as nothing can be done
|
||||||
|
DeleteFile(m_struLogFilePath.QueryStr());
|
||||||
|
}
|
||||||
|
|
||||||
|
_dup2(m_fdStdOut, _fileno(stdout));
|
||||||
|
_dup2(m_fdStdErr, _fileno(stderr));
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT
|
||||||
|
FileOutputManager::Initialize(PCWSTR pwzStdOutLogFileName, PCWSTR pwzApplicationPath)
|
||||||
|
{
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr = m_wsApplicationPath.Copy(pwzApplicationPath)))
|
||||||
|
{
|
||||||
|
hr = m_wsStdOutLogFileName.Copy(pwzStdOutLogFileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileOutputManager::NotifyStartupComplete()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileOutputManager::GetStdOutContent(STRA* struStdOutput)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// Ungraceful shutdown, try to log an error message.
|
||||||
|
// This will be a common place for errors as it means the hostfxr_main returned
|
||||||
|
// or there was an exception.
|
||||||
|
//
|
||||||
|
CHAR pzFileContents[4096] = { 0 };
|
||||||
|
DWORD dwNumBytesRead;
|
||||||
|
LARGE_INTEGER li = { 0 };
|
||||||
|
BOOL fLogged = FALSE;
|
||||||
|
DWORD dwFilePointer = 0;
|
||||||
|
|
||||||
|
if (m_hLogFileHandle != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
if (GetFileSizeEx(m_hLogFileHandle, &li) && li.LowPart > 0 && li.HighPart == 0)
|
||||||
|
{
|
||||||
|
if (li.LowPart > 4096)
|
||||||
|
{
|
||||||
|
dwFilePointer = SetFilePointer(m_hLogFileHandle, -4096, NULL, FILE_END);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dwFilePointer = SetFilePointer(m_hLogFileHandle, 0, NULL, FILE_BEGIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dwFilePointer != INVALID_SET_FILE_POINTER)
|
||||||
|
{
|
||||||
|
// Read file fails.
|
||||||
|
if (ReadFile(m_hLogFileHandle, pzFileContents, 4096, &dwNumBytesRead, NULL))
|
||||||
|
{
|
||||||
|
if (SUCCEEDED(struStdOutput->Copy(pzFileContents, dwNumBytesRead)))
|
||||||
|
{
|
||||||
|
fLogged = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fLogged;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT
|
||||||
|
FileOutputManager::Start()
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
SYSTEMTIME systemTime;
|
||||||
|
SECURITY_ATTRIBUTES saAttr = { 0 };
|
||||||
|
STRU struPath;
|
||||||
|
|
||||||
|
hr = UTILITY::ConvertPathToFullPath(
|
||||||
|
m_wsStdOutLogFileName.QueryStr(),
|
||||||
|
m_wsApplicationPath.QueryStr(),
|
||||||
|
&struPath);
|
||||||
|
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
goto Finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = UTILITY::EnsureDirectoryPathExist(struPath.QueryStr());
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
goto Finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_fdStdOut = _dup(_fileno(stdout));
|
||||||
|
if (m_fdStdOut == -1)
|
||||||
|
{
|
||||||
|
hr = E_HANDLE;
|
||||||
|
goto Finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_fdStdErr = _dup(_fileno(stderr));
|
||||||
|
if (m_fdStdErr == -1)
|
||||||
|
{
|
||||||
|
hr = E_HANDLE;
|
||||||
|
goto Finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
GetSystemTime(&systemTime);
|
||||||
|
hr = m_struLogFilePath.SafeSnwprintf(L"%s_%d%02d%02d%02d%02d%02d_%d.log",
|
||||||
|
struPath.QueryStr(),
|
||||||
|
systemTime.wYear,
|
||||||
|
systemTime.wMonth,
|
||||||
|
systemTime.wDay,
|
||||||
|
systemTime.wHour,
|
||||||
|
systemTime.wMinute,
|
||||||
|
systemTime.wSecond,
|
||||||
|
GetCurrentProcessId());
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
goto Finished;
|
||||||
|
}
|
||||||
|
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||||
|
saAttr.bInheritHandle = TRUE;
|
||||||
|
saAttr.lpSecurityDescriptor = NULL;
|
||||||
|
|
||||||
|
if (_wfreopen_s(&m_pStdOutFile, m_struLogFilePath.QueryStr(), L"w+", stdout) == 0)
|
||||||
|
{
|
||||||
|
setvbuf(m_pStdOutFile, NULL, _IONBF, 0);
|
||||||
|
if (_dup2(_fileno(m_pStdOutFile), _fileno(stdout)) == -1)
|
||||||
|
{
|
||||||
|
hr = E_HANDLE;
|
||||||
|
goto Finished;
|
||||||
|
}
|
||||||
|
if (_dup2(_fileno(m_pStdOutFile), _fileno(stderr)) == -1)
|
||||||
|
{
|
||||||
|
hr = E_HANDLE;
|
||||||
|
goto Finished;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_hLogFileHandle = (HANDLE)_get_osfhandle(_fileno(m_pStdOutFile));
|
||||||
|
if (m_hLogFileHandle == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
hr = E_HANDLE;
|
||||||
|
goto Finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Periodically flush the log content to file
|
||||||
|
m_Timer.InitializeTimer(STTIMER::TimerCallback, &m_struLogFilePath, FILE_FLUSH_TIMEOUT, FILE_FLUSH_TIMEOUT);
|
||||||
|
|
||||||
|
Finished:
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
class FileOutputManager : public IOutputManager
|
||||||
|
{
|
||||||
|
#define FILE_FLUSH_TIMEOUT 3000
|
||||||
|
public:
|
||||||
|
FileOutputManager();
|
||||||
|
~FileOutputManager();
|
||||||
|
|
||||||
|
HRESULT
|
||||||
|
Initialize(PCWSTR pwzStdOutLogFileName, PCWSTR pwzApplciationpath);
|
||||||
|
|
||||||
|
virtual bool GetStdOutContent(STRA* struStdOutput) override;
|
||||||
|
virtual HRESULT Start() override;
|
||||||
|
virtual void NotifyStartupComplete() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
HANDLE m_hLogFileHandle;
|
||||||
|
STTIMER m_Timer;
|
||||||
|
STRU m_wsStdOutLogFileName;
|
||||||
|
STRU m_wsApplicationPath;
|
||||||
|
STRU m_struLogFilePath;
|
||||||
|
int m_fdStdOut;
|
||||||
|
int m_fdStdErr;
|
||||||
|
FILE* m_pStdOutFile;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
#include "stdafx.h"
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
class IOutputManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual
|
||||||
|
HRESULT
|
||||||
|
Start() = 0;
|
||||||
|
|
||||||
|
virtual
|
||||||
|
~IOutputManager() {};
|
||||||
|
|
||||||
|
virtual
|
||||||
|
void
|
||||||
|
NotifyStartupComplete() = 0;
|
||||||
|
|
||||||
|
virtual
|
||||||
|
bool
|
||||||
|
GetStdOutContent(STRA* struStdOutput) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
#include "stdafx.h"
|
||||||
|
|
||||||
|
HRESULT
|
||||||
|
LoggingHelpers::CreateLoggingProvider(
|
||||||
|
bool fIsLoggingEnabled,
|
||||||
|
bool fEnablePipe,
|
||||||
|
PCWSTR pwzStdOutFileName,
|
||||||
|
PCWSTR pwzApplicationPath,
|
||||||
|
_Out_ IOutputManager** outputManager
|
||||||
|
)
|
||||||
|
{
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
|
||||||
|
DBG_ASSERT(outputManager != NULL);
|
||||||
|
|
||||||
|
if (fIsLoggingEnabled)
|
||||||
|
{
|
||||||
|
FileOutputManager* manager = new FileOutputManager;
|
||||||
|
hr = manager->Initialize(pwzStdOutFileName, pwzApplicationPath);
|
||||||
|
*outputManager = manager;
|
||||||
|
}
|
||||||
|
else if (fEnablePipe)
|
||||||
|
{
|
||||||
|
*outputManager = new PipeOutputManager;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*outputManager = new NullOutputManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
class LoggingHelpers
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
static
|
||||||
|
HRESULT
|
||||||
|
CreateLoggingProvider(
|
||||||
|
bool fLoggingEnabled,
|
||||||
|
bool fEnablePipe,
|
||||||
|
PCWSTR pwzStdOutFileName,
|
||||||
|
PCWSTR pwzApplicationPath,
|
||||||
|
_Out_ IOutputManager** outputManager
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "stdafx.h"
|
||||||
|
|
||||||
|
class NullOutputManager : public IOutputManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
NullOutputManager() = default;
|
||||||
|
|
||||||
|
~NullOutputManager() = default;
|
||||||
|
|
||||||
|
HRESULT Start()
|
||||||
|
{
|
||||||
|
// The process has console, e.g., IIS Express scenario
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NotifyStartupComplete()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetStdOutContent(STRA*)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
@ -0,0 +1,196 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
#include "stdafx.h"
|
||||||
|
|
||||||
|
PipeOutputManager::PipeOutputManager() :
|
||||||
|
m_dwStdErrReadTotal(0),
|
||||||
|
m_hErrReadPipe(INVALID_HANDLE_VALUE),
|
||||||
|
m_hErrWritePipe(INVALID_HANDLE_VALUE),
|
||||||
|
m_hErrThread(INVALID_HANDLE_VALUE),
|
||||||
|
m_fDisposed(FALSE)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PipeOutputManager::~PipeOutputManager()
|
||||||
|
{
|
||||||
|
StopOutputRedirection();
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
PipeOutputManager::StopOutputRedirection()
|
||||||
|
{
|
||||||
|
DWORD dwThreadStatus = 0;
|
||||||
|
STRA straStdOutput;
|
||||||
|
|
||||||
|
if (m_fDisposed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_fDisposed = true;
|
||||||
|
|
||||||
|
fflush(stdout);
|
||||||
|
fflush(stderr);
|
||||||
|
|
||||||
|
if (m_hErrWritePipe != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
CloseHandle(m_hErrWritePipe);
|
||||||
|
m_hErrWritePipe = INVALID_HANDLE_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_hErrThread != NULL &&
|
||||||
|
GetExitCodeThread(m_hErrThread, &dwThreadStatus) != 0 &&
|
||||||
|
dwThreadStatus == STILL_ACTIVE)
|
||||||
|
{
|
||||||
|
// wait for gracefullshut down, i.e., the exit of the background thread or timeout
|
||||||
|
if (WaitForSingleObject(m_hErrThread, PIPE_OUTPUT_THREAD_TIMEOUT) != WAIT_OBJECT_0)
|
||||||
|
{
|
||||||
|
// if the thread is still running, we need kill it first before exit to avoid AV
|
||||||
|
if (GetExitCodeThread(m_hErrThread, &dwThreadStatus) != 0 && dwThreadStatus == STILL_ACTIVE)
|
||||||
|
{
|
||||||
|
TerminateThread(m_hErrThread, STATUS_CONTROL_C_EXIT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseHandle(m_hErrThread);
|
||||||
|
m_hErrThread = NULL;
|
||||||
|
|
||||||
|
if (m_hErrReadPipe != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
CloseHandle(m_hErrReadPipe);
|
||||||
|
m_hErrReadPipe = INVALID_HANDLE_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore the original stdout and stderr handles of the process,
|
||||||
|
// as the application has either finished startup or has exited.
|
||||||
|
if (_dup2(m_fdStdOut, _fileno(stdout)) == -1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_dup2(m_fdStdErr, _fileno(stderr)) == -1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetStdOutContent(&straStdOutput))
|
||||||
|
{
|
||||||
|
printf(straStdOutput.QueryStr());
|
||||||
|
// Need to flush contents.
|
||||||
|
_flushall();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT PipeOutputManager::Start()
|
||||||
|
{
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
SECURITY_ATTRIBUTES saAttr = { 0 };
|
||||||
|
HANDLE hStdErrReadPipe;
|
||||||
|
HANDLE hStdErrWritePipe;
|
||||||
|
|
||||||
|
m_fdStdOut = _dup(_fileno(stdout));
|
||||||
|
if (m_fdStdOut == -1)
|
||||||
|
{
|
||||||
|
hr = E_HANDLE;
|
||||||
|
goto Finished;
|
||||||
|
}
|
||||||
|
m_fdStdErr = _dup(_fileno(stderr));
|
||||||
|
if (m_fdStdErr == -1)
|
||||||
|
{
|
||||||
|
hr = E_HANDLE;
|
||||||
|
goto Finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CreatePipe(&hStdErrReadPipe, &hStdErrWritePipe, &saAttr, 0 /*nSize*/))
|
||||||
|
{
|
||||||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||||
|
goto Finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO this still doesn't redirect calls in native, like wprintf
|
||||||
|
if (!SetStdHandle(STD_ERROR_HANDLE, hStdErrWritePipe))
|
||||||
|
{
|
||||||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||||
|
goto Finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SetStdHandle(STD_OUTPUT_HANDLE, hStdErrWritePipe))
|
||||||
|
{
|
||||||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||||
|
goto Finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_hErrReadPipe = hStdErrReadPipe;
|
||||||
|
m_hErrWritePipe = hStdErrWritePipe;
|
||||||
|
|
||||||
|
// Read the stderr handle on a separate thread until we get 4096 bytes.
|
||||||
|
m_hErrThread = CreateThread(
|
||||||
|
NULL, // default security attributes
|
||||||
|
0, // default stack size
|
||||||
|
(LPTHREAD_START_ROUTINE)ReadStdErrHandle,
|
||||||
|
this, // thread function arguments
|
||||||
|
0, // default creation flags
|
||||||
|
NULL); // receive thread identifier
|
||||||
|
|
||||||
|
if (m_hErrThread == NULL)
|
||||||
|
{
|
||||||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||||
|
goto Finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
Finished:
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
PipeOutputManager::ReadStdErrHandle(
|
||||||
|
LPVOID pContext
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PipeOutputManager *pLoggingProvider = (PipeOutputManager*)pContext;
|
||||||
|
DBG_ASSERT(pLoggingProvider != NULL);
|
||||||
|
pLoggingProvider->ReadStdErrHandleInternal();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PipeOutputManager::GetStdOutContent(STRA* struStdOutput)
|
||||||
|
{
|
||||||
|
bool fLogged = false;
|
||||||
|
if (m_dwStdErrReadTotal > 0)
|
||||||
|
{
|
||||||
|
if (SUCCEEDED(struStdOutput->Copy(m_pzFileContents, m_dwStdErrReadTotal)))
|
||||||
|
{
|
||||||
|
fLogged = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fLogged;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
PipeOutputManager::ReadStdErrHandleInternal(
|
||||||
|
VOID
|
||||||
|
)
|
||||||
|
{
|
||||||
|
DWORD dwNumBytesRead = 0;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (ReadFile(m_hErrReadPipe, &m_pzFileContents[m_dwStdErrReadTotal], MAX_PIPE_READ_SIZE - m_dwStdErrReadTotal, &dwNumBytesRead, NULL))
|
||||||
|
{
|
||||||
|
m_dwStdErrReadTotal += dwNumBytesRead;
|
||||||
|
if (m_dwStdErrReadTotal >= MAX_PIPE_READ_SIZE)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (GetLastError() == ERROR_BROKEN_PIPE)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
PipeOutputManager::NotifyStartupComplete()
|
||||||
|
{
|
||||||
|
StopOutputRedirection();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
class PipeOutputManager : public IOutputManager
|
||||||
|
{
|
||||||
|
#define PIPE_OUTPUT_THREAD_TIMEOUT 2000
|
||||||
|
#define MAX_PIPE_READ_SIZE 4096
|
||||||
|
public:
|
||||||
|
PipeOutputManager();
|
||||||
|
~PipeOutputManager();
|
||||||
|
|
||||||
|
// Inherited via ILoggerProvider
|
||||||
|
virtual HRESULT Start() override;
|
||||||
|
virtual void NotifyStartupComplete() override;
|
||||||
|
|
||||||
|
// Inherited via IOutputManager
|
||||||
|
virtual bool GetStdOutContent(STRA* struStdOutput) override;
|
||||||
|
|
||||||
|
VOID ReadStdErrHandleInternal(VOID);
|
||||||
|
|
||||||
|
static
|
||||||
|
VOID ReadStdErrHandle(LPVOID pContext);
|
||||||
|
|
||||||
|
VOID StopOutputRedirection();
|
||||||
|
private:
|
||||||
|
HANDLE m_hErrReadPipe;
|
||||||
|
HANDLE m_hErrWritePipe;
|
||||||
|
STRU m_struLogFilePath;
|
||||||
|
HANDLE m_hErrThread;
|
||||||
|
CHAR m_pzFileContents[MAX_PIPE_READ_SIZE] = { 0 };
|
||||||
|
BOOL m_fDisposed;
|
||||||
|
DWORD m_dwStdErrReadTotal;
|
||||||
|
int m_fdStdOut;
|
||||||
|
int m_fdStdErr;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "SRWLockWrapper.h"
|
#include "SRWLockWrapper.h"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,8 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
class SRWLockWrapper
|
class SRWLockWrapper
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include "Shlwapi.h"
|
#include "Shlwapi.h"
|
||||||
|
#include <io.h>
|
||||||
#include "hashtable.h"
|
#include "hashtable.h"
|
||||||
#include "stringu.h"
|
#include "stringu.h"
|
||||||
#include "stringa.h"
|
#include "stringa.h"
|
||||||
|
|
@ -23,6 +24,7 @@
|
||||||
#include "ahutil.h"
|
#include "ahutil.h"
|
||||||
#include "hashfn.h"
|
#include "hashfn.h"
|
||||||
#include "irequesthandler.h"
|
#include "irequesthandler.h"
|
||||||
|
#include "sttimer.h"
|
||||||
#include "requesthandler.h"
|
#include "requesthandler.h"
|
||||||
#include "iapplication.h"
|
#include "iapplication.h"
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
|
|
@ -34,3 +36,8 @@
|
||||||
#include "fx_ver.h"
|
#include "fx_ver.h"
|
||||||
#include "hostfxr_utility.h"
|
#include "hostfxr_utility.h"
|
||||||
#include "hostfxroptions.h"
|
#include "hostfxroptions.h"
|
||||||
|
#include "IOutputManager.h"
|
||||||
|
#include "FileOutputManager.h"
|
||||||
|
#include "PipeOutputManager.h"
|
||||||
|
#include "NullOutputManager.h"
|
||||||
|
#include "LoggingHelpers.h"
|
||||||
|
|
|
||||||
|
|
@ -214,7 +214,6 @@
|
||||||
<ClInclude Include="disconnectcontext.h" />
|
<ClInclude Include="disconnectcontext.h" />
|
||||||
<ClInclude Include="environmentvariablehelpers.h" />
|
<ClInclude Include="environmentvariablehelpers.h" />
|
||||||
<ClInclude Include="precomp.hxx" />
|
<ClInclude Include="precomp.hxx" />
|
||||||
<ClInclude Include="sttimer.h" />
|
|
||||||
<ClInclude Include=".\inprocess\inprocessapplication.h" />
|
<ClInclude Include=".\inprocess\inprocessapplication.h" />
|
||||||
<ClInclude Include=".\inprocess\inprocesshandler.h" />
|
<ClInclude Include=".\inprocess\inprocesshandler.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,6 @@ IN_PROCESS_APPLICATION::IN_PROCESS_APPLICATION(
|
||||||
PCWSTR pDotnetExeLocation) :
|
PCWSTR pDotnetExeLocation) :
|
||||||
m_pHttpServer(pHttpServer),
|
m_pHttpServer(pHttpServer),
|
||||||
m_ProcessExitCode(0),
|
m_ProcessExitCode(0),
|
||||||
m_hLogFileHandle(INVALID_HANDLE_VALUE),
|
|
||||||
m_hErrReadPipe(INVALID_HANDLE_VALUE),
|
|
||||||
m_hErrWritePipe(INVALID_HANDLE_VALUE),
|
|
||||||
m_dwStdErrReadTotal(0),
|
|
||||||
m_fDoneStdRedirect(FALSE),
|
|
||||||
m_fBlockCallbacksIntoManaged(FALSE),
|
m_fBlockCallbacksIntoManaged(FALSE),
|
||||||
m_fInitialized(FALSE),
|
m_fInitialized(FALSE),
|
||||||
m_fShutdownCalledFromNative(FALSE),
|
m_fShutdownCalledFromNative(FALSE),
|
||||||
|
|
@ -35,12 +30,6 @@ IN_PROCESS_APPLICATION::IN_PROCESS_APPLICATION(
|
||||||
|
|
||||||
IN_PROCESS_APPLICATION::~IN_PROCESS_APPLICATION()
|
IN_PROCESS_APPLICATION::~IN_PROCESS_APPLICATION()
|
||||||
{
|
{
|
||||||
if (m_hLogFileHandle != INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
m_Timer.CancelTimer();
|
|
||||||
CloseHandle(m_hLogFileHandle);
|
|
||||||
m_hLogFileHandle = INVALID_HANDLE_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_pConfig != NULL)
|
if (m_pConfig != NULL)
|
||||||
{
|
{
|
||||||
|
|
@ -106,6 +95,12 @@ IN_PROCESS_APPLICATION::ShutDown(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_pLoggerProvider != NULL)
|
||||||
|
{
|
||||||
|
delete m_pLoggerProvider;
|
||||||
|
m_pLoggerProvider = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
Finished:
|
Finished:
|
||||||
|
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
|
|
@ -131,8 +126,6 @@ IN_PROCESS_APPLICATION::ShutDownInternal()
|
||||||
{
|
{
|
||||||
DWORD dwThreadStatus = 0;
|
DWORD dwThreadStatus = 0;
|
||||||
DWORD dwTimeout = m_pConfig->QueryShutdownTimeLimitInMS();
|
DWORD dwTimeout = m_pConfig->QueryShutdownTimeLimitInMS();
|
||||||
HANDLE handle = NULL;
|
|
||||||
WIN32_FIND_DATA fileData;
|
|
||||||
|
|
||||||
if (IsDebuggerPresent())
|
if (IsDebuggerPresent())
|
||||||
{
|
{
|
||||||
|
|
@ -201,34 +194,6 @@ IN_PROCESS_APPLICATION::ShutDownInternal()
|
||||||
CloseHandle(m_hThread);
|
CloseHandle(m_hThread);
|
||||||
m_hThread = NULL;
|
m_hThread = NULL;
|
||||||
s_Application = NULL;
|
s_Application = NULL;
|
||||||
|
|
||||||
CloseStdErrHandles();
|
|
||||||
|
|
||||||
if (m_pStdFile != NULL)
|
|
||||||
{
|
|
||||||
fflush(stdout);
|
|
||||||
fflush(stderr);
|
|
||||||
fclose(m_pStdFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_hLogFileHandle != INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
m_Timer.CancelTimer();
|
|
||||||
CloseHandle(m_hLogFileHandle);
|
|
||||||
m_hLogFileHandle = INVALID_HANDLE_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete empty log file
|
|
||||||
handle = FindFirstFile(m_struLogFilePath.QueryStr(), &fileData);
|
|
||||||
if (handle != INVALID_HANDLE_VALUE &&
|
|
||||||
fileData.nFileSizeHigh == 0 &&
|
|
||||||
fileData.nFileSizeLow == 0) // skip check of nFileSizeHigh
|
|
||||||
{
|
|
||||||
FindClose(handle);
|
|
||||||
// no need to check whether the deletion succeeds
|
|
||||||
// as nothing can be done
|
|
||||||
DeleteFile(m_struLogFilePath.QueryStr());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
__override
|
__override
|
||||||
|
|
@ -371,263 +336,13 @@ IN_PROCESS_APPLICATION::SetCallbackHandles(
|
||||||
m_ShutdownHandlerContext = pvShutdownHandlerContext;
|
m_ShutdownHandlerContext = pvShutdownHandlerContext;
|
||||||
m_AsyncCompletionHandler = async_completion_handler;
|
m_AsyncCompletionHandler = async_completion_handler;
|
||||||
|
|
||||||
CloseStdErrHandles();
|
m_pLoggerProvider->NotifyStartupComplete();
|
||||||
// Can't check the std err handle as it isn't a critical error
|
// Can't check the std err handle as it isn't a critical error
|
||||||
SetStdHandle(STD_ERROR_HANDLE, INVALID_HANDLE_VALUE);
|
|
||||||
// Initialization complete
|
// Initialization complete
|
||||||
SetEvent(m_pInitalizeEvent);
|
SetEvent(m_pInitalizeEvent);
|
||||||
m_fInitialized = TRUE;
|
m_fInitialized = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID
|
|
||||||
IN_PROCESS_APPLICATION::SetStdOut(
|
|
||||||
VOID
|
|
||||||
)
|
|
||||||
{
|
|
||||||
HRESULT hr = S_OK;
|
|
||||||
STRU struPath;
|
|
||||||
SYSTEMTIME systemTime;
|
|
||||||
SECURITY_ATTRIBUTES saAttr = { 0 };
|
|
||||||
HANDLE hStdErrReadPipe;
|
|
||||||
HANDLE hStdErrWritePipe;
|
|
||||||
|
|
||||||
if (!m_fDoneStdRedirect)
|
|
||||||
{
|
|
||||||
// Have not set stdout yet, redirect stdout to log file
|
|
||||||
SRWLockWrapper lock(m_srwLock);
|
|
||||||
if (!m_fDoneStdRedirect)
|
|
||||||
{
|
|
||||||
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
||||||
saAttr.bInheritHandle = TRUE;
|
|
||||||
saAttr.lpSecurityDescriptor = NULL;
|
|
||||||
|
|
||||||
//
|
|
||||||
// best effort
|
|
||||||
// no need to capture the error code as nothing we can do here
|
|
||||||
// in case mamanged layer exits abnormally, may not be able to capture the log content as it is buffered.
|
|
||||||
//
|
|
||||||
if (!GetConsoleWindow())
|
|
||||||
{
|
|
||||||
// Full IIS scenario.
|
|
||||||
|
|
||||||
//
|
|
||||||
// SetStdHandle works as w3wp does not have Console
|
|
||||||
// Current process does not have a console
|
|
||||||
//
|
|
||||||
if (m_pConfig->QueryStdoutLogEnabled())
|
|
||||||
{
|
|
||||||
hr = UTILITY::ConvertPathToFullPath(
|
|
||||||
m_pConfig->QueryStdoutLogFile()->QueryStr(),
|
|
||||||
m_pConfig->QueryApplicationPhysicalPath()->QueryStr(),
|
|
||||||
&struPath);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
goto Finished;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr = UTILITY::EnsureDirectoryPathExist(struPath.QueryStr());
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
goto Finished;
|
|
||||||
}
|
|
||||||
|
|
||||||
GetSystemTime(&systemTime);
|
|
||||||
hr = m_struLogFilePath.SafeSnwprintf(L"%s_%d%02d%02d%02d%02d%02d_%d.log",
|
|
||||||
struPath.QueryStr(),
|
|
||||||
systemTime.wYear,
|
|
||||||
systemTime.wMonth,
|
|
||||||
systemTime.wDay,
|
|
||||||
systemTime.wHour,
|
|
||||||
systemTime.wMinute,
|
|
||||||
systemTime.wSecond,
|
|
||||||
GetCurrentProcessId());
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
goto Finished;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_hLogFileHandle = CreateFileW(m_struLogFilePath.QueryStr(),
|
|
||||||
FILE_READ_DATA | FILE_WRITE_DATA,
|
|
||||||
FILE_SHARE_READ,
|
|
||||||
&saAttr,
|
|
||||||
CREATE_ALWAYS,
|
|
||||||
FILE_ATTRIBUTE_NORMAL,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
if (m_hLogFileHandle == INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
||||||
goto Finished;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!SetStdHandle(STD_OUTPUT_HANDLE, m_hLogFileHandle))
|
|
||||||
{
|
|
||||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
||||||
goto Finished;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!SetStdHandle(STD_ERROR_HANDLE, m_hLogFileHandle))
|
|
||||||
{
|
|
||||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
||||||
goto Finished;
|
|
||||||
}
|
|
||||||
|
|
||||||
// not work
|
|
||||||
// AllocConsole() does not help
|
|
||||||
// *stdout = *m_pStdFile;
|
|
||||||
// *stderr = *m_pStdFile;
|
|
||||||
// _dup2(_fileno(m_pStdFile), _fileno(stdout));
|
|
||||||
// _dup2(_fileno(m_pStdFile), _fileno(stderr));
|
|
||||||
// this one cannot capture the process start failure
|
|
||||||
// _wfreopen_s(&m_pStdFile, struLogFileName.QueryStr(), L"w", stdout);
|
|
||||||
|
|
||||||
// Periodically flush the log content to file
|
|
||||||
m_Timer.InitializeTimer(STTIMER::TimerCallback, &m_struLogFilePath, 3000, 3000);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//
|
|
||||||
// CreatePipe for outputting stderr to the windows event log.
|
|
||||||
// Ignore failures
|
|
||||||
//
|
|
||||||
if (!CreatePipe(&hStdErrReadPipe, &hStdErrWritePipe, &saAttr, 0 /*nSize*/))
|
|
||||||
{
|
|
||||||
goto Finished;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!SetStdHandle(STD_ERROR_HANDLE, hStdErrWritePipe))
|
|
||||||
{
|
|
||||||
goto Finished;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_hErrReadPipe = hStdErrReadPipe;
|
|
||||||
m_hErrWritePipe = hStdErrWritePipe;
|
|
||||||
|
|
||||||
// Read the stderr handle on a separate thread until we get 4096 bytes.
|
|
||||||
m_hErrThread = CreateThread(
|
|
||||||
NULL, // default security attributes
|
|
||||||
0, // default stack size
|
|
||||||
(LPTHREAD_START_ROUTINE)ReadStdErrHandle,
|
|
||||||
this, // thread function arguments
|
|
||||||
0, // default creation flags
|
|
||||||
NULL); // receive thread identifier
|
|
||||||
|
|
||||||
if (m_hErrThread == NULL)
|
|
||||||
{
|
|
||||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
||||||
goto Finished;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// The process has console, e.g., IIS Express scenario
|
|
||||||
|
|
||||||
if (_wfopen_s(&m_pStdFile, m_struLogFilePath.QueryStr(), L"w") == 0)
|
|
||||||
{
|
|
||||||
// known issue: error info may not be capture when process crashes during buffering
|
|
||||||
// even we disabled FILE buffering
|
|
||||||
setvbuf(m_pStdFile, NULL, _IONBF, 0);
|
|
||||||
_dup2(_fileno(m_pStdFile), _fileno(stdout));
|
|
||||||
_dup2(_fileno(m_pStdFile), _fileno(stderr));
|
|
||||||
}
|
|
||||||
// These don't work for console scenario
|
|
||||||
// close and AllocConsole does not help
|
|
||||||
//_wfreopen_s(&m_pStdFile, struLogFileName.QueryStr(), L"w", stdout);
|
|
||||||
// SetStdHandle(STD_ERROR_HANDLE, m_hLogFileHandle);
|
|
||||||
// SetStdHandle(STD_OUTPUT_HANDLE, m_hLogFileHandle);
|
|
||||||
//*stdout = *m_pStdFile;
|
|
||||||
//*stderr = *m_pStdFile;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Finished:
|
|
||||||
m_fDoneStdRedirect = TRUE;
|
|
||||||
if (FAILED(hr) && m_pConfig->QueryStdoutLogEnabled())
|
|
||||||
{
|
|
||||||
UTILITY::LogEventF(g_hEventLog,
|
|
||||||
EVENTLOG_WARNING_TYPE,
|
|
||||||
ASPNETCORE_EVENT_CONFIG_ERROR,
|
|
||||||
ASPNETCORE_EVENT_INVALID_STDOUT_LOG_FILE_MSG,
|
|
||||||
m_struLogFilePath.QueryStr(),
|
|
||||||
hr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID
|
|
||||||
IN_PROCESS_APPLICATION::ReadStdErrHandle(
|
|
||||||
LPVOID pContext
|
|
||||||
)
|
|
||||||
{
|
|
||||||
IN_PROCESS_APPLICATION *pApplication = (IN_PROCESS_APPLICATION*)pContext;
|
|
||||||
DBG_ASSERT(pApplication != NULL);
|
|
||||||
pApplication->ReadStdErrHandleInternal();
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID
|
|
||||||
IN_PROCESS_APPLICATION::ReadStdErrHandleInternal(
|
|
||||||
VOID
|
|
||||||
)
|
|
||||||
{
|
|
||||||
DWORD dwNumBytesRead = 0;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if (ReadFile(m_hErrReadPipe, &m_pzFileContents[m_dwStdErrReadTotal], 4096 - m_dwStdErrReadTotal, &dwNumBytesRead, NULL))
|
|
||||||
{
|
|
||||||
m_dwStdErrReadTotal += dwNumBytesRead;
|
|
||||||
if (m_dwStdErrReadTotal >= 4096)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (GetLastError() == ERROR_BROKEN_PIPE)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID
|
|
||||||
IN_PROCESS_APPLICATION::CloseStdErrHandles
|
|
||||||
(
|
|
||||||
VOID
|
|
||||||
)
|
|
||||||
{
|
|
||||||
DWORD dwThreadStatus = 0;
|
|
||||||
DWORD dwTimeout = m_pConfig->QueryShutdownTimeLimitInMS();
|
|
||||||
// Close Handles for stderr as we only care about capturing startup errors
|
|
||||||
if (m_hErrWritePipe != INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
CloseHandle(m_hErrWritePipe);
|
|
||||||
m_hErrWritePipe = INVALID_HANDLE_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_hErrThread != NULL &&
|
|
||||||
GetExitCodeThread(m_hErrThread, &dwThreadStatus) != 0 &&
|
|
||||||
dwThreadStatus == STILL_ACTIVE)
|
|
||||||
{
|
|
||||||
// wait for gracefullshut down, i.e., the exit of the background thread or timeout
|
|
||||||
if (WaitForSingleObject(m_hErrThread, dwTimeout) != WAIT_OBJECT_0)
|
|
||||||
{
|
|
||||||
// if the thread is still running, we need kill it first before exit to avoid AV
|
|
||||||
if (GetExitCodeThread(m_hErrThread, &dwThreadStatus) != 0 && dwThreadStatus == STILL_ACTIVE)
|
|
||||||
{
|
|
||||||
TerminateThread(m_hErrThread, STATUS_CONTROL_C_EXIT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CloseHandle(m_hErrThread);
|
|
||||||
m_hErrThread = NULL;
|
|
||||||
|
|
||||||
if (m_hErrReadPipe != INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
CloseHandle(m_hErrReadPipe);
|
|
||||||
m_hErrReadPipe = INVALID_HANDLE_VALUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Will be called by the inprocesshandler
|
// Will be called by the inprocesshandler
|
||||||
HRESULT
|
HRESULT
|
||||||
IN_PROCESS_APPLICATION::LoadManagedApplication
|
IN_PROCESS_APPLICATION::LoadManagedApplication
|
||||||
|
|
@ -657,11 +372,27 @@ IN_PROCESS_APPLICATION::LoadManagedApplication
|
||||||
goto Finished;
|
goto Finished;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up stdout redirect
|
|
||||||
SetStdOut();
|
|
||||||
|
|
||||||
{
|
{
|
||||||
|
// Set up stdout redirect
|
||||||
|
|
||||||
SRWLockWrapper lock(m_srwLock);
|
SRWLockWrapper lock(m_srwLock);
|
||||||
|
|
||||||
|
if (m_pLoggerProvider == NULL)
|
||||||
|
{
|
||||||
|
hr = LoggingHelpers::CreateLoggingProvider(
|
||||||
|
m_pConfig->QueryStdoutLogEnabled(),
|
||||||
|
!GetConsoleWindow(),
|
||||||
|
m_pConfig->QueryStdoutLogFile()->QueryStr(),
|
||||||
|
m_pConfig->QueryApplicationPhysicalPath()->QueryStr(),
|
||||||
|
&m_pLoggerProvider);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
goto Finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pLoggerProvider->Start();
|
||||||
|
}
|
||||||
|
|
||||||
if (m_status != APPLICATION_STATUS::STARTING)
|
if (m_status != APPLICATION_STATUS::STARTING)
|
||||||
{
|
{
|
||||||
if (m_status == APPLICATION_STATUS::FAIL)
|
if (m_status == APPLICATION_STATUS::FAIL)
|
||||||
|
|
@ -887,6 +618,8 @@ Finished:
|
||||||
|
|
||||||
if (!m_fShutdownCalledFromNative)
|
if (!m_fShutdownCalledFromNative)
|
||||||
{
|
{
|
||||||
|
m_pLoggerProvider->NotifyStartupComplete();
|
||||||
|
|
||||||
LogErrorsOnMainExit(hr);
|
LogErrorsOnMainExit(hr);
|
||||||
if (m_fInitialized)
|
if (m_fInitialized)
|
||||||
{
|
{
|
||||||
|
|
@ -910,72 +643,20 @@ IN_PROCESS_APPLICATION::LogErrorsOnMainExit(
|
||||||
// This will be a common place for errors as it means the hostfxr_main returned
|
// This will be a common place for errors as it means the hostfxr_main returned
|
||||||
// or there was an exception.
|
// or there was an exception.
|
||||||
//
|
//
|
||||||
CHAR pzFileContents[4096] = { 0 };
|
STRA struStdErrOutput;
|
||||||
DWORD dwNumBytesRead;
|
if (m_pLoggerProvider->GetStdOutContent(&struStdErrOutput))
|
||||||
STRU struStdErrLog;
|
|
||||||
LARGE_INTEGER li = { 0 };
|
|
||||||
BOOL fLogged = FALSE;
|
|
||||||
DWORD dwFilePointer = 0;
|
|
||||||
|
|
||||||
if (m_pConfig->QueryStdoutLogEnabled())
|
|
||||||
{
|
{
|
||||||
// Put stdout/stderr logs into
|
UTILITY::LogEventF(g_hEventLog,
|
||||||
if (m_hLogFileHandle != INVALID_HANDLE_VALUE)
|
EVENTLOG_ERROR_TYPE,
|
||||||
{
|
ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT,
|
||||||
if (GetFileSizeEx(m_hLogFileHandle, &li) && li.LowPart > 0 && li.HighPart == 0)
|
ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_STDOUT_MSG,
|
||||||
{
|
m_pConfig->QueryApplicationPath()->QueryStr(),
|
||||||
if (li.LowPart > 4096)
|
m_pConfig->QueryApplicationPhysicalPath()->QueryStr(),
|
||||||
{
|
hr,
|
||||||
dwFilePointer = SetFilePointer(m_hLogFileHandle, -4096, NULL, FILE_END);
|
struStdErrOutput.QueryStr());
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dwFilePointer = SetFilePointer(m_hLogFileHandle, 0, NULL, FILE_BEGIN);
|
|
||||||
}
|
|
||||||
if (dwFilePointer != INVALID_SET_FILE_POINTER)
|
|
||||||
{
|
|
||||||
if (ReadFile(m_hLogFileHandle, pzFileContents, 4096, &dwNumBytesRead, NULL))
|
|
||||||
{
|
|
||||||
if (SUCCEEDED(struStdErrLog.CopyA(m_pzFileContents, m_dwStdErrReadTotal)))
|
|
||||||
{
|
|
||||||
UTILITY::LogEventF(g_hEventLog,
|
|
||||||
EVENTLOG_ERROR_TYPE,
|
|
||||||
ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT,
|
|
||||||
ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_STDOUT_MSG,
|
|
||||||
m_pConfig->QueryApplicationPath()->QueryStr(),
|
|
||||||
m_pConfig->QueryApplicationPhysicalPath()->QueryStr(),
|
|
||||||
hr,
|
|
||||||
struStdErrLog.QueryStr());
|
|
||||||
fLogged = TRUE;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (m_dwStdErrReadTotal > 0)
|
|
||||||
{
|
|
||||||
if (SUCCEEDED(struStdErrLog.CopyA(m_pzFileContents, m_dwStdErrReadTotal)))
|
|
||||||
{
|
|
||||||
UTILITY::LogEventF(g_hEventLog,
|
|
||||||
EVENTLOG_ERROR_TYPE,
|
|
||||||
ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT,
|
|
||||||
ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_STDERR_MSG,
|
|
||||||
m_pConfig->QueryApplicationPath()->QueryStr(),
|
|
||||||
m_pConfig->QueryApplicationPhysicalPath()->QueryStr(),
|
|
||||||
hr,
|
|
||||||
struStdErrLog.QueryStr());
|
|
||||||
fLogged = TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fLogged)
|
|
||||||
{
|
|
||||||
// If we didn't log, log the generic message.
|
|
||||||
UTILITY::LogEventF(g_hEventLog,
|
UTILITY::LogEventF(g_hEventLog,
|
||||||
EVENTLOG_ERROR_TYPE,
|
EVENTLOG_ERROR_TYPE,
|
||||||
ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT,
|
ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT,
|
||||||
|
|
@ -983,41 +664,34 @@ IN_PROCESS_APPLICATION::LogErrorsOnMainExit(
|
||||||
m_pConfig->QueryApplicationPath()->QueryStr(),
|
m_pConfig->QueryApplicationPath()->QueryStr(),
|
||||||
m_pConfig->QueryApplicationPhysicalPath()->QueryStr(),
|
m_pConfig->QueryApplicationPhysicalPath()->QueryStr(),
|
||||||
hr);
|
hr);
|
||||||
fLogged = TRUE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Calls hostfxr_main with the hostfxr and application as arguments.
|
// Calls hostfxr_main with the hostfxr and application as arguments.
|
||||||
// Method should be called with only
|
|
||||||
// Need to have __try / __except in methods that require unwinding.
|
|
||||||
// Note, this will not
|
|
||||||
//
|
//
|
||||||
HRESULT
|
HRESULT
|
||||||
IN_PROCESS_APPLICATION::RunDotnetApplication(DWORD argc, CONST PCWSTR* argv, hostfxr_main_fn pProc)
|
IN_PROCESS_APPLICATION::RunDotnetApplication(DWORD argc, CONST PCWSTR* argv, hostfxr_main_fn pProc)
|
||||||
{
|
{
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
|
|
||||||
__try
|
__try
|
||||||
{
|
{
|
||||||
m_ProcessExitCode = pProc(argc, argv);
|
m_ProcessExitCode = pProc(argc, argv);
|
||||||
|
if (m_ProcessExitCode != 0)
|
||||||
|
{
|
||||||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
__except (FilterException(GetExceptionCode(), GetExceptionInformation()))
|
__except(GetExceptionCode() != 0)
|
||||||
{
|
{
|
||||||
// TODO Log error message here.
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||||
hr = E_APPLICATION_ACTIVATION_EXEC_FAILURE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
INT
|
|
||||||
IN_PROCESS_APPLICATION::FilterException(unsigned int, struct _EXCEPTION_POINTERS*)
|
|
||||||
{
|
|
||||||
// We assume that any exception is a failure as the applicaiton didn't start or there was a startup error.
|
|
||||||
// TODO, log error based on exception code.
|
|
||||||
return EXCEPTION_EXECUTE_HANDLER;
|
|
||||||
}
|
|
||||||
|
|
||||||
REQUESTHANDLER_CONFIG*
|
REQUESTHANDLER_CONFIG*
|
||||||
IN_PROCESS_APPLICATION::QueryConfig() const
|
IN_PROCESS_APPLICATION::QueryConfig() const
|
||||||
|
|
|
||||||
|
|
@ -55,16 +55,6 @@ public:
|
||||||
VOID
|
VOID
|
||||||
);
|
);
|
||||||
|
|
||||||
VOID
|
|
||||||
ReadStdErrHandleInternal(
|
|
||||||
VOID
|
|
||||||
);
|
|
||||||
|
|
||||||
VOID
|
|
||||||
CloseStdErrHandles(
|
|
||||||
VOID
|
|
||||||
);
|
|
||||||
|
|
||||||
HRESULT
|
HRESULT
|
||||||
LoadManagedApplication(
|
LoadManagedApplication(
|
||||||
VOID
|
VOID
|
||||||
|
|
@ -130,17 +120,6 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static
|
|
||||||
DWORD
|
|
||||||
DoShutDown(
|
|
||||||
LPVOID lpParam
|
|
||||||
);
|
|
||||||
|
|
||||||
VOID
|
|
||||||
ShutDownInternal(
|
|
||||||
VOID
|
|
||||||
);
|
|
||||||
|
|
||||||
IHttpServer* const m_pHttpServer;
|
IHttpServer* const m_pHttpServer;
|
||||||
|
|
||||||
// Thread executing the .NET Core process
|
// Thread executing the .NET Core process
|
||||||
|
|
@ -159,26 +138,18 @@ private:
|
||||||
// The event that gets triggered when managed initialization is complete
|
// The event that gets triggered when managed initialization is complete
|
||||||
HANDLE m_pInitalizeEvent;
|
HANDLE m_pInitalizeEvent;
|
||||||
|
|
||||||
// The std log file handle
|
|
||||||
HANDLE m_hLogFileHandle;
|
|
||||||
HANDLE m_hErrReadPipe;
|
|
||||||
HANDLE m_hErrWritePipe;
|
|
||||||
STRU m_struLogFilePath;
|
|
||||||
STRU m_struExeLocation;
|
STRU m_struExeLocation;
|
||||||
|
|
||||||
// The exit code of the .NET Core process
|
// The exit code of the .NET Core process
|
||||||
INT m_ProcessExitCode;
|
INT m_ProcessExitCode;
|
||||||
|
|
||||||
BOOL m_fIsWebSocketsConnection;
|
BOOL m_fIsWebSocketsConnection;
|
||||||
BOOL m_fDoneStdRedirect;
|
|
||||||
volatile BOOL m_fBlockCallbacksIntoManaged;
|
volatile BOOL m_fBlockCallbacksIntoManaged;
|
||||||
volatile BOOL m_fShutdownCalledFromNative;
|
volatile BOOL m_fShutdownCalledFromNative;
|
||||||
volatile BOOL m_fShutdownCalledFromManaged;
|
volatile BOOL m_fShutdownCalledFromManaged;
|
||||||
BOOL m_fRecycleCalled;
|
BOOL m_fRecycleCalled;
|
||||||
BOOL m_fInitialized;
|
BOOL m_fInitialized;
|
||||||
|
|
||||||
FILE* m_pStdFile;
|
|
||||||
STTIMER m_Timer;
|
|
||||||
SRWLOCK m_srwLock;
|
SRWLOCK m_srwLock;
|
||||||
|
|
||||||
// Thread for capturing startup stderr logs when logging is disabled
|
// Thread for capturing startup stderr logs when logging is disabled
|
||||||
|
|
@ -188,6 +159,7 @@ private:
|
||||||
PCWSTR m_pstrDotnetExeLocation;
|
PCWSTR m_pstrDotnetExeLocation;
|
||||||
static IN_PROCESS_APPLICATION* s_Application;
|
static IN_PROCESS_APPLICATION* s_Application;
|
||||||
|
|
||||||
|
IOutputManager* m_pLoggerProvider;
|
||||||
REQUESTHANDLER_CONFIG* m_pConfig;
|
REQUESTHANDLER_CONFIG* m_pConfig;
|
||||||
|
|
||||||
// Allows to override call to hostfxr_main with custome callback
|
// Allows to override call to hostfxr_main with custome callback
|
||||||
|
|
@ -205,26 +177,26 @@ private:
|
||||||
_In_ LPVOID pContext
|
_In_ LPVOID pContext
|
||||||
);
|
);
|
||||||
|
|
||||||
static
|
|
||||||
VOID
|
|
||||||
ReadStdErrHandle
|
|
||||||
(
|
|
||||||
_In_ LPVOID pContext
|
|
||||||
);
|
|
||||||
|
|
||||||
HRESULT
|
HRESULT
|
||||||
SetEnvironementVariablesOnWorkerProcess(
|
SetEnvironementVariablesOnWorkerProcess(
|
||||||
VOID
|
VOID
|
||||||
);
|
);
|
||||||
|
|
||||||
static
|
|
||||||
INT
|
|
||||||
FilterException(unsigned int code, struct _EXCEPTION_POINTERS *ep);
|
|
||||||
|
|
||||||
HRESULT
|
HRESULT
|
||||||
RunDotnetApplication(
|
RunDotnetApplication(
|
||||||
DWORD argc,
|
DWORD argc,
|
||||||
CONST PCWSTR* argv,
|
CONST PCWSTR* argv,
|
||||||
hostfxr_main_fn pProc
|
hostfxr_main_fn pProc
|
||||||
);
|
);
|
||||||
|
|
||||||
|
static
|
||||||
|
DWORD
|
||||||
|
DoShutDown(
|
||||||
|
LPVOID lpParam
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
ShutDownInternal(
|
||||||
|
VOID
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -217,7 +217,6 @@
|
||||||
<ClInclude Include="aspnetcore_event.h" />
|
<ClInclude Include="aspnetcore_event.h" />
|
||||||
<ClInclude Include="disconnectcontext.h" />
|
<ClInclude Include="disconnectcontext.h" />
|
||||||
<ClInclude Include="environmentvariablehelpers.h" />
|
<ClInclude Include="environmentvariablehelpers.h" />
|
||||||
<ClInclude Include="sttimer.h" />
|
|
||||||
<ClInclude Include="outofprocess\forwarderconnection.h" />
|
<ClInclude Include="outofprocess\forwarderconnection.h" />
|
||||||
<ClInclude Include="outofprocess\processmanager.h" />
|
<ClInclude Include="outofprocess\processmanager.h" />
|
||||||
<ClInclude Include="outofprocess\protocolconfig.h" />
|
<ClInclude Include="outofprocess\protocolconfig.h" />
|
||||||
|
|
|
||||||
|
|
@ -32,12 +32,28 @@
|
||||||
<ImportGroup Label="Shared" />
|
<ImportGroup Label="Shared" />
|
||||||
<ImportGroup Label="PropertySheets" />
|
<ImportGroup Label="PropertySheets" />
|
||||||
<PropertyGroup Label="UserMacros" />
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<OutDir>$(MSBuildProjectDirectory)\bin\$(Configuration)\$(Platform)\</OutDir>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<OutDir>$(MSBuildProjectDirectory)\bin\$(Configuration)\$(Platform)\</OutDir>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<OutDir>$(MSBuildProjectDirectory)\bin\$(Configuration)\$(Platform)\</OutDir>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<OutDir>$(MSBuildProjectDirectory)\bin\$(Configuration)\$(Platform)\</OutDir>
|
||||||
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClInclude Include="Helpers.h" />
|
||||||
<ClInclude Include="stdafx.h" />
|
<ClInclude Include="stdafx.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="FileOutputManagerTests.cpp" />
|
||||||
|
<ClCompile Include="Helpers.cpp" />
|
||||||
<ClCompile Include="hostfxr_utility_tests.cpp" />
|
<ClCompile Include="hostfxr_utility_tests.cpp" />
|
||||||
<ClCompile Include="main.cpp" />
|
<ClCompile Include="main.cpp" />
|
||||||
|
<ClCompile Include="PipeOutputManagerTests.cpp" />
|
||||||
<ClCompile Include="stdafx.cpp">
|
<ClCompile Include="stdafx.cpp">
|
||||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||||
|
|
@ -141,7 +157,7 @@
|
||||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||||
<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)include;%(AdditionalIncludeDirectories);..\..\src\AspNetCoreModuleV2\IISLib;..\..\src\AspNetCoreModuleV2\CommonLib;..\gtest-1.8.0\include;..\..\src\AspNetCoreModuleV2\AspNetCore\Inc;</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)include;%(AdditionalIncludeDirectories);..\..\src\AspNetCoreModuleV2\IISLib;..\..\src\AspNetCoreModuleV2\CommonLib;..\gtest-1.8.0\include;..\..\src\AspNetCoreModuleV2\AspNetCore\Inc;</AdditionalIncludeDirectories>
|
||||||
<AdditionalOptions>/D "_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING" </AdditionalOptions>
|
<AdditionalOptions>/D "_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING" </AdditionalOptions>
|
||||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
<LanguageStandard>stdcpp14</LanguageStandard>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,142 @@
|
||||||
|
// 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 "gtest/internal/gtest-port.h"
|
||||||
|
|
||||||
|
class FileManagerWrapper
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FileOutputManager* manager;
|
||||||
|
FileManagerWrapper(FileOutputManager* m)
|
||||||
|
: manager(m)
|
||||||
|
{
|
||||||
|
manager->Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
~FileManagerWrapper()
|
||||||
|
{
|
||||||
|
delete manager;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace FileOutManagerStartupTests
|
||||||
|
{
|
||||||
|
using ::testing::Test;
|
||||||
|
class FileOutputManagerTest : public Test
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
void
|
||||||
|
Test(std::wstring fileNamePrefix, FILE* out)
|
||||||
|
{
|
||||||
|
PCWSTR expected = L"test";
|
||||||
|
|
||||||
|
std::wstring tempDirectory = Helpers::CreateRandomTempDirectory();
|
||||||
|
FileOutputManager* pManager = new FileOutputManager;
|
||||||
|
pManager->Initialize(fileNamePrefix.c_str(), tempDirectory.c_str());
|
||||||
|
{
|
||||||
|
FileManagerWrapper wrapper(pManager);
|
||||||
|
|
||||||
|
wprintf(expected, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
// std::filesystem is available on c++17, however gtest fails to build when using it
|
||||||
|
// c++14 has filesystem as experimental.
|
||||||
|
for (auto & p : std::experimental::filesystem::directory_iterator(tempDirectory))
|
||||||
|
{
|
||||||
|
std::wstring filename(p.path().filename());
|
||||||
|
ASSERT_EQ(filename.substr(0, fileNamePrefix.size()), fileNamePrefix);
|
||||||
|
|
||||||
|
std::wstring content = Helpers::ReadFileContent(std::wstring(p.path()));
|
||||||
|
ASSERT_EQ(content.length(), DWORD(4));
|
||||||
|
ASSERT_STREQ(content.c_str(), expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
Helpers::DeleteDirectory(tempDirectory);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(FileOutputManagerTest, WriteToFileCheckContentsWritten)
|
||||||
|
{
|
||||||
|
Test(L"", stdout);
|
||||||
|
Test(L"log", stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(FileOutputManagerTest, WriteToFileCheckContentsWrittenErr)
|
||||||
|
{
|
||||||
|
Test(L"", stderr);
|
||||||
|
Test(L"log", stderr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace FileOutManagerOutputTests
|
||||||
|
{
|
||||||
|
|
||||||
|
TEST(FileOutManagerOutputTest, StdErr)
|
||||||
|
{
|
||||||
|
PCSTR expected = "test";
|
||||||
|
|
||||||
|
std::wstring tempDirectory = Helpers::CreateRandomTempDirectory();
|
||||||
|
|
||||||
|
FileOutputManager* pManager = new FileOutputManager;
|
||||||
|
pManager->Initialize(L"", tempDirectory.c_str());
|
||||||
|
{
|
||||||
|
FileManagerWrapper wrapper(pManager);
|
||||||
|
|
||||||
|
printf(expected, stderr);
|
||||||
|
STRA straContent;
|
||||||
|
ASSERT_TRUE(pManager->GetStdOutContent(&straContent));
|
||||||
|
|
||||||
|
ASSERT_STREQ(straContent.QueryStr(), expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
Helpers::DeleteDirectory(tempDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FileOutManagerOutputTest, CheckFileOutput)
|
||||||
|
{
|
||||||
|
PCSTR expected = "test";
|
||||||
|
|
||||||
|
std::wstring tempDirectory = Helpers::CreateRandomTempDirectory();
|
||||||
|
|
||||||
|
FileOutputManager* pManager = new FileOutputManager;
|
||||||
|
pManager->Initialize(L"", tempDirectory.c_str());
|
||||||
|
{
|
||||||
|
FileManagerWrapper wrapper(pManager);
|
||||||
|
|
||||||
|
printf(expected);
|
||||||
|
STRA straContent;
|
||||||
|
ASSERT_TRUE(pManager->GetStdOutContent(&straContent));
|
||||||
|
|
||||||
|
ASSERT_STREQ(straContent.QueryStr(), expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
Helpers::DeleteDirectory(tempDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FileOutManagerOutputTest, CapAt4KB)
|
||||||
|
{
|
||||||
|
PCSTR expected = "test";
|
||||||
|
|
||||||
|
std::wstring tempDirectory = Helpers::CreateRandomTempDirectory();
|
||||||
|
|
||||||
|
FileOutputManager* pManager = new FileOutputManager;
|
||||||
|
pManager->Initialize(L"", tempDirectory.c_str());
|
||||||
|
{
|
||||||
|
FileManagerWrapper wrapper(pManager);
|
||||||
|
|
||||||
|
for (int i = 0; i < 1200; i++)
|
||||||
|
{
|
||||||
|
printf(expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
STRA straContent;
|
||||||
|
ASSERT_TRUE(pManager->GetStdOutContent(&straContent));
|
||||||
|
|
||||||
|
ASSERT_EQ(straContent.QueryCCH(), 4096);
|
||||||
|
}
|
||||||
|
|
||||||
|
Helpers::DeleteDirectory(tempDirectory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
#include "stdafx.h"
|
||||||
|
|
||||||
|
std::wstring
|
||||||
|
Helpers::CreateRandomValue()
|
||||||
|
{
|
||||||
|
int randomValue = rand();
|
||||||
|
return std::to_wstring(randomValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring
|
||||||
|
Helpers::CreateRandomTempDirectory()
|
||||||
|
{
|
||||||
|
PWSTR tempPath = new WCHAR[256];
|
||||||
|
GetTempPath(256, tempPath);
|
||||||
|
std::wstring wstringPath(tempPath);
|
||||||
|
|
||||||
|
return wstringPath.append(Helpers::CreateRandomValue()).append(L"\\");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Helpers::DeleteDirectory(std::wstring directory)
|
||||||
|
{
|
||||||
|
std::experimental::filesystem::remove_all(directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring
|
||||||
|
Helpers::ReadFileContent(std::wstring file)
|
||||||
|
{
|
||||||
|
std::wcout << file << std::endl;
|
||||||
|
|
||||||
|
std::fstream t(file);
|
||||||
|
std::stringstream buffer;
|
||||||
|
buffer << t.rdbuf();
|
||||||
|
|
||||||
|
int nChars = MultiByteToWideChar(CP_ACP, 0, buffer.str().c_str(), -1, NULL, 0);
|
||||||
|
|
||||||
|
LPWSTR pwzName = new WCHAR[nChars];
|
||||||
|
MultiByteToWideChar(CP_UTF8, 0, buffer.str().c_str(), -1, pwzName, nChars);
|
||||||
|
|
||||||
|
std::wstring retVal(pwzName);
|
||||||
|
|
||||||
|
delete pwzName;
|
||||||
|
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
class Helpers
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
static
|
||||||
|
std::wstring
|
||||||
|
CreateRandomValue();
|
||||||
|
|
||||||
|
static
|
||||||
|
std::wstring
|
||||||
|
CreateRandomTempDirectory();
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
DeleteDirectory(std::wstring directory);
|
||||||
|
|
||||||
|
static
|
||||||
|
std::wstring
|
||||||
|
ReadFileContent(std::wstring file);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
// 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 "gtest/internal/gtest-port.h"
|
||||||
|
|
||||||
|
class FileManagerWrapper
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PipeOutputManager * manager;
|
||||||
|
FileManagerWrapper(PipeOutputManager* m)
|
||||||
|
: manager(m)
|
||||||
|
{
|
||||||
|
manager->Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
~FileManagerWrapper()
|
||||||
|
{
|
||||||
|
delete manager;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace PipeOutputManagerTests
|
||||||
|
{
|
||||||
|
TEST(PipeManagerOutputTest, NotifyStartupCompleteCallsDispose)
|
||||||
|
{
|
||||||
|
PCWSTR expected = L"test";
|
||||||
|
|
||||||
|
PipeOutputManager* pManager = new PipeOutputManager();
|
||||||
|
ASSERT_EQ(S_OK, pManager->Start());
|
||||||
|
|
||||||
|
pManager->NotifyStartupComplete();
|
||||||
|
|
||||||
|
// Test will fail if we didn't redirect stdout back to a file descriptor.
|
||||||
|
// This is because gtest relies on console output to know if a test succeeded or failed.
|
||||||
|
// If the output still points to a file/pipe, the test (and all other tests after it) will fail.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -9,6 +9,7 @@ int wmain(int argc, wchar_t* argv[])
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
std::srand((unsigned int)std::time(0));
|
||||||
::testing::InitGoogleTest(&argc, argv);
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
RUN_ALL_TESTS();
|
RUN_ALL_TESTS();
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <experimental/filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
#include <hashfn.h>
|
#include <hashfn.h>
|
||||||
#include <hashtable.h>
|
#include <hashtable.h>
|
||||||
|
|
@ -48,6 +50,7 @@
|
||||||
#include "requesthandler.h"
|
#include "requesthandler.h"
|
||||||
#include "resources.h"
|
#include "resources.h"
|
||||||
#include "aspnetcore_msg.h"
|
#include "aspnetcore_msg.h"
|
||||||
|
#include "Helpers.h"
|
||||||
|
|
||||||
#undef assert // Macro redefinition in IISLib.
|
#undef assert // Macro redefinition in IISLib.
|
||||||
#include "gtest\gtest.h"
|
#include "gtest\gtest.h"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
// 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 System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using IISIntegration.FunctionalTests.Utilities;
|
||||||
|
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
|
{
|
||||||
|
public class LoggingTests : IISFunctionalTestBase
|
||||||
|
{
|
||||||
|
[Theory]
|
||||||
|
[InlineData("CheckErrLogFile")]
|
||||||
|
[InlineData("CheckLogFile")]
|
||||||
|
public async Task CheckStdoutLogging(string path)
|
||||||
|
{
|
||||||
|
var deploymentParameters = Helpers.GetBaseDeploymentParameters();
|
||||||
|
deploymentParameters.PublishApplicationBeforeDeployment = true;
|
||||||
|
deploymentParameters.PreservePublishedApplicationForDebugging = true; // workaround for keeping
|
||||||
|
|
||||||
|
var deploymentResult = await DeployAsync(deploymentParameters);
|
||||||
|
|
||||||
|
Helpers.ModifyAspNetCoreSectionInWebConfig(deploymentResult, "stdoutLogEnabled", "true");
|
||||||
|
Helpers.ModifyAspNetCoreSectionInWebConfig(deploymentResult, "stdoutLogFile", @".\logs\stdout");
|
||||||
|
|
||||||
|
var response = await deploymentResult.RetryingHttpClient.GetAsync(path);
|
||||||
|
|
||||||
|
var responseText = await response.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
Assert.Equal("Hello World", responseText);
|
||||||
|
|
||||||
|
Dispose();
|
||||||
|
|
||||||
|
var folderPath = Path.Combine(deploymentResult.DeploymentResult.ContentRoot, @"logs");
|
||||||
|
|
||||||
|
var fileInDirectory = Directory.GetFiles(folderPath).Single();
|
||||||
|
Assert.NotNull(fileInDirectory);
|
||||||
|
|
||||||
|
string contents = null;
|
||||||
|
for (var i = 0; i < 20; i++)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
contents = await File.ReadAllTextAsync(fileInDirectory);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch (IOException)
|
||||||
|
{
|
||||||
|
// File in use by IISExpress, delay a bit before rereading.
|
||||||
|
}
|
||||||
|
await Task.Delay(20);
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.NotNull(contents);
|
||||||
|
|
||||||
|
// Open the log file and see if there are any contents.
|
||||||
|
Assert.Contains("TEST MESSAGE", contents);
|
||||||
|
|
||||||
|
RetryHelper.RetryOperation(
|
||||||
|
() => Directory.Delete(deploymentParameters.PublishedApplicationRootPath, true),
|
||||||
|
e => Logger.LogWarning($"Failed to delete directory : {e.Message}"),
|
||||||
|
retryCount: 3,
|
||||||
|
retryDelayMilliseconds: 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
// 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 System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using IISIntegration.FunctionalTests.Utilities;
|
||||||
|
using Xunit;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
|
{
|
||||||
|
public class StartupExceptionTests : IISFunctionalTestBase
|
||||||
|
{
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("CheckLogFile")]
|
||||||
|
[InlineData("CheckErrLogFile")]
|
||||||
|
public async Task CheckStdoutWithRandomNumber(string path)
|
||||||
|
{
|
||||||
|
var deploymentParameters = Helpers.GetBaseDeploymentParameters("StartupExceptionWebsite");
|
||||||
|
deploymentParameters.EnvironmentVariables["ASPNETCORE_INPROCESS_STARTUP_VALUE"] = path;
|
||||||
|
var randomNumberString = new Random(Guid.NewGuid().GetHashCode()).Next(10000000).ToString();
|
||||||
|
deploymentParameters.EnvironmentVariables["ASPNETCORE_INPROCESS_RANDOM_VALUE"] = randomNumberString;
|
||||||
|
|
||||||
|
var deploymentResult = await DeployAsync(deploymentParameters);
|
||||||
|
|
||||||
|
var response = await deploymentResult.RetryingHttpClient.GetAsync(path);
|
||||||
|
|
||||||
|
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
|
||||||
|
|
||||||
|
Assert.Contains(TestSink.Writes, context => context.Message.Contains($"Random number: {randomNumberString}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("CheckLargeStdErrWrites")]
|
||||||
|
[InlineData("CheckLargeStdOutWrites")]
|
||||||
|
[InlineData("CheckOversizedStdErrWrites")]
|
||||||
|
[InlineData("CheckOversizedStdOutWrites")]
|
||||||
|
public async Task CheckStdoutWithLargeWrites(string path)
|
||||||
|
{
|
||||||
|
var deploymentParameters = Helpers.GetBaseDeploymentParameters("StartupExceptionWebsite");
|
||||||
|
deploymentParameters.EnvironmentVariables["ASPNETCORE_INPROCESS_STARTUP_VALUE"] = path;
|
||||||
|
var deploymentResult = await DeployAsync(deploymentParameters);
|
||||||
|
|
||||||
|
var response = await deploymentResult.RetryingHttpClient.GetAsync(path);
|
||||||
|
|
||||||
|
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
|
||||||
|
|
||||||
|
Assert.Contains(TestSink.Writes, context => context.Message.Contains(new string('a', 4096)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -33,7 +33,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
|
|
||||||
var deploymentResult = await DeployAsync(deploymentParameters);
|
var deploymentResult = await DeployAsync(deploymentParameters);
|
||||||
|
|
||||||
ModifyAspNetCoreSectionInWebConfig(deploymentResult, "processPath", "%DotnetPath%");
|
Helpers.ModifyAspNetCoreSectionInWebConfig(deploymentResult, "processPath", "%DotnetPath%");
|
||||||
|
|
||||||
var response = await deploymentResult.RetryingHttpClient.GetAsync("HelloWorld");
|
var response = await deploymentResult.RetryingHttpClient.GetAsync("HelloWorld");
|
||||||
|
|
||||||
|
|
@ -52,7 +52,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
|
|
||||||
var deploymentResult = await DeployAsync(deploymentParameters);
|
var deploymentResult = await DeployAsync(deploymentParameters);
|
||||||
|
|
||||||
ModifyAspNetCoreSectionInWebConfig(deploymentResult, "processPath", "%DotnetPath%");
|
Helpers.ModifyAspNetCoreSectionInWebConfig(deploymentResult, "processPath", "%DotnetPath%");
|
||||||
|
|
||||||
// Request to base address and check if various parts of the body are rendered & measure the cold startup time.
|
// Request to base address and check if various parts of the body are rendered & measure the cold startup time.
|
||||||
var response = await deploymentResult.RetryingHttpClient.GetAsync("HelloWorld");
|
var response = await deploymentResult.RetryingHttpClient.GetAsync("HelloWorld");
|
||||||
|
|
@ -60,7 +60,6 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
|
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static TestMatrix TestVariants
|
public static TestMatrix TestVariants
|
||||||
=> TestMatrix.ForServers(ServerType.IISExpress)
|
=> TestMatrix.ForServers(ServerType.IISExpress)
|
||||||
.WithTfms(Tfm.NetCoreApp22)
|
.WithTfms(Tfm.NetCoreApp22)
|
||||||
|
|
@ -94,7 +93,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
Assert.Contains(TestSink.Writes, context => context.Message.Contains("Application is running inside IIS process but is not configured to use IIS server"));
|
Assert.Contains(TestSink.Writes, context => context.Message.Contains("Application is running inside IIS process but is not configured to use IIS server"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private DeploymentParameters GetBaseDeploymentParameters(string site = "InProcessWebSite")
|
// Defaults to inprocess specific deployment parameters
|
||||||
|
public static DeploymentParameters GetBaseDeploymentParameters(string site = "InProcessWebSite")
|
||||||
{
|
{
|
||||||
return new DeploymentParameters(Helpers.GetTestWebSitePath(site), ServerType.IISExpress, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64)
|
return new DeploymentParameters(Helpers.GetTestWebSitePath(site), ServerType.IISExpress, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64)
|
||||||
{
|
{
|
||||||
|
|
@ -105,16 +105,5 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
PublishApplicationBeforeDeployment = site == "InProcessWebSite",
|
PublishApplicationBeforeDeployment = site == "InProcessWebSite",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ModifyAspNetCoreSectionInWebConfig(IISDeploymentResult deploymentResult, string key, string value)
|
|
||||||
{
|
|
||||||
// modify the web.config after publish
|
|
||||||
var root = deploymentResult.DeploymentResult.ContentRoot;
|
|
||||||
var webConfigFile = $"{root}/web.config";
|
|
||||||
var config = XDocument.Load(webConfigFile);
|
|
||||||
var element = config.Descendants("aspNetCore").FirstOrDefault();
|
|
||||||
element.SetAttributeValue(key, value);
|
|
||||||
config.Save(webConfigFile);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,9 @@
|
||||||
// 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.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
||||||
using Microsoft.AspNetCore.Testing;
|
using Microsoft.AspNetCore.Testing;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
|
|
@ -16,5 +19,32 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
public static string GetInProcessTestSitesPath() => GetTestWebSitePath("InProcessWebSite");
|
public static string GetInProcessTestSitesPath() => GetTestWebSitePath("InProcessWebSite");
|
||||||
|
|
||||||
public static string GetOutOfProcessTestSitesPath() => GetTestWebSitePath("OutOfProcessWebSite");
|
public static string GetOutOfProcessTestSitesPath() => GetTestWebSitePath("OutOfProcessWebSite");
|
||||||
|
|
||||||
|
public static void ModifyAspNetCoreSectionInWebConfig(IISDeploymentResult deploymentResult, string key, string value)
|
||||||
|
=> ModifySectionInWebConfig(deploymentResult, key, value, section: "aspNetCore", 0);
|
||||||
|
|
||||||
|
public static void ModifySectionInWebConfig(IISDeploymentResult deploymentResult, string key, string value, string section, int index)
|
||||||
|
{
|
||||||
|
// modify the web.config after publish
|
||||||
|
var root = deploymentResult.DeploymentResult.ContentRoot;
|
||||||
|
var webConfigFile = $"{root}/web.config";
|
||||||
|
var config = XDocument.Load(webConfigFile);
|
||||||
|
var element = config.Descendants(section).ToList()[index];
|
||||||
|
element.SetAttributeValue(key, value);
|
||||||
|
config.Save(webConfigFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defaults to inprocess specific deployment parameters
|
||||||
|
public static DeploymentParameters GetBaseDeploymentParameters(string site = "InProcessWebSite")
|
||||||
|
{
|
||||||
|
return new DeploymentParameters(Helpers.GetTestWebSitePath(site), ServerType.IISExpress, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64)
|
||||||
|
{
|
||||||
|
TargetFramework = Tfm.NetCoreApp22,
|
||||||
|
ApplicationType = ApplicationType.Portable,
|
||||||
|
AncmVersion = AncmVersion.AspNetCoreModuleV2,
|
||||||
|
HostingModel = HostingModel.InProcess,
|
||||||
|
PublishApplicationBeforeDeployment = site == "InProcessWebSite",
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -657,7 +657,6 @@ namespace IISTestSite
|
||||||
{
|
{
|
||||||
app.Run(async context =>
|
app.Run(async context =>
|
||||||
{
|
{
|
||||||
|
|
||||||
if (context.Request.Path.StartsWithSegments("/NullBuffer"))
|
if (context.Request.Path.StartsWithSegments("/NullBuffer"))
|
||||||
{
|
{
|
||||||
await context.Response.Body.WriteAsync(null, 0, 0);
|
await context.Response.Body.WriteAsync(null, 0, 0);
|
||||||
|
|
@ -704,5 +703,27 @@ namespace IISTestSite
|
||||||
{
|
{
|
||||||
app.Run(async ctx => { await ctx.Response.WriteAsync(AppDomain.CurrentDomain.BaseDirectory); });
|
app.Run(async ctx => { await ctx.Response.WriteAsync(AppDomain.CurrentDomain.BaseDirectory); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void CheckLogFile(IApplicationBuilder app)
|
||||||
|
{
|
||||||
|
app.Run(async ctx =>
|
||||||
|
{
|
||||||
|
Console.WriteLine("TEST MESSAGE");
|
||||||
|
|
||||||
|
await ctx.Response.WriteAsync("Hello World");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CheckErrLogFile(IApplicationBuilder app)
|
||||||
|
{
|
||||||
|
app.Run(async ctx =>
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine("TEST MESSAGE");
|
||||||
|
Console.Error.Flush();
|
||||||
|
|
||||||
|
await ctx.Response.WriteAsync("Hello World");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<system.webServer>
|
<system.webServer>
|
||||||
<handlers>
|
<handlers>
|
||||||
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
|
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
|
||||||
</handlers>
|
</handlers>
|
||||||
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false" hostingModel="inprocess">
|
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="true" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false" hostingModel="inprocess">
|
||||||
<environmentVariables>
|
<environmentVariables>
|
||||||
<environmentVariable name="ASPNETCORE_INPROCESS_TESTING_VALUE" value="foobar" />
|
<environmentVariable name="ASPNETCORE_INPROCESS_TESTING_VALUE" value="foobar" />
|
||||||
<environmentVariable name="ASPNETCORE_INPROCESS_TESTING_LONG_VALUE" value="AReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNativeAReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNativeAReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNativeAReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNativeAReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNativeAReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNative" />
|
<environmentVariable name="ASPNETCORE_INPROCESS_TESTING_LONG_VALUE" value="AReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNativeAReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNativeAReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNativeAReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNativeAReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNativeAReallyLongValueThatIsGreaterThan300CharactersToForceResizeInNative" />
|
||||||
<environmentVariable name="ProgramFiles" value="foobarbaz" />
|
<environmentVariable name="ProgramFiles" value="foobarbaz" />
|
||||||
<environmentVariable name="ASPNETCORE_IIS_HTTPAUTH" value="shouldberemoved"/>
|
<environmentVariable name="ASPNETCORE_IIS_HTTPAUTH" value="shouldberemoved" />
|
||||||
</environmentVariables>
|
</environmentVariables>
|
||||||
</aspNetCore>
|
</aspNetCore>
|
||||||
</system.webServer>
|
</system.webServer>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
// 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 System;
|
||||||
|
|
||||||
|
namespace IISTestSite
|
||||||
|
{
|
||||||
|
public static class Program
|
||||||
|
{
|
||||||
|
public static void Main(string[] args)
|
||||||
|
{
|
||||||
|
var envVariable = Environment.GetEnvironmentVariable("ASPNETCORE_INPROCESS_STARTUP_VALUE");
|
||||||
|
var randomNumber = Environment.GetEnvironmentVariable("ASPNETCORE_INPROCESS_RANDOM_VALUE");
|
||||||
|
|
||||||
|
// Semicolons are appended to env variables; removing them.
|
||||||
|
if (envVariable == "CheckLargeStdOutWrites")
|
||||||
|
{
|
||||||
|
Console.WriteLine(new string('a', 4096));
|
||||||
|
}
|
||||||
|
else if (envVariable == "CheckLargeStdErrWrites")
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine(new string('a', 4096));
|
||||||
|
Console.Error.Flush();
|
||||||
|
}
|
||||||
|
else if (envVariable == "CheckLogFile")
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Random number: {randomNumber}");
|
||||||
|
}
|
||||||
|
else if (envVariable == "CheckErrLogFile")
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine($"Random number: {randomNumber}");
|
||||||
|
Console.Error.Flush();
|
||||||
|
}
|
||||||
|
else if (envVariable == "CheckOversizedStdErrWrites")
|
||||||
|
{
|
||||||
|
Console.WriteLine(new string('a', 5000));
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (envVariable == "CheckOversizedStdOutWrites")
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine(new string('a', 4096));
|
||||||
|
Console.Error.Flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
{
|
||||||
|
"iisSettings": {
|
||||||
|
"windowsAuthentication": true,
|
||||||
|
"anonymousAuthentication": true,
|
||||||
|
"iisExpress": {
|
||||||
|
"applicationUrl": "http://localhost:5762/",
|
||||||
|
"sslPort": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"profiles": {
|
||||||
|
"ANCM IIS Express": {
|
||||||
|
"commandName": "Executable",
|
||||||
|
"executablePath": "$(IISExpressPath)",
|
||||||
|
"commandLineArgs": "$(IISExpressArguments)",
|
||||||
|
"nativeDebugging": true,
|
||||||
|
"environmentVariables": {
|
||||||
|
"IIS_SITE_PATH": "$(MSBuildThisFileDirectory)",
|
||||||
|
"ANCM_PATH": "$(TargetDir)$(AncmV2Path)",
|
||||||
|
"LAUNCHER_ARGS": "$(TargetPath)",
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||||
|
"LAUNCHER_PATH": "$(DotNetPath)"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ANCM IIS": {
|
||||||
|
"commandName": "Executable",
|
||||||
|
"executablePath": "$(IISPath)",
|
||||||
|
"commandLineArgs": "$(IISArguments)",
|
||||||
|
"environmentVariables": {
|
||||||
|
"IIS_SITE_PATH": "$(MSBuildThisFileDirectory)",
|
||||||
|
"ANCM_PATH": "$(TargetDir)$(AncmV2Path)",
|
||||||
|
"LAUNCHER_ARGS": "$(TargetPath)",
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||||
|
"LAUNCHER_PATH": "$(DotNetPath)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<Import Project="..\..\..\build\testsite.props" />
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFrameworks>netcoreapp2.2</TargetFrameworks>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\src\Microsoft.AspNetCore.Server.IIS\Microsoft.AspNetCore.Server.IIS.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="$(MicrosoftAspNetCoreHostingPackageVersion)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
Loading…
Reference in New Issue