Adds support for Razor compilation at build-time

This PR adds two new tools as well as a tasks project. None of these
projects produce a package and they ship as part of
Microsoft.AspNetCore.Razor.Design. For now this is a 'fat' package that
contains all of the dependencies, but we plan to strip them out in the
future.

The support for compilation at build-time will start as **off** by
default. The immediate goal here is to get this to flow through the
build so that we can test it as part of the inner loop effort. We will
enable this feature by default once we've done more thorough testing.

Since this is mostly a code dump, I plan to address blocking and minor
feedback only. If there are design issues that are non-critical, I will
open follow up items.

The next step will be to start adding more detailed tests.
This commit is contained in:
Ryan Nowak 2017-12-13 16:14:44 -08:00
parent 18ce7f07ac
commit a3fef5eeaa
19 changed files with 515 additions and 47 deletions

View File

@ -7,6 +7,7 @@
$(RestoreSources);
https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json;
https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json;
https://dotnet.myget.org/F/msbuild/api/v3/index.json;
https://dotnet.myget.org/F/roslyn/api/v3/index.json;
https://vside.myget.org/F/vssdk/api/v3/index.json;
https://vside.myget.org/F/vsmac/api/v3/index.json

View File

@ -1,9 +1,109 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project>
<!-- Using explicit SDK imports here because the default way conflicts with the AfterBuild target -->
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk"/>
<PropertyGroup>
<Description>Razor is a markup syntax for adding server-side logic to web pages. This package contains MSBuild support for Razor.</Description>
<TargetFrameworks>net46;netstandard2.0</TargetFrameworks>
<!--
Using netcoreapp2.0 here is a workaround for https://github.com/Microsoft/msbuild/issues/2661
We need to use a P2P reference to build some other projects that need to target netcoreapp2.0
and even though we don't actually want to reference the output, MSBuild will not allow it.
-->
<TargetFramework>netstandard2.0</TargetFramework>
<!-- This project doesn't have any code, so don't include it in the .nupkg -->
<IncludeBuildOutput>false</IncludeBuildOutput>
</PropertyGroup>
<!--
Building this package is somewhat complicated because we need to Build or Publish some other projects
that have different TFM's including one with multiple TFMs.
</Project>
We then need to include the output of those projects in our output directory (where it will be used
by tests) and in the nukpg.
-->
<ItemGroup>
<!-- These are just normal MSBuild files that we want to include in the package -->
<Content Include="build\**\*.props" PackagePath="build\"/>
<Content Include="build\**\*.targets" PackagePath="build\"/>
<Content Include="buildMultiTargeting\*.props" PackagePath="buildMultiTargeting\"/>
<Content Include="buildMultiTargeting\*.targets" PackagePath="buildMultiTargeting\"/>
</ItemGroup>
<!-- This is the tasks project that needs to be included in the package. -->
<ItemGroup>
<TaskProject Include="..\Microsoft.AspNetCore.Razor.Tasks\Microsoft.AspNetCore.Razor.Tasks.csproj"/>
</ItemGroup>
<!-- These are tools that need to be included in the package. -->
<ItemGroup>
<ToolProject Include="..\Microsoft.AspNetCore.Razor.GenerateTool\Microsoft.AspNetCore.Razor.GenerateTool.csproj"/>
<ToolProject Include="..\Microsoft.AspNetCore.Razor.TagHelperTool\Microsoft.AspNetCore.Razor.TagHelperTool.csproj"/>
</ItemGroup>
<!-- Using explicit SDK imports here because the default way conflicts with the AfterBuild target -->
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
<PropertyGroup>
<GenerateNuspecDependsOn>$(GenerateNuspecDependsOn);_BuildDependencyProjects</GenerateNuspecDependsOn>
<BuildDependsOn>_BuildDependencyProjects;$(BuildDependsOn)</BuildDependsOn>
</PropertyGroup>
<Target Name="_BuildDependencyProjects">
<!--
The Microsoft.AspNetCore.Razor.Tasks package needs to support both net46 and netstandard2.0 for desktop vs
coreclr MSBuild - so we have to build it twice.
We're careful here to avoid setting properties when building the other projects. This can create problems
with concurrency.
First, build the project, then copy it to the ouput directory, then add it as packable content.
-->
<MSBuild Projects="@(TaskProject)"/>
<MSBuild
Projects="@(TaskProject)"
Properties="TargetFramework=net46"
Targets="GetTargetPath">
<Output TaskParameter="TargetOutputs" ItemName="TaskAssemblyNet46"/>
</MSBuild>
<MSBuild
Projects="@(TaskProject)"
Properties="TargetFramework=netstandard2.0"
Targets="GetTargetPath">
<Output TaskParameter="TargetOutputs" ItemName="TaskAssemblyNetStandard"/>
</MSBuild>
<Copy SourceFiles="@(TaskAssemblyNet46)" DestinationFolder="$(OutputPath)\tasks\net46\">
<Output TaskParameter="CopiedFiles" ItemName="FileWrites"/>
</Copy>
<Copy SourceFiles="@(TaskAssemblyNetStandard)" DestinationFolder="$(OutputPath)\tasks\netstandard2.0\">
<Output TaskParameter="CopiedFiles" ItemName="FileWrites"/>
</Copy>
<ItemGroup>
<None Include="@(TaskAssemblyNet46)" PackagePath="tasks\net46\" Pack="true"/>
<None Include="@(TaskAssemblyNetStandard)" PackagePath="tasks\netstandard2.0\" Pack="true"/>
</ItemGroup>
<!--
Next we need to build the netcoreapp2.0 tools. In this case we need to do a publish, because we need
all of the output to put in the package.
-->
<RemoveDir Directories="tools\"/>
<MSBuild Projects="@(ToolProject)"/>
<MSBuild
Projects="@(ToolProject)"
Properties="PublishDir=$(MSBuildProjectDirectory)\$(OutputPath)tools\"
Targets="Publish"/>
<ItemGroup>
<None Include="$(OutputPath)tools\**\*" Exclude="$(OutputPath)tools\**\*.xml;$(OutputPath)tools\**\*.pdb" PackagePath="tools\" Pack="true"/>
</ItemGroup>
</Target>
</Project>

