Implement a .Design package and some testing for MSBuild
This is the first step in adding support for Razor compilation at build time. Additional steps will complete this by adding tag helper discovery, code generation and finally a call to CsC. I want to get this in now to get the package into the build system and to lay down the general infrastructure for testing. --- The strategy for testing here is to use checked in projects that have everything Razor needs to compile code. We already have shims for the APIs Razor uses by default in this repo and I'm using them in the project. The test infrastructure creates a temporary directory, copies the project, and fixes up a few small things to cooperate with outputs we've already built so that the test can use the new versions of Razor bits built from this repo. We can then call various MSBuild targets and verify the files on disk. I envision tests that verify incrementalism as well as the basic E2E. We will test the E2E in general in other places, since it's part of the new default experience. This repo will test things at a higher level of detail, but in slightly artifical scenarios.
This commit is contained in:
parent
1c9c05b64d
commit
1962989ffc
22
Razor.sln
22
Razor.sln
|
|
@ -78,6 +78,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.Mac.
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.Mac.LanguageServices.Razor.Test", "test\Microsoft.VisualStudio.Mac.LanguageServices.Razor.Test\Microsoft.VisualStudio.Mac.LanguageServices.Razor.Test.csproj", "{B8A3E4CA-D54A-441F-A3BF-E00F060CA042}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.Razor.Design", "src\Microsoft.AspNetCore.Razor.Design\Microsoft.AspNetCore.Razor.Design.csproj", "{5257B25D-330A-4DCF-ACED-B4709CFBF916}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.Razor.Design.Test", "test\Microsoft.AspNetCore.Razor.Design.Test\Microsoft.AspNetCore.Razor.Design.Test.csproj", "{1D90F276-E1CA-4FDF-A173-EB889E7D3150}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -316,6 +320,22 @@ Global
|
|||
{B8A3E4CA-D54A-441F-A3BF-E00F060CA042}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B8A3E4CA-D54A-441F-A3BF-E00F060CA042}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B8A3E4CA-D54A-441F-A3BF-E00F060CA042}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
|
||||
{5257B25D-330A-4DCF-ACED-B4709CFBF916}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5257B25D-330A-4DCF-ACED-B4709CFBF916}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5257B25D-330A-4DCF-ACED-B4709CFBF916}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5257B25D-330A-4DCF-ACED-B4709CFBF916}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5257B25D-330A-4DCF-ACED-B4709CFBF916}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5257B25D-330A-4DCF-ACED-B4709CFBF916}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5257B25D-330A-4DCF-ACED-B4709CFBF916}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5257B25D-330A-4DCF-ACED-B4709CFBF916}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
|
||||
{1D90F276-E1CA-4FDF-A173-EB889E7D3150}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1D90F276-E1CA-4FDF-A173-EB889E7D3150}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1D90F276-E1CA-4FDF-A173-EB889E7D3150}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1D90F276-E1CA-4FDF-A173-EB889E7D3150}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1D90F276-E1CA-4FDF-A173-EB889E7D3150}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1D90F276-E1CA-4FDF-A173-EB889E7D3150}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1D90F276-E1CA-4FDF-A173-EB889E7D3150}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1D90F276-E1CA-4FDF-A173-EB889E7D3150}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -350,6 +370,8 @@ Global
|
|||
{FAF9986F-E086-4513-9D52-F7BF5FFCF31D} = {C0CC1E1F-1559-44DE-93A8-63259CEA2AAB}
|
||||
{95B18DEE-8B45-4CF0-B9F8-CCBAF3B5251A} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
|
||||
{B8A3E4CA-D54A-441F-A3BF-E00F060CA042} = {92463391-81BE-462B-AC3C-78C6C760741F}
|
||||
{5257B25D-330A-4DCF-ACED-B4709CFBF916} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
|
||||
{1D90F276-E1CA-4FDF-A173-EB889E7D3150} = {92463391-81BE-462B-AC3C-78C6C760741F}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {0035341D-175A-4D05-95E6-F1C2785A1E26}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
<Project 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>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<Project>
|
||||
<!--
|
||||
Properties supporting Razor MSBuild integration
|
||||
-->
|
||||
|
||||
<PropertyGroup>
|
||||
<RazorGenerateDependsOn></RazorGenerateDependsOn>
|
||||
<RazorCompileDependsOn></RazorCompileDependsOn>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<Project>
|
||||
<!--
|
||||
Targets supporting Razor MSBuild integration
|
||||
-->
|
||||
|
||||
<Target Name="RazorGenerate" DependsOnTargets="$(RazorGenerateDependsOn)">
|
||||
</Target>
|
||||
|
||||
<Target Name="RazorCompile" DependsOnTargets="$(RazorCompileDependsOn)">
|
||||
</Target>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<Project>
|
||||
<Import Project="..\build\Microsoft.AspNetCore.Razor.Design.props" />
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<Project>
|
||||
<Import Project="..\build\Microsoft.AspNetCore.Razor.Design.targets" />
|
||||
</Project>
|
||||
|
|
@ -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.Text;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||
{
|
||||
internal class Assert : Xunit.Assert
|
||||
{
|
||||
public static void BuildPassed(MSBuildResult result)
|
||||
{
|
||||
NotNull(result);
|
||||
|
||||
if (result.ExitCode != 0)
|
||||
{
|
||||
throw new BuildFailedException(result);
|
||||
}
|
||||
}
|
||||
|
||||
private class BuildFailedException : Xunit.Sdk.XunitException
|
||||
{
|
||||
public BuildFailedException(MSBuildResult result)
|
||||
{
|
||||
Result = result;
|
||||
}
|
||||
|
||||
public MSBuildResult Result { get; }
|
||||
|
||||
public override string Message
|
||||
{
|
||||
get
|
||||
{
|
||||
var message = new StringBuilder();
|
||||
message.Append("Build failed: ");
|
||||
message.Append(Result.FileName);
|
||||
message.Append(" ");
|
||||
message.Append(Result.Arguments);
|
||||
message.AppendLine();
|
||||
message.AppendLine();
|
||||
message.Append(Result.Output);
|
||||
return message.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// 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 Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||
{
|
||||
public class CleanProjectIntegrationTest : MSBuildIntegrationTestBase
|
||||
{
|
||||
[Fact]
|
||||
[InitializeTestProject("SimpleMvc")]
|
||||
public async Task CleanProject_RunBuild()
|
||||
{
|
||||
var result = await DotnetMSBuild("Restore;Build"); // Equivalent to dotnet build
|
||||
|
||||
Assert.BuildPassed(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
// 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.Reflection;
|
||||
using Xunit.Sdk;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||
{
|
||||
public class InitializeTestProjectAttribute : BeforeAfterTestAttribute
|
||||
{
|
||||
private readonly string _projectName;
|
||||
|
||||
public InitializeTestProjectAttribute(string projectName)
|
||||
{
|
||||
_projectName = projectName;
|
||||
}
|
||||
|
||||
public override void Before(MethodInfo methodUnderTest)
|
||||
{
|
||||
if (!typeof(MSBuildIntegrationTestBase).GetTypeInfo().IsAssignableFrom(methodUnderTest.DeclaringType.GetTypeInfo()))
|
||||
{
|
||||
throw new InvalidOperationException($"This should be used on a class derived from {typeof(MSBuildIntegrationTestBase)}");
|
||||
}
|
||||
|
||||
MSBuildIntegrationTestBase.Project = ProjectDirectory.Create(_projectName);
|
||||
}
|
||||
|
||||
public override void After(MethodInfo methodUnderTest)
|
||||
{
|
||||
if (!typeof(MSBuildIntegrationTestBase).GetTypeInfo().IsAssignableFrom(methodUnderTest.DeclaringType.GetTypeInfo()))
|
||||
{
|
||||
throw new InvalidOperationException($"This should be used on a class derived from {typeof(MSBuildIntegrationTestBase)}");
|
||||
}
|
||||
|
||||
MSBuildIntegrationTestBase.Project.Dispose();
|
||||
MSBuildIntegrationTestBase.Project = null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
// 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.Diagnostics;
|
||||
#if NET461
|
||||
using System.Runtime.Remoting;
|
||||
using System.Runtime.Remoting.Messaging;
|
||||
#else
|
||||
using System.Threading;
|
||||
#endif
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||
{
|
||||
public abstract class MSBuildIntegrationTestBase
|
||||
{
|
||||
#if NET461
|
||||
#elif NETCOREAPP2_0 || NETCOREAPP2_1
|
||||
private static readonly AsyncLocal<ProjectDirectory> _project = new AsyncLocal<ProjectDirectory>();
|
||||
#else
|
||||
#error TFM not supported
|
||||
#endif
|
||||
|
||||
protected MSBuildIntegrationTestBase()
|
||||
{
|
||||
}
|
||||
|
||||
// Used by the test framework to set the project that we're working with
|
||||
internal static ProjectDirectory Project
|
||||
{
|
||||
#if NET461
|
||||
get
|
||||
{
|
||||
var handle = (ObjectHandle)CallContext.LogicalGetData("MSBuildIntegrationTestBase_Project");
|
||||
return (ProjectDirectory)handle.Unwrap();
|
||||
}
|
||||
set
|
||||
{
|
||||
CallContext.LogicalSetData("MSBuildIntegrationTestBase_Project", new ObjectHandle(value));
|
||||
}
|
||||
#elif NETCOREAPP2_0 || NETCOREAPP2_1
|
||||
get { return _project.Value; }
|
||||
set { _project.Value = value; }
|
||||
#else
|
||||
#error TFM not supported
|
||||
#endif
|
||||
}
|
||||
|
||||
internal Task<MSBuildResult> DotnetMSBuild(string target)
|
||||
{
|
||||
return MSBuildProcessManager.RunProcessAsync($"/t:{target}", Project.DirectoryPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
// 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.Diagnostics;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||
{
|
||||
internal static class MSBuildProcessManager
|
||||
{
|
||||
public static Task<MSBuildResult> RunProcessAsync(string arguments, string workingDirectory, TimeSpan? timeout = null)
|
||||
{
|
||||
timeout = timeout ?? TimeSpan.FromSeconds(30);
|
||||
|
||||
var process = new Process()
|
||||
{
|
||||
StartInfo = new ProcessStartInfo()
|
||||
{
|
||||
FileName = "dotnet",
|
||||
Arguments = "msbuild " + arguments,
|
||||
WorkingDirectory = workingDirectory,
|
||||
UseShellExecute = false,
|
||||
RedirectStandardError = true,
|
||||
RedirectStandardOutput = true,
|
||||
},
|
||||
EnableRaisingEvents = true,
|
||||
};
|
||||
|
||||
var completionSource = new TaskCompletionSource<MSBuildResult>();
|
||||
var output = new StringBuilder();
|
||||
|
||||
process.Exited += Process_Exited;
|
||||
process.ErrorDataReceived += Process_ErrorDataReceived;
|
||||
process.OutputDataReceived += Process_OutputDataReceived;
|
||||
|
||||
process.Start();
|
||||
process.BeginErrorReadLine();
|
||||
process.BeginOutputReadLine();
|
||||
|
||||
var timeoutTask = Task.Delay(timeout.Value).ContinueWith((t) =>
|
||||
{
|
||||
// Don't timeout during debug sessions
|
||||
while (Debugger.IsAttached)
|
||||
{
|
||||
Thread.Sleep(TimeSpan.FromSeconds(1));
|
||||
}
|
||||
|
||||
if (process.HasExited)
|
||||
{
|
||||
// This will happen on success, the 'real' task has already completed so this value will
|
||||
// never be visible.
|
||||
return (MSBuildResult)null;
|
||||
}
|
||||
|
||||
// This is a timeout.
|
||||
process.Kill();
|
||||
throw new TimeoutException($"command '${process.StartInfo.FileName} {process.StartInfo.Arguments}' timed out after {timeout}.");
|
||||
});
|
||||
|
||||
return Task.WhenAny<MSBuildResult>(completionSource.Task, timeoutTask).Unwrap();
|
||||
|
||||
void Process_Exited(object sender, EventArgs e)
|
||||
{
|
||||
var result = new MSBuildResult(process.StartInfo.FileName, process.StartInfo.Arguments, process.ExitCode, output.ToString());
|
||||
completionSource.SetResult(result);
|
||||
}
|
||||
|
||||
void Process_ErrorDataReceived(object sender, DataReceivedEventArgs e)
|
||||
{
|
||||
output.AppendLine(e.Data);
|
||||
}
|
||||
|
||||
void Process_OutputDataReceived(object sender, DataReceivedEventArgs e)
|
||||
{
|
||||
output.AppendLine(e.Data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// 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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||
{
|
||||
internal class MSBuildResult
|
||||
{
|
||||
public MSBuildResult(string fileName, string arguments, int exitCode, string output)
|
||||
{
|
||||
FileName = fileName;
|
||||
Arguments = arguments;
|
||||
ExitCode = exitCode;
|
||||
Output = output;
|
||||
}
|
||||
|
||||
public string Arguments { get; }
|
||||
|
||||
public string FileName { get; }
|
||||
|
||||
public int ExitCode { get; }
|
||||
|
||||
public string Output { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
// 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.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Microsoft.AspNetCore.Testing;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
|
||||
{
|
||||
internal class ProjectDirectory : IDisposable
|
||||
{
|
||||
public static ProjectDirectory Create(string projectName)
|
||||
{
|
||||
var destinationPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
|
||||
Directory.CreateDirectory(destinationPath);
|
||||
|
||||
try
|
||||
{
|
||||
if (Directory.EnumerateFiles(destinationPath).Any())
|
||||
{
|
||||
throw new InvalidOperationException($"{destinationPath} should be empty");
|
||||
}
|
||||
|
||||
var solutionRoot = TestPathUtilities.GetSolutionRootDirectory("Razor");
|
||||
if (solutionRoot == null)
|
||||
{
|
||||
throw new InvalidOperationException("Could not find solution root.");
|
||||
}
|
||||
|
||||
var projectRoot = Path.Combine(solutionRoot, "test", "testapps", projectName);
|
||||
if (!Directory.Exists(projectRoot))
|
||||
{
|
||||
throw new InvalidOperationException($"Could not find project at '{projectRoot}'");
|
||||
}
|
||||
|
||||
CopyDirectory(new DirectoryInfo(projectRoot), new DirectoryInfo(destinationPath));
|
||||
|
||||
foreach (var project in Directory.EnumerateFiles(destinationPath, "*.csproj"))
|
||||
{
|
||||
RewriteCsproj(projectRoot, project);
|
||||
}
|
||||
|
||||
return new ProjectDirectory(destinationPath);
|
||||
}
|
||||
catch
|
||||
{
|
||||
CleanupDirectory(destinationPath);
|
||||
throw;
|
||||
}
|
||||
|
||||
void CopyDirectory(DirectoryInfo source, DirectoryInfo destination)
|
||||
{
|
||||
foreach (var directory in source.EnumerateDirectories())
|
||||
{
|
||||
if (directory.Name == "bin" || directory.Name == "obj")
|
||||
{
|
||||
// Just in case someone has opened the project in an IDE or built it. We don't want to copy
|
||||
// these folders.
|
||||
continue;
|
||||
}
|
||||
|
||||
var created = destination.CreateSubdirectory(directory.Name);
|
||||
CopyDirectory(directory, created);
|
||||
}
|
||||
|
||||
foreach (var file in source.EnumerateFiles())
|
||||
{
|
||||
file.CopyTo(Path.Combine(destination.FullName, file.Name));
|
||||
}
|
||||
}
|
||||
|
||||
void RewriteCsproj(string originalProjectRoot, string filePath)
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
private ProjectDirectory(string directoryPath)
|
||||
{
|
||||
DirectoryPath = directoryPath;
|
||||
}
|
||||
|
||||
public string DirectoryPath { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
CleanupDirectory(DirectoryPath);
|
||||
}
|
||||
|
||||
private static void CleanupDirectory(string filePath)
|
||||
{
|
||||
var tries = 5;
|
||||
var sleep = TimeSpan.FromSeconds(3);
|
||||
|
||||
for (var i = 0; i < tries; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.Delete(filePath, recursive: true);
|
||||
return;
|
||||
}
|
||||
catch when (i < tries - 1)
|
||||
{
|
||||
Console.WriteLine($"Failed to delete directory {filePath}, trying again.");
|
||||
Thread.Sleep(sleep);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>
|
||||
<PreserveCompilationContext>true</PreserveCompilationContext>
|
||||
<DefaultItemExcludes>$(DefaultItemExcludes);TestFiles\**</DefaultItemExcludes>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="xunit.runner.json" CopyToOutputDirectory="PreserveNewest" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Testing" Version="$(MicrosoftAspNetCoreTestingPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftNETTestSdkPackageVersion)" />
|
||||
<PackageReference Include="Moq" Version="$(MoqPackageVersion)" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="$(XunitRunnerVisualStudioPackageVersion)" />
|
||||
<PackageReference Include="xunit" Version="$(XunitPackageVersion)" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"methodDisplay": "method",
|
||||
"shadowCopy": false
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>
|
||||
<TargetFrameworks>$(StandardTestTfms);netstandard2.0</TargetFrameworks>
|
||||
<PreserveCompilationContext>true</PreserveCompilationContext>
|
||||
</PropertyGroup>
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
using System;
|
||||
|
||||
namespace SimpleMvc.Models
|
||||
{
|
||||
public class ErrorViewModel
|
||||
{
|
||||
public string RequestId { get; set; }
|
||||
|
||||
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
namespace SimpleMvc
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<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>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
@{
|
||||
ViewData["Title"] = "About";
|
||||
}
|
||||
<h2>@ViewData["Title"]</h2>
|
||||
<h3>@ViewData["Message"]</h3>
|
||||
|
||||
<p>Use this area to provide additional information.</p>
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
@{
|
||||
ViewData["Title"] = "Contact";
|
||||
}
|
||||
<h2>@ViewData["Title"]</h2>
|
||||
<h3>@ViewData["Message"]</h3>
|
||||
|
||||
<address>
|
||||
One Microsoft Way<br />
|
||||
Redmond, WA 98052-6399<br />
|
||||
<abbr title="Phone">P:</abbr>
|
||||
425.555.0100
|
||||
</address>
|
||||
|
||||
<address>
|
||||
<strong>Support:</strong> <a href="mailto:Support@example.com">Support@example.com</a><br />
|
||||
<strong>Marketing:</strong> <a href="mailto:Marketing@example.com">Marketing@example.com</a>
|
||||
</address>
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
@{
|
||||
ViewData["Title"] = "Home Page";
|
||||
}
|
||||
|
||||
<div id="myCarousel" class="carousel slide" data-ride="carousel" data-interval="6000">
|
||||
<ol class="carousel-indicators">
|
||||
<li data-target="#myCarousel" data-slide-to="0" class="active"></li>
|
||||
<li data-target="#myCarousel" data-slide-to="1"></li>
|
||||
<li data-target="#myCarousel" data-slide-to="2"></li>
|
||||
<li data-target="#myCarousel" data-slide-to="3"></li>
|
||||
</ol>
|
||||
<div class="carousel-inner" role="listbox">
|
||||
<div class="item active">
|
||||
<img src="~/images/banner1.svg" alt="ASP.NET" class="img-responsive" />
|
||||
<div class="carousel-caption" role="option">
|
||||
<p>
|
||||
Learn how to build ASP.NET apps that can run anywhere.
|
||||
<a class="btn btn-default" href="https://go.microsoft.com/fwlink/?LinkID=525028&clcid=0x409">
|
||||
Learn More
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<img src="~/images/banner2.svg" alt="Visual Studio" class="img-responsive" />
|
||||
<div class="carousel-caption" role="option">
|
||||
<p>
|
||||
There are powerful new features in Visual Studio for building modern web apps.
|
||||
<a class="btn btn-default" href="https://go.microsoft.com/fwlink/?LinkID=525030&clcid=0x409">
|
||||
Learn More
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<img src="~/images/banner3.svg" alt="Package Management" class="img-responsive" />
|
||||
<div class="carousel-caption" role="option">
|
||||
<p>
|
||||
Bring in libraries from NuGet, Bower, and npm, and automate tasks using Grunt or Gulp.
|
||||
<a class="btn btn-default" href="https://go.microsoft.com/fwlink/?LinkID=525029&clcid=0x409">
|
||||
Learn More
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<img src="~/images/banner4.svg" alt="Microsoft Azure" class="img-responsive" />
|
||||
<div class="carousel-caption" role="option">
|
||||
<p>
|
||||
Learn how Microsoft's Azure cloud platform allows you to build, deploy, and scale web apps.
|
||||
<a class="btn btn-default" href="https://go.microsoft.com/fwlink/?LinkID=525027&clcid=0x409">
|
||||
Learn More
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a class="left carousel-control" href="#myCarousel" role="button" data-slide="prev">
|
||||
<span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>
|
||||
<span class="sr-only">Previous</span>
|
||||
</a>
|
||||
<a class="right carousel-control" href="#myCarousel" role="button" data-slide="next">
|
||||
<span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
|
||||
<span class="sr-only">Next</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<h2>Application uses</h2>
|
||||
<ul>
|
||||
<li>Sample pages using ASP.NET Core MVC</li>
|
||||
<li><a href="https://go.microsoft.com/fwlink/?LinkId=518004">Bower</a> for managing client-side libraries</li>
|
||||
<li>Theming using <a href="https://go.microsoft.com/fwlink/?LinkID=398939">Bootstrap</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<h2>How to</h2>
|
||||
<ul>
|
||||
<li><a href="https://go.microsoft.com/fwlink/?LinkID=398600">Add a Controller and View</a></li>
|
||||
<li><a href="https://go.microsoft.com/fwlink/?LinkId=699315">Manage User Secrets using Secret Manager.</a></li>
|
||||
<li><a href="https://go.microsoft.com/fwlink/?LinkId=699316">Use logging to log a message.</a></li>
|
||||
<li><a href="https://go.microsoft.com/fwlink/?LinkId=699317">Add packages using NuGet.</a></li>
|
||||
<li><a href="https://go.microsoft.com/fwlink/?LinkId=699318">Add client packages using Bower.</a></li>
|
||||
<li><a href="https://go.microsoft.com/fwlink/?LinkId=699319">Target development, staging or production environment.</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<h2>Overview</h2>
|
||||
<ul>
|
||||
<li><a href="https://go.microsoft.com/fwlink/?LinkId=518008">Conceptual overview of what is ASP.NET Core</a></li>
|
||||
<li><a href="https://go.microsoft.com/fwlink/?LinkId=699320">Fundamentals of ASP.NET Core such as Startup and middleware.</a></li>
|
||||
<li><a href="https://go.microsoft.com/fwlink/?LinkId=398602">Working with Data</a></li>
|
||||
<li><a href="https://go.microsoft.com/fwlink/?LinkId=398603">Security</a></li>
|
||||
<li><a href="https://go.microsoft.com/fwlink/?LinkID=699321">Client side development</a></li>
|
||||
<li><a href="https://go.microsoft.com/fwlink/?LinkID=699322">Develop on different platforms</a></li>
|
||||
<li><a href="https://go.microsoft.com/fwlink/?LinkID=699323">Read more on the documentation site</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<h2>Run & Deploy</h2>
|
||||
<ul>
|
||||
<li><a href="https://go.microsoft.com/fwlink/?LinkID=517851">Run your app</a></li>
|
||||
<li><a href="https://go.microsoft.com/fwlink/?LinkID=517853">Run tools such as EF migrations and more</a></li>
|
||||
<li><a href="https://go.microsoft.com/fwlink/?LinkID=398609">Publish to Microsoft Azure Web Apps</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
@model ErrorViewModel
|
||||
@{
|
||||
ViewData["Title"] = "Error";
|
||||
}
|
||||
|
||||
<h1 class="text-danger">Error.</h1>
|
||||
<h2 class="text-danger">An error occurred while processing your request.</h2>
|
||||
|
||||
@if (Model.ShowRequestId)
|
||||
{
|
||||
<p>
|
||||
<strong>Request ID:</strong> <code>@Model.RequestId</code>
|
||||
</p>
|
||||
}
|
||||
|
||||
<h3>Development Mode</h3>
|
||||
<p>
|
||||
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Development environment should not be enabled in deployed applications</strong>, as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>, and restarting the application.
|
||||
</p>
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>@ViewData["Title"] - SimpleMvc</title>
|
||||
|
||||
<environment include="Development">
|
||||
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
|
||||
<link rel="stylesheet" href="~/css/site.css" />
|
||||
</environment>
|
||||
<environment exclude="Development">
|
||||
<link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/css/bootstrap.min.css"
|
||||
asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
|
||||
asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" />
|
||||
<link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />
|
||||
</environment>
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a asp-area="" asp-controller="Home" asp-action="Index" class="navbar-brand">SimpleMvc</a>
|
||||
</div>
|
||||
<div class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a asp-area="" asp-controller="Home" asp-action="Index">Home</a></li>
|
||||
<li><a asp-area="" asp-controller="Home" asp-action="About">About</a></li>
|
||||
<li><a asp-area="" asp-controller="Home" asp-action="Contact">Contact</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="container body-content">
|
||||
@RenderBody()
|
||||
<hr />
|
||||
<footer>
|
||||
<p>© 2017 - SimpleMvc</p>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<environment include="Development">
|
||||
<script src="~/lib/jquery/dist/jquery.js"></script>
|
||||
<script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
|
||||
<script src="~/js/site.js" asp-append-version="true"></script>
|
||||
</environment>
|
||||
<environment exclude="Development">
|
||||
<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.2.0.min.js"
|
||||
asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
|
||||
asp-fallback-test="window.jQuery"
|
||||
crossorigin="anonymous"
|
||||
integrity="sha384-K+ctZQ+LL8q6tP7I94W+qzQsfRV2a+AfHIi9k8z8l9ggpc8X+Ytst4yBo/hH+8Fk">
|
||||
</script>
|
||||
<script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/bootstrap.min.js"
|
||||
asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.min.js"
|
||||
asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal"
|
||||
crossorigin="anonymous"
|
||||
integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa">
|
||||
</script>
|
||||
<script src="~/js/site.min.js" asp-append-version="true"></script>
|
||||
</environment>
|
||||
|
||||
@RenderSection("Scripts", required: false)
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<environment include="Development">
|
||||
<script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>
|
||||
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>
|
||||
</environment>
|
||||
<environment exclude="Development">
|
||||
<script src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.14.0/jquery.validate.min.js"
|
||||
asp-fallback-src="~/lib/jquery-validation/dist/jquery.validate.min.js"
|
||||
asp-fallback-test="window.jQuery && window.jQuery.validator"
|
||||
crossorigin="anonymous"
|
||||
integrity="sha384-Fnqn3nxp3506LP/7Y3j/25BlWeA3PXTyT1l78LjECcPaKCV12TsZP7yyMxOe/G/k">
|
||||
</script>
|
||||
<script src="https://ajax.aspnetcdn.com/ajax/jquery.validation.unobtrusive/3.2.6/jquery.validate.unobtrusive.min.js"
|
||||
asp-fallback-src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"
|
||||
asp-fallback-test="window.jQuery && window.jQuery.validator && window.jQuery.validator.unobtrusive"
|
||||
crossorigin="anonymous"
|
||||
integrity="sha384-JrXK+k53HACyavUKOsL+NkmSesD2P+73eDMrbTtTk0h4RmOF8hF8apPlkp26JlyH">
|
||||
</script>
|
||||
</environment>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
@using SimpleMvc
|
||||
@using SimpleMvc.Models
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
@{
|
||||
Layout = "_Layout";
|
||||
}
|
||||
Loading…
Reference in New Issue