View File

@ -1,10 +0,0 @@
<Project>
<!--
Properties supporting Razor MSBuild integration
-->
<PropertyGroup>
<RazorGenerateDependsOn></RazorGenerateDependsOn>
<RazorCompileDependsOn></RazorCompileDependsOn>
</PropertyGroup>
</Project>

View File

@ -1,11 +0,0 @@
<Project>
<!--
Targets supporting Razor MSBuild integration
-->
<Target Name="RazorGenerate" DependsOnTargets="$(RazorGenerateDependsOn)">
</Target>
<Target Name="RazorCompile" DependsOnTargets="$(RazorCompileDependsOn)">
</Target>
</Project>

View File

@ -0,0 +1,37 @@
<Project TreatAsLocalProperty="TaskFolder;TaskAssembly">
<!--
Properties and tasks supporting Razor MSBuild integration
-->
<!--
Razor defines two primary targets:
'RazorGenerate' - which updates generated code
'RazorCompile' - compiles an assembly from generated code
Use these properties to attach behavior to the corresponding target.
-->
<PropertyGroup>
<RazorGenerateDependsOn>_RazorResolveTagHelpers;RazorCoreGenerate</RazorGenerateDependsOn>
<RazorCompileDependsOn>_RazorResolveTagHelpers;RazorCoreGenerate;RazorCoreCompile</RazorCompileDependsOn>
</PropertyGroup>
<!--
Razor also attaches itself by default to some of the standard .NET targets. Uses these properties to
configure this behaviour.
-->
<PropertyGroup>
<RazorCompileOnBuild Condition="'$(RazorCompileOnBuild)'==''">false</RazorCompileOnBuild>
</PropertyGroup>
<PropertyGroup>
<!-- Override this to hijack the tasks and targets. Used by tests. -->
<_RazorMSBuildRoot Condition="'$(_RazorMSBuildRoot)'==''">$(MSBuildThisFileDirectory)..\..\</_RazorMSBuildRoot>
<TaskFolder Condition=" '$(MSBuildRuntimeType)' == 'Core' ">netstandard2.0</TaskFolder>
<TaskFolder Condition=" '$(MSBuildRuntimeType)' != 'Core' ">net46</TaskFolder>
<TaskAssembly>$(_RazorMSBuildRoot)\tasks\$(TaskFolder)\Microsoft.AspNetCore.Razor.Tasks.dll</TaskAssembly>
</PropertyGroup>
<UsingTask TaskName="Microsoft.AspNetCore.Razor.Tasks.RazorGenerate" AssemblyFile="$(TaskAssembly)" />
<UsingTask TaskName="Microsoft.AspNetCore.Razor.Tasks.RazorTagHelper" AssemblyFile="$(TaskAssembly)" />
</Project>

View File

@ -0,0 +1,238 @@
<Project>
<!--
Targets supporting Razor MSBuild integration
-->
<Target Name="RazorGenerate" DependsOnTargets="$(RazorGenerateDependsOn)">
</Target>
<Target Name="RazorCompile" DependsOnTargets="$(RazorCompileDependsOn)">
</Target>
<PropertyGroup Condition="'$(RazorCompileOnBuild)'=='true'">
<BuildDependsOn>$(BuildDependsOn);RazorCompile</BuildDependsOn>
</PropertyGroup>
<!--
Default values for properties that affect Razor MSBuild behavior.
-->
<PropertyGroup>
<!-- Output directory used for generated files -->
<RazorGenerateOutputPath Condition="'$(RazorGenerateOutputPath)'==''">$(IntermediateOutputPath)Razor\</RazorGenerateOutputPath>
<!-- File name (without extension) of the assembly produced by Razor -->
<RazorTargetName Condition="'$(RazorTargetName)'==''">$(TargetName).PrecompiledViews</RazorTargetName>
</PropertyGroup>
<!-- Implementation details here... -->
<PropertyGroup>
<!-- Used for tag helper discovery -->
<_RazorTagHelperInputCache>$(IntermediateOutputPath)$(TargetName).TagHelpers.input.cache</_RazorTagHelperInputCache>
<_RazorTagHelperOutputCache>$(IntermediateOutputPath)$(TargetName).TagHelpers.output.cache</_RazorTagHelperOutputCache>
<!-- Used to creating the final compiled Razor dll -->
<_RazorIntermediateAssembly>$(IntermediateOutputPath)$(RazorTargetName).dll</_RazorIntermediateAssembly>
<_RazorIntermediatePdb>$(IntermediateOutputPath)$(RazorTargetName).pdb</_RazorIntermediatePdb>
<!-- Used to locate our tools -->
<_RazorGenerateToolAssembly>$(_RazorMSBuildRoot)tools\Microsoft.AspNetCore.Razor.GenerateTool.dll</_RazorGenerateToolAssembly>
<_RazorTagHelperToolAssembly>$(_RazorMSBuildRoot)tools\Microsoft.AspNetCore.Razor.TagHelperTool.dll</_RazorTagHelperToolAssembly>
</PropertyGroup>
<!--
Gathers input assemblies for Tag Helper discovery and compilation. Add items to @(ReferencePath)
-->
<Target
Name="RazorResolveAssemblyReferences"
DependsOnTargets="ResolveReferences">
<ItemGroup>
<RazorReferencePath Include="@(ReferencePath)"/>
<RazorReferencePath Include="$([System.IO.Path]::GetFullPath('$(IntermediateOutputPath)$(TargetName)$(TargetExt)'))"/>
</ItemGroup>
</Target>
<Target
Name="_RazorResolveTagHelpers"
DependsOnTargets="CoreCompile;RazorResolveAssemblyReferences"
Inputs="$(MSBuildAllProjects);@(RazorReferencePath)"
Outputs="$(_RazorTagHelperInputCache)">
<!--
We're manipulating our output directly here because we want to separate the actual up-to-date check
of RazorCoreGenerate from the output of this target. Many times the set of tag helpers doesn't change
so we don't need to regenerate the code.
-->
<Touch
Files="$(_RazorTagHelperInputCache)"
AlwaysCreate="true">
<Output
TaskParameter="TouchedFiles"
ItemName="FileWrites" />
</Touch>
<RazorTagHelper
Debug="$(_RazorDebugTagHelperTask)"
DebugTool="$(_RazorDebugTagHelperTool)"
ToolAssembly="$(_RazorTagHelperToolAssembly)"
Assemblies="@(RazorReferencePath)"
TagHelperManifest="$(_RazorTagHelperOutputCache)">
<Output
TaskParameter="TagHelperManifest"
ItemName="FileWrites"/>
</RazorTagHelper>
</Target>
<Target Name="_RazorResolveSourceFiles">
<ItemGroup>
<RazorCompile Include="@(Content)" Condition="'%(Content.Extension)'=='.cshtml'" />
<_RazorGenerated Include="@(RazorCompile->'$(RazorGenerateOutputPath)%(RelativeDir)%(Filename).cs')">
<Source>%(Identity)</Source>
</_RazorGenerated>
</ItemGroup>
</Target>
<Target
Name="RazorCoreGenerate"
DependsOnTargets="_RazorResolveSourceFiles;_RazorResolveTagHelpers"
Inputs="$(MSBuildAllProjects);@(RazorCompile);$(_RazorTagHelperOutputCache)"
Outputs="@(_RazorGenerated)">
<RemoveDir
Directories="$(RazorGenerateOutputPath)"
Condition = "Exists('$(RazorGenerateOutputPath)')"/>
<MakeDir
Directories="%(_RazorGenerated.RelativeDir)"
Condition="!Exists('%(_RazorGenerated.RelativeDir)')" />
<RazorGenerate
Debug="$(_RazorDebugGenerateCodeTask)"
DebugTool="$(_RazorDebugGenerateCodeTool)"
ToolAssembly="$(_RazorGenerateToolAssembly)"
Sources="@(RazorCompile)"
ProjectRoot="$(MSBuildProjectDirectory)"
TagHelperManifest="$(_RazorTagHelperOutputCache)"
OutputPath="$(RazorGenerateOutputPath)" />
<ItemGroup>
<FileWrites Include="@(_RazorGenerated)" />
</ItemGroup>
</Target>
<!--
What follows here was copied and modified from the XamlPreCompile target in
Microsoft.CSharp.CurrentVersion.targets
The XamlPreCompile target must remain identical to
the CoreCompile target in Microsoft.CSharp.Core.targets.
Any updates to one must be made to the other.
-->
<Target
Name="RazorCoreCompile"
Inputs="$(MSBuildAllProjects);
@(_RazorGenerated);
@(_CoreCompileResourceInputs);
$(ApplicationIcon);
$(AssemblyOriginatorKeyFile);
@(RazorReferencePath);"
Outputs="$(_RazorIntermediateAssembly)"
Returns=""
DependsOnTargets="_RazorResolveTagHelpers;RazorCoreGenerate">
<!-- These two compiler warnings are raised when a reference is bound to a different version
than specified in the assembly reference version number. MSBuild raises the same warning in this case,
so the compiler warning would be redundant. -->
<PropertyGroup Condition="('$(TargetFrameworkVersion)' != 'v1.0') and ('$(TargetFrameworkVersion)' != 'v1.1')">
<NoWarn>$(NoWarn);1701;1702</NoWarn>
</PropertyGroup>
<PropertyGroup>
<!-- To match historical behavior, when inside VS11+ disable the warning from csc.exe indicating that no sources were passed in-->
<NoWarn Condition=" '$(BuildingInsideVisualStudio)' == 'true' and '$(VisualStudioVersion)' != '' and '$(VisualStudioVersion)' > '10.0' ">$(NoWarn);2008</NoWarn>
</PropertyGroup>
<ItemGroup Condition="'$(TargetingClr2Framework)'=='true'">
<ReferencePath>
<EmbedInteropTypes/>
</ReferencePath>
</ItemGroup>
<PropertyGroup>
<!-- If the user has specified AppConfigForCompiler, we'll use it. If they have not, but they set UseAppConfigForCompiler,
then we'll use AppConfig -->
<AppConfigForCompiler Condition="'$(AppConfigForCompiler)' == '' and '$(UseAppConfigForCompiler)' == 'true'">$(AppConfig)</AppConfigForCompiler>
</PropertyGroup>
<!-- Prefer32Bit was introduced in .NET 4.5. Set it to false if we are targeting 4.0 -->
<PropertyGroup Condition="('$(TargetFrameworkVersion)' == 'v4.0')">
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(UseSharedCompilation)' == ''">
<UseSharedCompilation>true</UseSharedCompilation>
</PropertyGroup>
<Csc
AllowUnsafeBlocks="$(AllowUnsafeBlocks)"
ApplicationConfiguration="$(AppConfigForCompiler)"
BaseAddress="$(BaseAddress)"
CheckForOverflowUnderflow="$(CheckForOverflowUnderflow)"
CodePage="$(CodePage)"
DebugType="$(DebugType)"
DefineConstants="$(DefineConstants)"
DelaySign="$(DelaySign)"
DisabledWarnings="$(NoWarn)"
EmitDebugInformation="$(DebugSymbols)"
EnvironmentVariables="$(CscEnvironment)"
ErrorEndLocation="$(ErrorEndLocation)"
ErrorLog="$(ErrorLog)"
ErrorReport="$(ErrorReport)"
FileAlignment="$(FileAlignment)"
GenerateFullPaths="$(GenerateFullPaths)"
HighEntropyVA="$(HighEntropyVA)"
KeyContainer="$(KeyContainerName)"
KeyFile="$(KeyOriginatorFile)"
LangVersion="$(LangVersion)"
NoConfig="true"
NoLogo="$(NoLogo)"
NoStandardLib="$(NoCompilerStandardLib)"
NoWin32Manifest="$(NoWin32Manifest)"
Optimize="$(Optimize)"
OutputAssembly="$(_RazorIntermediateAssembly)"
PdbFile="$(_RazorIntermediatePdb)"
Platform="$(PlatformTarget)"
Prefer32Bit="$(Prefer32Bit)"
PreferredUILang="$(PreferredUILang)"
References="@(RazorReferencePath)"
ReportAnalyzer="$(ReportAnalyzer)"
ResponseFiles="$(CompilerResponseFile)"
Sources="@(_RazorGenerated)"
SubsystemVersion="$(SubsystemVersion)"
TargetType="Library"
ToolExe="$(CscToolExe)"
ToolPath="$(CscToolPath)"
TreatWarningsAsErrors="$(TreatWarningsAsErrors)"
UseHostCompilerIfAvailable="$(UseHostCompilerIfAvailable)"
UseSharedCompilation="$(UseSharedCompilation)"
Utf8Output="$(Utf8Output)"
VsSessionGuid="$(VsSessionGuid)"
WarningLevel="$(WarningLevel)"
WarningsAsErrors="$(WarningsAsErrors)"
WarningsNotAsErrors="$(WarningsNotAsErrors)"
Win32Icon="$(ApplicationIcon)"
Win32Manifest="$(Win32Manifest)"
Win32Resource="$(Win32Resource)">
<Output
TaskParameter="OutputAssembly"
ItemName="FileWrites" />
</Csc>
<!-- Output the PDB and COPY of things to FileWrites -->
<Message Importance="High" Text="$(_RazorIntermediateAssembly) -> $(OutDir)$(RazorTargetName)" />
<Copy
SourceFiles="$(_RazorIntermediateAssembly)"
DestinationFolder="$(OutDir)"
SkipUnchangedFiles="true"/>
</Target>
</Project>

View File

@ -1,3 +1,3 @@
<Project>
<Import Project="..\build\Microsoft.AspNetCore.Razor.Design.props" />
<Import Project="..\build\netstandard2.0\Microsoft.AspNetCore.Razor.Design.props" />
</Project>

View File

@ -1,3 +1,3 @@
<Project>
<Import Project="..\build\Microsoft.AspNetCore.Razor.Design.targets" />
<Import Project="..\build\netstandard2.0\Microsoft.AspNetCore.Razor.Design.targets" />
</Project>

View File

@ -114,7 +114,7 @@ namespace Microsoft.AspNetCore.Razor.GenerateTool
Parallel.For(0, outputs.Length, new ParallelOptions() { MaxDegreeOfParallelism = 4 }, i =>
{
var source = sources[i];
var csharpDocument = templateEngine.GenerateCode(source.ViewEnginePath);
outputs[i] = new OutputItem(source, csharpDocument);
});

View File

@ -1,6 +1,7 @@
// 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.Text;
namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
@ -17,6 +18,17 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
}
}
public static void FileExists(MSBuildResult result, string filePath)
{
NotNull(result);
NotNull(filePath);
if (!File.Exists(Path.Combine(result.Project.DirectoryPath, filePath)))
{
throw new FileMissingException(result, filePath);
}
}
private class BuildFailedException : Xunit.Sdk.XunitException
{
public BuildFailedException(MSBuildResult result)
@ -42,5 +54,36 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
}
}
}
private class FileMissingException : Xunit.Sdk.XunitException
{
public FileMissingException(MSBuildResult result, string filePath)
{
Result = result;
FilePath = filePath;
}
public string FilePath { get; }
public MSBuildResult Result { get; }
public override string Message
{
get
{
var message = new StringBuilder();
message.Append($"File: '{FilePath}' was not found.");
message.Append(Result.FileName);
message.Append(" ");
message.Append(Result.Arguments);
message.AppendLine();
message.AppendLine();
message.Append(Result.Output);
return message.ToString();
;
}
}
}
}
}

View File

@ -12,9 +12,11 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
[InitializeTestProject("SimpleMvc")]
public async Task CleanProject_RunBuild()
{
var result = await DotnetMSBuild("Restore;Build"); // Equivalent to dotnet build
var result = await DotnetMSBuild("Restore;Build", "/p:RazorCompileOnBuild=true");
Assert.BuildPassed(result);
Assert.FileExists(result, @"bin/Debug/netcoreapp2.0/SimpleMvc.dll");
Assert.FileExists(result, @"bin/Debug/netcoreapp2.0/SimpleMvc.PrecompiledViews.dll");
}
}
}

View File

@ -47,9 +47,10 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
#endif
}
internal Task<MSBuildResult> DotnetMSBuild(string target)
internal Task<MSBuildResult> DotnetMSBuild(string target, string args = null, bool debug = false)
{
return MSBuildProcessManager.RunProcessAsync($"/t:{target}", Project.DirectoryPath);
var timeout = debug ? (TimeSpan?)Timeout.InfiniteTimeSpan : null;
return MSBuildProcessManager.RunProcessAsync(Project, $"/t:{target} {args}", timeout);
}
}
}

View File

@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
{
internal static class MSBuildProcessManager
{
public static Task<MSBuildResult> RunProcessAsync(string arguments, string workingDirectory, TimeSpan? timeout = null)
public static Task<MSBuildResult> RunProcessAsync(ProjectDirectory project, string arguments, TimeSpan? timeout = null)
{
timeout = timeout ?? TimeSpan.FromSeconds(30);
@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
{
FileName = "dotnet",
Arguments = "msbuild " + arguments,
WorkingDirectory = workingDirectory,
WorkingDirectory = project.DirectoryPath,
UseShellExecute = false,
RedirectStandardError = true,
RedirectStandardOutput = true,
@ -64,7 +64,7 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
void Process_Exited(object sender, EventArgs e)
{
var result = new MSBuildResult(process.StartInfo.FileName, process.StartInfo.Arguments, process.ExitCode, output.ToString());
var result = new MSBuildResult(project, process.StartInfo.FileName, process.StartInfo.Arguments, process.ExitCode, output.ToString());
completionSource.SetResult(result);
}

View File

@ -5,20 +5,23 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
{
internal class MSBuildResult
{
public MSBuildResult(string fileName, string arguments, int exitCode, string output)
public MSBuildResult(ProjectDirectory project, string fileName, string arguments, int exitCode, string output)
{
Project = project;
FileName = fileName;
Arguments = arguments;
ExitCode = exitCode;
Output = output;
}
public ProjectDirectory Project { get; }
public string Arguments { get; }
public string FileName { get; }
public int ExitCode { get; }
public string Output { get; }
}
}

View File

@ -37,10 +37,8 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
CopyDirectory(new DirectoryInfo(projectRoot), new DirectoryInfo(destinationPath));
foreach (var project in Directory.EnumerateFiles(destinationPath, "*.csproj"))
{
RewriteCsproj(projectRoot, project);
}
CreateDirectoryProps(projectRoot, destinationPath);
CreateDirectoryTargets(destinationPath);
return new ProjectDirectory(destinationPath);
}
@ -71,13 +69,35 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
}
}
void RewriteCsproj(string originalProjectRoot, string filePath)
void CreateDirectoryProps(string originalProjectRoot, string projectRoot)
{
// We need to replace $(OriginalProjectRoot) with the path to the original directory
// that way relative references will resolve.
var text = File.ReadAllText(filePath);
text = text.Replace("$(OriginalProjectRoot)", originalProjectRoot);
File.WriteAllText(filePath, text);
#if DEBUG
var configuration = "Debug";
#elif RELEASE
var configuration = "Release";
#else
#error Unknown Configuration
#endif
var text = $@"
<Project>
<PropertyGroup>
<OriginalProjectRoot>{originalProjectRoot}</OriginalProjectRoot>
<_RazorMSBuildRoot>$(OriginalProjectRoot)\..\..\..\src\Microsoft.AspNetCore.Razor.Design\bin\{configuration}\netstandard2.0\</_RazorMSBuildRoot>
</PropertyGroup>
<Import Project=""$(OriginalProjectRoot)\..\..\..\src\Microsoft.AspNetCore.Razor.Design\build\netstandard2.0\Microsoft.AspNetCore.Razor.Design.props""/>
</Project>
";
File.WriteAllText(Path.Combine(projectRoot, "Directory.Build.props"), text);
}
void CreateDirectoryTargets(string projectRoot)
{
var text = $@"
<Project>
<Import Project=""$(OriginalProjectRoot)\..\..\..\src\Microsoft.AspNetCore.Razor.Design\build\netstandard2.0\Microsoft.AspNetCore.Razor.Design.targets""/>
</Project>
";
File.WriteAllText(Path.Combine(projectRoot, "Directory.Build.targets"), text);
}
}

View File

@ -1,9 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>
<!--
There's not much value in multi-targeting here, this doesn't run much .NET code, it tests MSBuild.
This is also a partial workaround for https://github.com/Microsoft/msbuild/issues/2661 - this project
has netcoreapp2.0 dependencies that need to be built first.
-->
<TargetFramework>netcoreapp2.0</TargetFramework>
<PreserveCompilationContext>true</PreserveCompilationContext>
<DefaultItemExcludes>$(DefaultItemExcludes);TestFiles\**</DefaultItemExcludes>
</PropertyGroup>
<ItemGroup>
@ -18,4 +23,11 @@
<PackageReference Include="xunit" Version="$(XunitPackageVersion)" />
</ItemGroup>
<ItemGroup>
<!-- We don't need anything in this assembly, we just want to make sure it's built -->
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Razor.Design\Microsoft.AspNetCore.Razor.Design.csproj">
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
</ItemGroup>
</Project>

View File

@ -1,6 +1,9 @@
// 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.Threading.Tasks;
using Microsoft.AspNetCore.Html;
namespace Microsoft.AspNetCore.Mvc.Razor
{
public abstract class RazorPage : RazorPageBase
@ -16,5 +19,30 @@ namespace Microsoft.AspNetCore.Mvc.Razor
public override void EnsureRenderedBodyOrSections()
{
}
protected virtual IHtmlContent RenderBody()
{
return null;
}
public HtmlString RenderSection(string name)
{
return null;
}
public HtmlString RenderSection(string name, bool required)
{
return null;
}
public Task<HtmlString> RenderSectionAsync(string name)
{
return null;
}
public Task<HtmlString> RenderSectionAsync(string name, bool required)
{
return null;
}
}
}

View File

@ -5,6 +5,9 @@ namespace SimpleMvc
{
public static void Main(string[] args)
{
// Just make sure we have a reference to the MvcShim
var t = typeof(Microsoft.AspNetCore.Mvc.IActionResult);
System.Console.WriteLine(t.FullName);
}
}
}

View File

@ -4,6 +4,7 @@
</PropertyGroup>
<ItemGroup>
<!-- In test scenarios $(OriginalProjectRoot) is defined in a generated Directory.Build.props file -->
<ProjectReference Include="$(OriginalProjectRoot)\..\..\Microsoft.AspNetCore.Razor.Test.MvcShim\Microsoft.AspNetCore.Razor.Test.MvcShim.csproj"/>
<ProjectReference Include="$(OriginalProjectRoot)\..\..\..\src\Microsoft.AspNetCore.Razor.Runtime\Microsoft.AspNetCore.Razor.Runtime.csproj"/>
</ItemGroup>