Repository: StackExchange/StackExchange.Precompilation
Branch: master
Commit: d595fac3c69c
Files: 81
Total size: 152.0 KB
Directory structure:
gitextract_e7pohamh/
├── .gitignore
├── BuildAndPack.ps1
├── Directory.Build.props
├── README.md
├── Release.ps1
├── StackExchange.Precompilation/
│ ├── AfterCompileContext.cs
│ ├── AppDomainHelper.cs
│ ├── Attributes.cs
│ ├── BeforeCompileContext.cs
│ ├── CompileContext.cs
│ ├── CompileModuleElement.cs
│ ├── CompileModulesCollection.cs
│ ├── CompiledFromDirectoryAttribute.cs
│ ├── CompiledFromFileAttribute.cs
│ ├── ICompileContext.cs
│ ├── ICompileModule.cs
│ ├── IMetadataReference.cs
│ ├── PrecompilationModuleLoader.cs
│ ├── PrecompilerSection.cs
│ ├── RazorCacheElement.cs
│ └── StackExchange.Precompilation.csproj
├── StackExchange.Precompilation.Build/
│ ├── App.config
│ ├── Attributes.cs
│ ├── Compilation.cs
│ ├── CompilationAssemblyResolver.cs
│ ├── CompilationProxy.cs
│ ├── ICompilationProxy.cs
│ ├── PrecompilationCommandLineArgs.cs
│ ├── PrecompilationCommandLineParser.cs
│ ├── Program.cs
│ ├── StackExchange.Precompilation.Build.csproj
│ ├── StackExchange.Precompilation.Build.packages.config
│ └── StackExchange.Precompilation.Build.targets
├── StackExchange.Precompilation.Tests/
│ ├── CommandLineTests.cs
│ └── StackExchange.Precompilation.Tests.csproj
├── StackExchange.Precompilation.sln
├── StackExhcange.Precompilation.MVC5/
│ ├── Hacks.cs
│ ├── PrecompilationView.cs
│ ├── PrecompilationVirtualPathFactory.cs
│ ├── PrecompiledViewEngine.cs
│ ├── ProfiledVirtualPathProviderViewEngine.cs
│ ├── RazorParser.cs
│ ├── RoslynRazorViewEngine.cs
│ └── StackExchange.Precompilation.MVC5.csproj
├── Test.ConsoleApp/
│ ├── AliasTest.cs
│ ├── App.config
│ ├── Program.cs
│ └── Test.ConsoleApp.csproj
├── Test.Module/
│ ├── Test.Module.csproj
│ └── TestCompileModule.cs
├── Test.WebApp/
│ ├── Content/
│ │ └── PartialExternalContent.cshtml
│ ├── Controllers/
│ │ └── HomeController.cs
│ ├── Models/
│ │ └── SampleModel.cs
│ ├── MvcApplication.cs
│ ├── Properties/
│ │ └── AssemblyInfo.cs
│ ├── Test.WebApp.csproj
│ ├── Views/
│ │ ├── Home/
│ │ │ ├── ExcludedLayout.cshtml
│ │ │ ├── Index.Mobile.cshtml
│ │ │ └── Index.cshtml
│ │ ├── Other/
│ │ │ └── RelativePartial.cshtml
│ │ ├── Shared/
│ │ │ ├── EditorTemplates/
│ │ │ │ ├── SampleModel.Mobile.cshtml
│ │ │ │ ├── SampleModel.cshtml
│ │ │ │ └── String.cshtml
│ │ │ ├── _Footer.Mobile.cshtml
│ │ │ ├── _Footer.cshtml
│ │ │ ├── _Layout.Excluded.cshtml
│ │ │ ├── _Layout.Mobile.cshtml
│ │ │ ├── _Layout.Overridden.cshtml
│ │ │ └── _Layout.cshtml
│ │ ├── Web.config
│ │ └── _ViewStart.cshtml
│ └── Web.config
├── Test.WebApp.ExternalViews/
│ ├── App_Code/
│ │ └── Helpers.cshtml
│ ├── ExternalViews.cs
│ ├── Test.WebApp.ExternalViews.csproj
│ └── Views/
│ ├── Shared/
│ │ ├── ExternalPartial.cshtml
│ │ └── ExternalView.cshtml
│ └── Web.config
├── appveyor.yml
├── license.txt
└── semver.txt
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
*.suo
*/bin/
*/obj/
*.orig
*.user
*.nupkg
*.GhostDoc.xml
MoonSpeak.sln.ide/
tools
packages
.vs
_ReSharper*
================================================
FILE: BuildAndPack.ps1
================================================
param(
[parameter(Position=0)]
[string] $VersionSuffix,
[parameter(Position=1)]
[string] $GitCommitId,
[parameter(Position=2)]
[string[]] $MsBuildArgs,
[switch] $CIBuild
)
if (-not $semver)
{
set-variable -name semver -scope global -value (get-content .\semver.txt)
}
if ($VersionSuffix -or $CIBuild)
{
$version = "$semver$VersionSuffix"
}
else
{
$epoch = [math]::truncate((new-timespan -start (get-date -date "01/01/1970") -end (get-date)).TotalSeconds)
$version = "$semver-local$epoch"
}
if(-not $GitCommitId)
{
$GitCommitId = $(git rev-parse HEAD)
}
$solutionDir = "$((Resolve-Path .).Path)\"
$defaultArgs = "/v:n", "/nologo",
"/p:SolutionDir=$solutionDir",
"/p:RepositoryCommit=$GitCommitId",
"/p:Version=$version",
"/p:Configuration=Release",
"/p:SEPrecompilerPath=$solutionDir\StackExchange.Precompilation.Build\bin\Release\net462"
if ($MsBuildArgs)
{
$defaultArgs += $MsBuildArgs
}
& msbuild ($defaultArgs + "/t:Restore")
& msbuild ($defaultArgs + "/t:Build,Pack")
if ($LastExitCode -ne 0)
{
throw "MSBuild failed"
}
.\Test.ConsoleApp\bin\Release\net462\Test.ConsoleApp.exe
if ($LastExitCode -ne 0)
{
throw "Test.ConsoleApp failed to run"
}
================================================
FILE: Directory.Build.props
================================================
<Project>
<PropertyGroup>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<IsPackable>false</IsPackable> <!-- enabled on each packable project exlpicitly -->
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugType>embedded</DebugType>
<PackageOutputPath>$(SolutionDir)packages\obj\</PackageOutputPath>
<Authors>m0sa</Authors>
<Copyright>Stack Exchange 2017</Copyright>
<PackageTags>Razor AspNet MsBuild Roslyn Metaprogramming</PackageTags>
<RepositoryUrl>https://github.com/StackExchange/StackExchange.Precompilation.git</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<ProjectUrl>https://github.com/StackExchange/StackExchange.Precompilation</ProjectUrl>
<PackageReleaseNotes><![CDATA[
Version 5.1.0
* updating roslyn packages to 2.10.0
* updating mvc packages to 5.2.7
* fixing SourceLink support for native pdbs
Version 5.0.0
* updating how Precompilation.Build resolves it's Workspaces dependency
* retiring Precompilation.Metaprogramming
* support running compilation modules at runtime in RoslynRazorViewEngine
* split out System.Web / MVC5 portions into a separate package
* bumping aspnet mvc packages to 5.2.4
* updating roslyn packages to 2.8.2
Version 4.7.0
* updated roslyn packages to 2.7.0
* cleaned up diagnostics numbers
* report source text in razor HttpParseExceptions
* report razor parser errors diagnostics during precompilation
Version 4.6.1
* fixed perf regression due to missing app.config with proper GC settings in the .Build package
* updated roslyn packages to latest version (2.6.1)
* fixed remoting runtime exception in long builds
Version 4.6
* updated roslyn packages to latest version (2.6)
* fixed case where layout and view page weren't resolvable by the same view engine
Version 4.5
* upped MVC5 to latest minor version (5.2.3)
* razor cache directory option can ge passed in via PRECOMPILATION_RAZORCACHEDIRECTORY environment variable
Version 4.4
* added configurable support for caching the razor (.cshtml -> .cs) generation step
* added optional razorCache element to the precompilation configuration section
* fixing non-default langversion bug
* better handling of failing precompilation modules
* don't ouput hidden diagnostics to console
* updated roslyn packages to 2.4.0
Version 4.1.1
* updated roslyn packages to 2.3.2
Version 4.1.0
* updated roslyn packages to 2.3.1
* don't emit pdb files when debugtype embedded
* pathmap support
]]>
</PackageReleaseNotes>
</PropertyGroup>
</Project>
================================================
FILE: README.md
================================================
StackExchange.Precompilation
============================
[](https://ci.appveyor.com/project/StackExchange/stackexchange-precompilation/branch/master)
Replacing csc.exe
-----------------
- `Install-Package StackExchange.Precompilation.Build -Pre`
Replacing aspnet_compiler.exe for .cshtml precompilation
--------------------------------------------------------
- `Install-Package StackExchange.Precompilation.Build -Pre`
- Add `<PropertyGroup><SEPrecompilerIncludeRazor>true</SEPrecompilerIncludeRazor></PropertyGroup>` to your .csproj file (usually replacing the `MvcBuildViews` property)
#### Using precompiled views
- [Add the PrecompiledViewEngine to ViewEngines](https://github.com/StackExchange/StackExchange.Precompilation/blob/fd536b764983e2674a4549b7be6f26e971190c1e/Test.WebApp/Global.asax.cs#L29)
#### Using C# 7 in ASP.NET MVC 5
- [Add the RoslynRazorViewEngine to ViewEngines](https://github.com/StackExchange/StackExchange.Precompilation/blob/fd536b764983e2674a4549b7be6f26e971190c1e/Test.WebApp/Global.asax.cs#L32)
Meta-programming
----------------
- Create a new project
- `Install-Package StackExchange.Precompilation -Pre`
- Implement the ICompileModule interface
- `Install-Package StackExchange.Precompilation.Build -Pre` in the target project
- [Configure your new module](https://github.com/StackExchange/StackExchange.Precompilation/blob/fd536b764983e2674a4549b7be6f26e971190c1e/Test.ConsoleApp/App.config#L8) in the target project's web.config or app.config
Development
-----------
if you have an existing project with StackExchange.Precompilation packages and encounter a bug you can simply:
- pull this repo
- increment semver.txt
- make the fix in the source code
- run BuildAndPack.ps1 (requires a console with VS env vars in your PATH, I recommend powershell with Posh-VsVars)
- setup a nuget source pointing at .\packages\obj
- after that you can update the packages StackExchange.Precompilation in your target project from the packages\obj source
- this gives you local *-local{timestamp} suffixed packages instead of the *-alpha{build} ones produced by the CI build
- PROTIP: if you want to attach an debugger to the compilation of your project or any of the Test.* projects, add a `System.Diagnostics.Debugger.Launch()` statement somewhere in the code ;)
- CI *-alpha{build} packages are available on the stackoverflow myget feed https://www.myget.org/F/stackoverflow/api/v2
================================================
FILE: Release.ps1
================================================
set-variable -name semver -scope global -value (get-content .\semver.txt)
git tag -a "releases/$semver" -m "creating $semver release"
git push --tags
================================================
FILE: StackExchange.Precompilation/AfterCompileContext.cs
================================================
using System.Collections.Generic;
using System.IO;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
namespace StackExchange.Precompilation
{
public class AfterCompileContext : ICompileContext
{
public CSharpCommandLineArguments Arguments { get; internal set; }
public CSharpCompilation Compilation { get; internal set; }
public Stream AssemblyStream { get; internal set; }
public Stream SymbolStream { get; internal set; }
public Stream XmlDocStream { get; internal set; }
public IList<Diagnostic> Diagnostics { get; internal set; }
}
}
================================================
FILE: StackExchange.Precompilation/AppDomainHelper.cs
================================================
using System;
namespace StackExchange.Precompilation
{
/// <summary>
/// Precompilation helper methods.
/// </summary>
public static class AppDomainHelper
{
/// <summary>
/// The friednly name of the <see cref="AppDomain"/> hosting the compilation.
/// </summary>
public const string CsCompilationAppDomainName = "csMoonSpeak";
/// <summary>
/// </summary>
/// <param name="appDomain"></param>
/// <returns>Returns <c>true</c> if the <paramref name="appDomain"/> is a Precompilation domain.</returns>
public static bool IsPrecompilation(this AppDomain appDomain)
{
return (appDomain ?? AppDomain.CurrentDomain).FriendlyName == CsCompilationAppDomainName;
}
}
}
================================================
FILE: StackExchange.Precompilation/Attributes.cs
================================================
[assembly:System.Runtime.CompilerServices.InternalsVisibleToAttribute("StackExchange.Precompiler")]
[assembly:System.Runtime.CompilerServices.InternalsVisibleToAttribute("StackExchange.Precompilation.Build")]
[assembly:System.Runtime.CompilerServices.InternalsVisibleToAttribute("StackExchange.Precompilation.MVC5")]
================================================
FILE: StackExchange.Precompilation/BeforeCompileContext.cs
================================================
using System.Collections.Generic;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
namespace StackExchange.Precompilation
{
public class BeforeCompileContext : ICompileContext
{
public CSharpCommandLineArguments Arguments { get; set; }
public CSharpCompilation Compilation { get; set; }
public IList<Diagnostic> Diagnostics { get; internal set; }
}
}
================================================
FILE: StackExchange.Precompilation/CompileContext.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
namespace StackExchange.Precompilation
{
internal class CompileContext
{
private readonly ICollection<ICompileModule> _modules;
public BeforeCompileContext BeforeCompileContext { get; private set; }
public AfterCompileContext AfterCompileContext { get; private set; }
public CompileContext(ICollection<ICompileModule> modules)
{
_modules = modules;
}
public void Before(BeforeCompileContext context)
{
Apply(context, x => BeforeCompileContext = x, m => m.BeforeCompile);
}
public void After(AfterCompileContext context)
{
Apply(context, x => AfterCompileContext = x, m => m.AfterCompile);
}
private void Apply<TContext>(TContext ctx, Action<TContext> setter, Func<ICompileModule, Action<TContext>> actionGetter)
where TContext : ICompileContext
{
setter(ctx);
foreach(var module in _modules)
{
try
{
var action = actionGetter(module);
action(ctx);
}
catch (Exception ex)
{
var methodName = ctx is BeforeCompileContext ? nameof(ICompileModule.BeforeCompile) : nameof(ICompileModule.AfterCompile);
throw new PrecompilationModuleException($"Precompilation module '{module.GetType().FullName}.{methodName}({typeof(TContext)})' failed", ex);
}
}
}
}
internal class PrecompilationModuleException : Exception
{
public PrecompilationModuleException(string message, Exception inner) : base(message, inner)
{
}
}
}
================================================
FILE: StackExchange.Precompilation/CompileModuleElement.cs
================================================
using System.Configuration;
namespace StackExchange.Precompilation
{
/// <summary>
/// A compile module configuration element.
/// </summary>
/// <seealso cref="ICompileModule"/>
public class CompileModuleElement : ConfigurationElement
{
/// <summary>
/// The type of the <see cref="ICompileModule"/> to be loaded at compile time.
/// </summary>
[ConfigurationProperty("type", IsRequired = true, DefaultValue = null)]
public string Type { get { return (string)base["type"]; } }
}
}
================================================
FILE: StackExchange.Precompilation/CompileModulesCollection.cs
================================================
using System.Configuration;
namespace StackExchange.Precompilation
{
/// <summary>
/// A collection of <see cref="CompileModuleElement"/> instances.
/// </summary>
public class CompileModulesCollection : ConfigurationElementCollection
{
protected override ConfigurationElement CreateNewElement()
{
return new CompileModuleElement();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((CompileModuleElement)element).Type;
}
}
}
================================================
FILE: StackExchange.Precompilation/CompiledFromDirectoryAttribute.cs
================================================
using System;
namespace StackExchange.Precompilation
{
/// <summary>
/// Decorates a precompiled MVC assembly. Used to calculate relative view paths.
/// </summary>
[AttributeUsage(AttributeTargets.Assembly)]
public class CompiledFromDirectoryAttribute : Attribute
{
/// <summary>
/// Gets the source directory path.
/// </summary>
public string SourceDirectory { get; private set; }
/// <summary></summary>
/// <param name="sourceDirectory"></param>
public CompiledFromDirectoryAttribute(string sourceDirectory)
{
SourceDirectory = sourceDirectory;
}
}
}
================================================
FILE: StackExchange.Precompilation/CompiledFromFileAttribute.cs
================================================
using System;
namespace StackExchange.Precompilation
{
/// <summary>
/// Decorates a precompiled MVC page.
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class CompiledFromFileAttribute : Attribute
{
/// <summary>
/// Gets the source file path.
/// </summary>
public string SourceFile { get; private set; }
/// <summary></summary>
/// <param name="sourceFile"></param>
public CompiledFromFileAttribute(string sourceFile)
{
SourceFile = sourceFile;
}
}
}
================================================
FILE: StackExchange.Precompilation/ICompileContext.cs
================================================
using System.Collections.Generic;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
namespace StackExchange.Precompilation
{
public interface ICompileContext
{
CSharpCommandLineArguments Arguments { get; }
CSharpCompilation Compilation { get; }
IList<Diagnostic> Diagnostics { get; }
}
}
================================================
FILE: StackExchange.Precompilation/ICompileModule.cs
================================================
namespace StackExchange.Precompilation
{
/// <summary>
/// Allows plugging into the compilation pipeline. Has to be registered in app/web.config
/// </summary>
/// <remarks>
/// <example>
/// <code language="xml"><![CDATA[
/// <configuration>
/// <configSections>
/// <section name="stackExchange.precompiler" type="StackExchange.Precompilation.PrecompilerSection, StackExchange.Precompilation" />
/// </configSections>
/// <stackExchange.precompiler>
/// <modules>
/// <add type="MyAssembly.MyModule, MyAssembly" />
/// </modules>
/// </stackExchange.precompiler>
/// </coniguration>]]>
/// </code>
/// </example>
/// </remarks>
public interface ICompileModule
{
/// <summary>
/// Called before anything is emitted
/// </summary>
/// <param name="context"></param>
void BeforeCompile(BeforeCompileContext context);
/// <summary>
/// Called after the compilation is emitted. Changing the compilation will not have any effect at this point
/// but the assembly can be changed before it is saved on disk or loaded into memory.
/// </summary>
/// <param name="context"></param>
void AfterCompile(AfterCompileContext context);
}
}
================================================
FILE: StackExchange.Precompilation/IMetadataReference.cs
================================================
================================================
FILE: StackExchange.Precompilation/PrecompilationModuleLoader.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
namespace StackExchange.Precompilation
{
internal class PrecompilationModuleLoader
{
/// <summary>Fires when a <see cref="CompileModuleElement" /> cannot be resolved to an actual <see cref="System.Type" />.</summary>
/// <remarks>Register the handlers before touching <see cref="LoadedModules" />.</remarks>
public event Action<CompileModuleElement, Exception> ModuleInitializationFailed;
/// <summary>Gets a cached collection of loaded modules.</summary>
public ICollection<ICompileModule> LoadedModules => _loadedModules.Value;
private readonly Lazy<ICollection<ICompileModule>> _loadedModules;
private readonly PrecompilerSection _configuration;
public PrecompilationModuleLoader(PrecompilerSection configuration)
{
_configuration = configuration;
_loadedModules = new Lazy<ICollection<ICompileModule>>(() =>
{
var result = new List<ICompileModule>();
if (_configuration == null || _configuration.CompileModules == null)
{
return result;
}
foreach(var module in _configuration.CompileModules.Cast<CompileModuleElement>())
{
try
{
var type = Type.GetType(module.Type, true);
if (Activator.CreateInstance(type, true) is ICompileModule cm)
{
result.Add(cm);
}
else
{
throw new TypeLoadException($"{module.Type} is not an {nameof(ICompileModule)}.");
}
}
catch(Exception ex)
{
ModuleInitializationFailed?.Invoke(module, ex);
}
}
return result;
});
}
}
}
================================================
FILE: StackExchange.Precompilation/PrecompilerSection.cs
================================================
using System.Configuration;
namespace StackExchange.Precompilation
{
/// <summary>
/// Defines the <c>stackExchange.precompiler</c> <see cref="ConfigurationSection"/>.
/// </summary>
/// <seealso cref="ICompileModule"/>
public class PrecompilerSection : ConfigurationSection
{
/// <summary>
/// Gets the <see cref="CompileModulesCollection"/>.
/// </summary>
[ConfigurationProperty("modules", IsRequired = false)]
[ConfigurationCollection(typeof(CompileModulesCollection))]
public CompileModulesCollection CompileModules => (CompileModulesCollection)base["modules"];
/// <summary>
/// Gets the <c>stackExchange.precompiler</c> section from the <see cref="ConfigurationManager"/>.
/// </summary>
public static PrecompilerSection Current => (PrecompilerSection)ConfigurationManager.GetSection("stackExchange.precompiler");
[ConfigurationProperty("razorCache", IsRequired = false)]
public RazorCacheElement RazorCache => (RazorCacheElement)base["razorCache"];
}
}
================================================
FILE: StackExchange.Precompilation/RazorCacheElement.cs
================================================
using System.Configuration;
namespace StackExchange.Precompilation
{
public class RazorCacheElement : ConfigurationElement
{
/// <summary>
/// The type of the <see cref="ICompileModule"/> to be loaded at compile time.
/// </summary>
[ConfigurationProperty("directory", IsRequired = true, DefaultValue = null)]
public string Directory => (string)base["directory"];
}
}
================================================
FILE: StackExchange.Precompilation/StackExchange.Precompilation.csproj
================================================
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net462;netstandard20</TargetFrameworks>
<Description>Hooks into the ASP.NET MVC pipeline to enable usage of C# 7.2, and views precompiled with StackExchange.Precompilation.Build</Description>
<IsPackable>true</IsPackable>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Configuration.ConfigurationManager" Version="4.4.1" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="2.10.0" ExcludeAssets="analyzers"/>
</ItemGroup>
</Project>
================================================
FILE: StackExchange.Precompilation.Build/App.config
================================================
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" />
</startup>
<runtime>
<gcServer enabled="true" />
<gcConcurrent enabled="false" />
</runtime>
</configuration>
================================================
FILE: StackExchange.Precompilation.Build/Attributes.cs
================================================
[assembly:System.Runtime.CompilerServices.InternalsVisibleToAttribute("StackExchange.Precompilation.MVC5")]
================================================
FILE: StackExchange.Precompilation.Build/Compilation.cs
================================================
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.Emit;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Host;
using System.Composition.Hosting;
using Microsoft.CodeAnalysis.Host.Mef;
using System.Composition;
using System.Threading;
namespace StackExchange.Precompilation
{
internal class Compilation
{
private readonly PrecompilationCommandLineArgs _precompilationCommandLineArgs;
internal CSharpCommandLineArguments CscArgs { get; private set; }
internal DirectoryInfo CurrentDirectory { get; private set; }
internal List<Diagnostic> Diagnostics { get; private set; }
internal Encoding Encoding { get; private set; }
private const string DiagnosticCategory = "StackExchange.Precompilation";
private static DiagnosticDescriptor FailedToCreateModule =
new DiagnosticDescriptor("SE001", "Failed to instantiate ICompileModule", "Failed to instantiate ICompileModule '{0}': {1}", DiagnosticCategory, DiagnosticSeverity.Error, true);
private static DiagnosticDescriptor FailedToCreateCompilation =
new DiagnosticDescriptor("SE002", "Failed to create compilation", "{0}", DiagnosticCategory, DiagnosticSeverity.Error, true);
internal static DiagnosticDescriptor ViewGenerationFailed =
new DiagnosticDescriptor("SE003", "View generation failed", "View generation failed: {0}", DiagnosticCategory, DiagnosticSeverity.Error, true);
internal static DiagnosticDescriptor FailedParsingSourceTree =
new DiagnosticDescriptor("SE004", "Failed parsing source tree", "Failed parasing source tree: {0}", DiagnosticCategory, DiagnosticSeverity.Error, true);
internal static DiagnosticDescriptor PrecompilationModuleFailed =
new DiagnosticDescriptor("SE005", "Precompilation module failed", "{0}: {1}", DiagnosticCategory, DiagnosticSeverity.Error, true);
private static DiagnosticDescriptor AnalysisFailed =
new DiagnosticDescriptor("SE006", "Analysis failed", "{0}", DiagnosticCategory, DiagnosticSeverity.Error, true);
private static DiagnosticDescriptor UnhandledException =
new DiagnosticDescriptor("SE007", "Unhandled exception", "Unhandled exception: {0}", DiagnosticCategory, DiagnosticSeverity.Error, true);
internal static DiagnosticDescriptor ERR_FileNotFound =
new DiagnosticDescriptor("CS2001", "FileNotFound", "Source file '{0}' could not be found", DiagnosticCategory, DiagnosticSeverity.Error, true);
internal static DiagnosticDescriptor ERR_BinaryFile =
new DiagnosticDescriptor("CS2015", "BinaryFile", "'{0}' is a binary file instead of a text file", DiagnosticCategory, DiagnosticSeverity.Error, true);
internal static DiagnosticDescriptor ERR_NoSourceFile =
new DiagnosticDescriptor("CS1504", "NoSourceFile", "Source file '{0}' could not be opened ('{1}')", DiagnosticCategory, DiagnosticSeverity.Error, true);
internal static DiagnosticDescriptor CachingFailed =
new DiagnosticDescriptor("SE008", "Razor caching failed", "Caching generated cshtml for '{0}' failed, deleting file '{1}' - '{2}'", DiagnosticCategory, DiagnosticSeverity.Warning, true);
internal static DiagnosticDescriptor CachingFailedHard =
new DiagnosticDescriptor("SE009", "Razor caching failed hard", "Caching generated cshtml for '{0}' to '{1}' failed, unabled to delete cache file", DiagnosticCategory, DiagnosticSeverity.Error, true);
internal static DiagnosticDescriptor RazorParserError =
new DiagnosticDescriptor("SE010", "Razor parser error", "Razor parser error: {0}", DiagnosticCategory, DiagnosticSeverity.Error, true);
public Compilation(PrecompilationCommandLineArgs precompilationCommandLineArgs)
{
_precompilationCommandLineArgs = precompilationCommandLineArgs;
CurrentDirectory = new DirectoryInfo(_precompilationCommandLineArgs.BaseDirectory);
AppDomain.CurrentDomain.SetData("DataDirectory", Path.Combine(CurrentDirectory.FullName, "App_Data")); // HACK mocking ASP.NET's ~/App_Data aka. |DataDirectory|
// HACK moar HttpRuntime stuff
AppDomain.CurrentDomain.SetData(".appDomain", AppDomain.CurrentDomain.FriendlyName);
AppDomain.CurrentDomain.SetData(".appPath", CurrentDirectory.FullName);
AppDomain.CurrentDomain.SetData(".appVPath", "/");
}
public async Task<bool> RunAsync(CancellationToken cancellationToken = default(CancellationToken))
{
try
{
// this parameter was introduced in rc3, all call to it seem to be using RuntimeEnvironment.GetRuntimeDirectory()
// https://github.com/dotnet/roslyn/blob/0382e3e3fc543fc483090bff3ab1eaae39dfb4d9/src/Compilers/CSharp/csc/Program.cs#L18
var sdkDirectory = RuntimeEnvironment.GetRuntimeDirectory();
CscArgs = CSharpCommandLineParser.Default.Parse(_precompilationCommandLineArgs.Arguments, _precompilationCommandLineArgs.BaseDirectory, sdkDirectory);
Diagnostics = new List<Diagnostic>(CscArgs.Errors);
// load those before anything else hooks into our AssemlbyResolve.
var loader = new PrecompilationModuleLoader(PrecompilerSection.Current);
loader.ModuleInitializationFailed += (module, ex) =>
{
Diagnostics.Add(Diagnostic.Create(
FailedToCreateModule,
Location.Create(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile, new TextSpan(), new LinePositionSpan()),
module.Type,
ex.Message));
};
var compilationModules = loader.LoadedModules;
if (Diagnostics.Any())
{
return false;
}
Encoding = CscArgs.Encoding ?? new UTF8Encoding(false); // utf8 without bom
var outputPath = Path.Combine(CscArgs.OutputDirectory, CscArgs.OutputFileName);
var pdbPath = CscArgs.PdbPath ?? Path.ChangeExtension(outputPath, ".pdb");
using (var container = CreateCompositionHost())
using (var workspace = CreateWokspace(container))
using (var peStream = new MemoryStream())
using (var pdbStream = CscArgs.EmitPdb && CscArgs.EmitOptions.DebugInformationFormat != DebugInformationFormat.Embedded ? new MemoryStream() : null)
using (var xmlDocumentationStream = !string.IsNullOrWhiteSpace(CscArgs.DocumentationPath) ? new MemoryStream() : null)
{
EmitResult emitResult = null;
var documentExtenders = workspace.Services.FindLanguageServices<IDocumentExtender>(_ => true).ToList();
var project = CreateProject(workspace, documentExtenders);
CSharpCompilation compilation = null;
CompilationWithAnalyzers compilationWithAnalyzers = null;
try
{
Diagnostics.AddRange((await Task.WhenAll(documentExtenders.Select(x => x.Complete()))).SelectMany(x => x));
compilation = await project.GetCompilationAsync(cancellationToken) as CSharpCompilation;
}
catch (Exception ex)
{
Diagnostics.Add(Diagnostic.Create(FailedToCreateCompilation, Location.None, ex));
return false;
}
var analyzers = project.AnalyzerReferences.SelectMany(x => x.GetAnalyzers(project.Language)).ToImmutableArray();
if (!analyzers.IsEmpty)
{
compilationWithAnalyzers = compilation.WithAnalyzers(analyzers, project.AnalyzerOptions, cancellationToken);
compilation = compilationWithAnalyzers.Compilation as CSharpCompilation;
}
var context = new CompileContext(compilationModules);
context.Before(new BeforeCompileContext
{
Arguments = CscArgs,
Compilation = compilation.AddSyntaxTrees(GeneratedSyntaxTrees()),
Diagnostics = Diagnostics,
});
CscArgs = context.BeforeCompileContext.Arguments;
compilation = context.BeforeCompileContext.Compilation;
var analysisTask = compilationWithAnalyzers?.GetAnalysisResultAsync(cancellationToken);
using (var win32Resources = CreateWin32Resource(compilation))
{
// PathMapping is also required here, to actually get the symbols to line up:
// https://github.com/dotnet/roslyn/blob/9d081e899b35294b8f1793d31abe5e2c43698844/src/Compilers/Core/Portable/CommandLine/CommonCompiler.cs#L616
// PathUtilities.NormalizePathPrefix is internal, but callable via the SourceFileResolver, that we set in CreateProject
var emitOptions = CscArgs.EmitOptions
.WithPdbFilePath(compilation.Options.SourceReferenceResolver.NormalizePath(pdbPath, CscArgs.BaseDirectory));
// https://github.com/dotnet/roslyn/blob/41950e21da3ac2c307fb46c2ca8c8509b5059909/src/Compilers/Core/Portable/CommandLine/CommonCompiler.cs#L437
emitResult = compilation.Emit(
peStream: peStream,
pdbStream: pdbStream,
xmlDocumentationStream: xmlDocumentationStream,
win32Resources: win32Resources,
manifestResources: CscArgs.ManifestResources,
options: emitOptions,
sourceLinkStream: TryOpenFile(CscArgs.SourceLink, out var sourceLinkStream) ? sourceLinkStream : null,
embeddedTexts: CscArgs.EmbeddedFiles.AsEnumerable()
.Select(x => TryOpenFile(x.Path, out var embeddedText) ? EmbeddedText.FromStream(x.Path, embeddedText) : null)
.Where(x => x != null),
debugEntryPoint: null,
cancellationToken: cancellationToken);
}
Diagnostics.AddRange(emitResult.Diagnostics);
try
{
var analysisResult = analysisTask == null ? null : await analysisTask;
if (analysisResult != null)
{
Diagnostics.AddRange(analysisResult.GetAllDiagnostics());
foreach (var info in analysisResult.AnalyzerTelemetryInfo)
{
Console.WriteLine($"hidden: {info.Key} {info.Value.ExecutionTime.TotalMilliseconds:#}ms");
}
}
}
catch (OperationCanceledException)
{
Console.WriteLine("warning: analysis canceled");
}
catch (Exception ex)
{
Diagnostics.Add(Diagnostic.Create(AnalysisFailed, Location.None, ex));
return false;
}
if (!emitResult.Success || HasErrors)
{
return false;
}
context.After(new AfterCompileContext
{
Arguments = CscArgs,
AssemblyStream = peStream,
Compilation = compilation,
Diagnostics = Diagnostics,
SymbolStream = pdbStream,
XmlDocStream = xmlDocumentationStream,
});
if (!HasErrors)
{
// do not create the output files if emit fails
// if the output files are there, msbuild incremental build thinks the previous build succeeded
await Task.WhenAll(
DumpToFileAsync(outputPath, peStream, cancellationToken),
DumpToFileAsync(pdbPath, pdbStream, cancellationToken),
DumpToFileAsync(CscArgs.DocumentationPath, xmlDocumentationStream, cancellationToken));
return true;
}
return false;
}
}
catch (PrecompilationModuleException pmex)
{
Diagnostics.Add(Diagnostic.Create(PrecompilationModuleFailed, Location.None, pmex.Message, pmex.InnerException));
return false;
}
catch (Exception ex)
{
Diagnostics.Add(Diagnostic.Create(UnhandledException, Location.None, ex));
return false;
}
finally
{
// strings only, since the Console.Out textwriter is another app domain...
// https://stackoverflow.com/questions/2459994/is-there-a-way-to-print-a-new-line-when-using-message
for (var i = 0; i < Diagnostics.Count; i++)
{
var d = Diagnostics[i];
if (!d.IsSuppressed && d.Severity != DiagnosticSeverity.Hidden)
{
Console.WriteLine(d.ToString().Replace("\r", "").Replace("\n", "\\n"));
}
}
}
}
private bool HasErrors => Diagnostics.Any(x => !x.IsSuppressed && x.Severity == DiagnosticSeverity.Error);
private const string WorkspaceKind = nameof(StackExchange) + "." + nameof(StackExchange.Precompilation);
// all of this is because DesktopAnalyzerAssemblyLoader needs full paths
[ExportWorkspaceService(typeof(IAnalyzerService), WorkspaceKind), Shared]
private class CompilationAnalyzerService : IAnalyzerService, IWorkspaceService
{
private readonly IAnalyzerAssemblyLoader _loader = new CompilationAnalyzerAssemblyLoader();
public IAnalyzerAssemblyLoader GetLoader() => _loader;
}
private class CompilationAnalyzerAssemblyLoader : IAnalyzerAssemblyLoader
{
private static Type DesktopAssemblyLoader = Type.GetType("Microsoft.CodeAnalysis.DesktopAnalyzerAssemblyLoader, Microsoft.CodeAnalysis.Workspaces.Desktop");
private static IAnalyzerAssemblyLoader _desktopLoader = (IAnalyzerAssemblyLoader)Activator.CreateInstance(DesktopAssemblyLoader);
private string ResolvePath(string path) => Path.IsPathRooted(path) ? path : Path.GetFullPath(path);
public void AddDependencyLocation(string fullPath) => _desktopLoader.AddDependencyLocation(ResolvePath(fullPath));
public Assembly LoadFromPath(string fullPath) => _desktopLoader.LoadFromPath(ResolvePath(fullPath));
}
private CompositionHost CreateCompositionHost()
{
var assemblies = new[]
{
"Microsoft.CodeAnalysis.Workspaces",
"Microsoft.CodeAnalysis.CSharp.Workspaces",
"Microsoft.CodeAnalysis.Workspaces.Desktop",
"StackExchange.Precompilation.MVC5",
};
var parts = new List<Type>();
foreach (var a in assemblies)
{
try
{
parts.AddRange(Assembly.Load(a)?.GetTypes() ?? Enumerable.Empty<Type>());
}
catch (ReflectionTypeLoadException thatsWhyWeCantHaveNiceThings)
{
// https://msdn.microsoft.com/en-us/library/system.reflection.assembly.gettypes(v=vs.110).aspx#Anchor_2
parts.AddRange(thatsWhyWeCantHaveNiceThings.Types.Where(x => x != null));
}
catch (FileNotFoundException nfe) when (nfe.FileName == "StackExchange.Precompilation.MVC5")
{
// enable this to be loaded dynamically
}
}
return new ContainerConfiguration()
.WithParts(parts)
.WithPart<CompilationAnalyzerService>()
.WithPart<CompilationAnalyzerAssemblyLoader>()
.CreateContainer();
}
private static AdhocWorkspace CreateWokspace(CompositionHost container)
{
var host = MefHostServices.Create(container);
// belive me, I did try DesktopMefHostServices.DefaultServices
var workspace = new AdhocWorkspace(host, WorkspaceKind);
return workspace;
}
private Project CreateProject(AdhocWorkspace workspace, List<IDocumentExtender> documentExtenders)
{
var projectInfo = CommandLineProject.CreateProjectInfo(CscArgs.OutputFileName, "C#", Environment.CommandLine, _precompilationCommandLineArgs.BaseDirectory, workspace);
projectInfo = projectInfo
.WithCompilationOptions(CscArgs.CompilationOptions
.WithSourceReferenceResolver(new SourceFileResolver(CscArgs.SourcePaths, CscArgs.BaseDirectory, CscArgs.PathMap))) // required for path mapping support
.WithDocuments(
projectInfo
.Documents
.Select(d => documentExtenders.Aggregate(d, (doc, ex) => ex.Extend(doc))));
return workspace.AddProject(projectInfo);
}
private bool TryOpenFile(string path, out Stream stream)
{
stream = null;
if (string.IsNullOrEmpty(path))
{
return false;
}
if (!File.Exists(path))
{
Diagnostics.Add(Diagnostic.Create(ERR_FileNotFound, null, path));
return false;
}
try
{
stream = File.OpenRead(path);
return true;
}
catch (Exception ex)
{
Diagnostics.Add(Diagnostic.Create(ERR_NoSourceFile, null, path, ex.Message));
return false;
}
}
private Stream CreateWin32Resource(CSharpCompilation compilation)
{
if (TryOpenFile(CscArgs.Win32ResourceFile, out var stream)) return stream;
using (var manifestStream = compilation.Options.OutputKind != OutputKind.NetModule && TryOpenFile(CscArgs.Win32Manifest, out var manifest) ? manifest : null)
using (var iconStream = TryOpenFile(CscArgs.Win32Icon, out var icon) ? icon : null)
return compilation.CreateDefaultWin32Resources(true, CscArgs.NoWin32Manifest, manifestStream, iconStream);
}
private static async Task DumpToFileAsync(string path, MemoryStream stream, CancellationToken cancellationToken)
{
if (stream?.Length > 0)
{
stream.Position = 0;
using (var file = File.Create(path))
using (cancellationToken.Register(() => { try { File.Delete(path); } catch { } }))
{
await stream.CopyToAsync(file, 4096, cancellationToken);
}
}
}
private sealed class NaiveReferenceResolver : MetadataReferenceResolver
{
private NaiveReferenceResolver() { }
public static NaiveReferenceResolver Instance { get; } = new NaiveReferenceResolver();
public override bool Equals(object other) => other is NaiveReferenceResolver;
public override int GetHashCode() => 42;
public override ImmutableArray<PortableExecutableReference> ResolveReference(string reference, string baseFilePath, MetadataReferenceProperties properties)
=> ImmutableArray.Create(MetadataReference.CreateFromFile(reference, properties));
}
private IEnumerable<SyntaxTree> GeneratedSyntaxTrees()
{
yield return SyntaxFactory.ParseSyntaxTree($"[assembly: {typeof(CompiledFromDirectoryAttribute).FullName}(@\"{CurrentDirectory.FullName}\")]", CscArgs.ParseOptions);
}
public Location AsLocation(string path)
{
return Location.Create(path, new TextSpan(), new LinePositionSpan());
}
}
public interface IDocumentExtender : ILanguageService
{
DocumentInfo Extend(DocumentInfo document);
Task<ICollection<Diagnostic>> Complete();
}
}
================================================
FILE: StackExchange.Precompilation.Build/CompilationAssemblyResolver.cs
================================================
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
namespace StackExchange.Precompilation
{
class CompilationAssemblyResolver : MarshalByRefObject
{
internal static void Register(AppDomain domain, string[] references)
{
CompilationAssemblyResolver resolver =
domain.CreateInstanceFromAndUnwrap(
Assembly.GetExecutingAssembly().Location,
typeof(CompilationAssemblyResolver).FullName) as CompilationAssemblyResolver;
resolver.RegisterDomain(domain);
resolver.Setup(references);
}
private AppDomain domain;
private readonly ConcurrentDictionary<string, Lazy<Assembly>> resolvedAssemblies = new ConcurrentDictionary<string, Lazy<Assembly>>();
private void Setup(string[] references)
{
void Resolve(AssemblyName name, Func<Assembly> loader)
{
var resolved = new Lazy<Assembly>(loader, LazyThreadSafetyMode.ExecutionAndPublication);
var keyName = new AssemblyName(ApplyPolicy(name.FullName));
resolvedAssemblies.AddOrUpdate(keyName.FullName, resolved, (key, existing) => existing); // TODO log conflicting binds?
resolvedAssemblies.AddOrUpdate(keyName.Name, resolved, (key, existing) => existing); // TODO log conflicting partial binds?
}
// load runtime references from tools/*.dll
var location = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
Directory.EnumerateFiles(location, "*.dll")
.AsParallel()
.ForAll(dll =>
{
try
{
var assemblyName = AssemblyName.GetAssemblyName(dll);
Resolve(assemblyName, () => Assembly.LoadFile(dll));
}
catch (Exception ex)
{
Console.WriteLine("hidden: failed to resolve assembly {0}: {1}", dll, ex.Message);
}
});
// load all the other references
references
.AsParallel()
.Select(x =>
{
try
{
return AssemblyName.GetAssemblyName(x);
}
catch (Exception ex)
{
Console.WriteLine($"warning: Couldn't load reference from '{x}' - '{ex.Message}'");
return null;
}
})
.Where(x => x != null)
.ForAll(name => Resolve(name, () =>
{
var path = new Uri(name.CodeBase).LocalPath;
try
{
return Assembly.LoadFile(path);
}
catch (Exception ex)
{
Console.WriteLine($"warning: Couldn't load reference '{name.FullName}' from '{path}' - '{ex.Message}'");
return null;
}
}));
}
private void RegisterDomain(AppDomain domain)
{
this.domain = domain;
this.domain.AssemblyResolve += ResolveAssembly;
}
private string ApplyPolicy(string name)
{
while (true) {
var newName = domain.ApplyPolicy(name);
if (newName == name) return name;
name = newName;
}
}
private Assembly ResolveAssembly(object sender, ResolveEventArgs e)
{
var name = ApplyPolicy(e.Name);
var assemblyName = new AssemblyName(name);
return resolvedAssemblies.GetOrAdd(assemblyName.FullName, NullAssembly).Value ??
resolvedAssemblies.GetOrAdd(assemblyName.Name, NullAssembly).Value;
}
private static Lazy<Assembly> NullAssembly(string key) => new Lazy<Assembly>(() => null, LazyThreadSafetyMode.ExecutionAndPublication);
}
}
================================================
FILE: StackExchange.Precompilation.Build/CompilationProxy.cs
================================================
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
namespace StackExchange.Precompilation
{
class CompilationProxy : MarshalByRefObject
{
public static bool RunCs(string[] args)
{
var precompilationArgs = PrecompilationCommandLineParser.Parse(args, Directory.GetCurrentDirectory());
CompilationProxy proxy = null;
AppDomain compilationDomain = null;
try
{
var currentSetup = AppDomain.CurrentDomain.SetupInformation;
var setup = new AppDomainSetup()
{
ApplicationName = currentSetup.ApplicationName,
ApplicationBase = currentSetup.ApplicationBase,
ConfigurationFile = precompilationArgs.AppConfig,
DisallowBindingRedirects = true,
};
if (setup.ConfigurationFile == null)
{
setup.ConfigurationFile = new[] { "app.config", "web.config" }.Select(x => Path.Combine(precompilationArgs.BaseDirectory, x)).FirstOrDefault(File.Exists);
if (!string.IsNullOrWhiteSpace(setup.ConfigurationFile))
{
Console.WriteLine("WARNING: '" + setup.ConfigurationFile + "' used as fallback config file");
}
}
compilationDomain = AppDomain.CreateDomain(
AppDomainHelper.CsCompilationAppDomainName,
AppDomain.CurrentDomain.Evidence,
setup);
compilationDomain.UnhandledException += (s, e) =>
{
Console.WriteLine("error: " + e);
};
var references = precompilationArgs.References; //.Concat(Directory.EnumerateFiles(AppDomain.CurrentDomain.BaseDirectory).Where(r => assemblyExt.Contains(Path.GetExtension(r)))).ToArray()
CompilationAssemblyResolver.Register(compilationDomain, references);
proxy = (CompilationProxy)compilationDomain.CreateInstanceAndUnwrap(
typeof(CompilationProxy).Assembly.FullName,
typeof(CompilationProxy).FullName);
Console.CancelKeyPress += (s, e) => proxy?.ForceStop();
return proxy.RunCs(precompilationArgs);
}
finally
{
proxy?.ForceStop();
// runtime has exited, finish off by unloading the runtime appdomain
if (compilationDomain != null) AppDomain.Unload(compilationDomain);
}
}
public override object InitializeLifetimeService() => null;
private CancellationTokenSource _cts;
// ReSharper disable MemberCanBeMadeStatic.Local
// making the methods below static would not be a good idea, they need to run in the _compilation app domain
private bool RunCs(PrecompilationCommandLineArgs precompilationArgs)
{
_cts = new CancellationTokenSource();
return new Compilation(precompilationArgs).RunAsync(_cts.Token).Result;
}
private void ForceStop()
{
var cts = _cts;
_cts = null;
cts?.Cancel();
cts?.Dispose();
}
}
}
================================================
FILE: StackExchange.Precompilation.Build/ICompilationProxy.cs
================================================
namespace StackExchange.Precompilation
{
interface ICompilationProxy
{
object InitializeLifetimeService();
}
}
================================================
FILE: StackExchange.Precompilation.Build/PrecompilationCommandLineArgs.cs
================================================
using System;
namespace StackExchange.Precompilation
{
[Serializable]
public class PrecompilationCommandLineArgs : MarshalByRefObject
{
/// <summary>
/// Unprocessed arguments.
/// </summary>
public string[] Arguments { get; set; }
/// <summary>
/// The current directory in which the compilation was started.
/// </summary>
public string BaseDirectory { get; set; }
/// <summary>
/// The value of the /appconfig switch if present.
/// </summary>
public string AppConfig { get; set; }
/// <summary>
/// The values of the /reference switches.
/// </summary>
public string[] References { get; set; }
}
}
================================================
FILE: StackExchange.Precompilation.Build/PrecompilationCommandLineParser.cs
================================================
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
namespace StackExchange.Precompilation
{
// we need the values of the /reference and the /appconfig switches before we spin up the app domain
// to get those we need to either spin up a new AppDomain and load Microsoft.CodeAnalysis.CSharp to use CSharpCommandLineParser or parse the args ourselves
// https://msdn.microsoft.com/en-us/library/78f4aasd.aspx
public class PrecompilationCommandLineParser
{
private static readonly Regex UnespacedBackslashes = new Regex(@"(?!\\+"")\\+", RegexOptions.Compiled);
private static readonly Regex QuotesAfterSingleBackSlash = new Regex(@"(?<=(^|[^\\])((\\\\)+)?)""", RegexOptions.ExplicitCapture | RegexOptions.Compiled);
private static readonly Regex Escaped = new Regex(@"\\(\\|"")", RegexOptions.Compiled);
public static string[] SplitCommandLine(string commandLine)
{
return Split(commandLine)
.TakeWhile(arg => !arg.StartsWith("#", StringComparison.Ordinal))
.Select(dirty => UnespacedBackslashes.Replace(dirty, "$0$0"))
.Select(normalized => QuotesAfterSingleBackSlash.Replace(normalized, ""))
.Select(unquoted => Escaped.Replace(unquoted, "$1"))
.Where(arg => !string.IsNullOrEmpty(arg))
.Select(str => str.Trim())
.ToArray();
}
private static IEnumerable<string> Split(string commandLine)
{
var isQuoted = false;
var backslashCount = 0;
var splitIndex = 0;
var length = commandLine.Length;
for (var i = 0; i < length; i++)
{
var c = commandLine[i];
switch (c)
{
case '\\':
backslashCount += 1;
break;
case '\"':
if (backslashCount % 2 == 0) isQuoted = !isQuoted;
goto default;
case ' ':
case '\t':
case '\n':
case '\r':
if (!isQuoted)
{
var take = i - splitIndex;
if (take > 0)
{
yield return commandLine.Substring(splitIndex, take);
}
splitIndex = i + 1;
}
goto default;
default:
backslashCount = 0;
break;
}
}
if (splitIndex < length)
{
yield return commandLine.Substring(splitIndex);
}
}
private static readonly Regex Reference = new Regex(@"/r(eference)?:(?<alias>[\w_]+=)?", RegexOptions.IgnoreCase | RegexOptions.Compiled);
public static PrecompilationCommandLineArgs Parse(string[] arguments, string baseDirectory)
{
var result = new PrecompilationCommandLineArgs { Arguments = arguments, BaseDirectory = baseDirectory };
if (arguments == null) return result;
var loadedRsp = new HashSet<string>();
var references = new HashSet<string>();
for(var i = 0; i < arguments.Length; i++)
{
var arg = arguments[i];
var reference = Reference.Match(arg);
if(arg.StartsWith("@"))
{
if (!loadedRsp.Add(arg = ParseFileFromArg(arg, '@'))) continue;
arguments = arguments.Concat(File.ReadAllLines(arg).SelectMany(SplitCommandLine)).ToArray();
}
else if(reference.Success)
{
// don't care about reference aliases in the compilation appdomain
// https://msdn.microsoft.com/en-us/library/ms173212.aspx
references.Add(ParseFileFromArg(arg, reference.Groups["alias"].Success ? '=' : ':'));
}
else if(arg.StartsWith("/appconfig:"))
{
result.AppConfig = ParseFileFromArg(arg);
}
}
result.References = references.ToArray();
return result;
}
private static string ParseFileFromArg(string arg, char delimiter = ':')
{
return Path.GetFullPath(arg.Substring(arg.IndexOf(delimiter) + 1));
}
}
}
================================================
FILE: StackExchange.Precompilation.Build/Program.cs
================================================
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.CodeAnalysis.CSharp;
namespace StackExchange.Precompilation
{
static class Program
{
static void Main(string[] args)
{
try
{
if (!CompilationProxy.RunCs(args))
{
Environment.ExitCode = 1;
}
}
catch (Exception ex)
{
var agg = ex as AggregateException;
Console.WriteLine("ERROR: An unhandled exception occured");
if (agg != null)
{
agg = agg.Flatten();
foreach (var inner in agg.InnerExceptions)
{
Console.Error.WriteLine("error: " + inner);
}
}
else
{
Console.Error.WriteLine("error: " + ex);
}
Environment.ExitCode = 2;
}
}
}
}
================================================
FILE: StackExchange.Precompilation.Build/StackExchange.Precompilation.Build.csproj
================================================
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net462</TargetFramework>
<AssemblyName>StackExchange.Precompiler</AssemblyName>
<Description>Replaces CSC and aspnet_compiler.exe with StackExchange.Precompiler for compiling C# (.cs) and Razor View (.cshtml) files in asp.net mvc 5 projects.</Description>
<IsTool>true</IsTool>
<IsPackable>true</IsPackable>
<PackageId>StackExchange.Precompilation.Build</PackageId>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<BeforePack>_ToolsSetup;$(BeforePack)</BeforePack>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\StackExchange.Precompilation\StackExchange.Precompilation.csproj">
<Project>{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</Project>
<Name>StackExchange.Precompilation</Name>
</ProjectReference>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="2.10.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.DiaSymReader.Native" Version="1.7.0" PrivateAssets="all" />
</ItemGroup>
<Target Name="_ToolsSetup">
<ItemGroup>
<_BinOutputs Include="bin\$(Configuration)\$(TargetFramework)\*.*" />
<None Include="@(_BinOutputs)" Pack="true" PackagePath="tools\%(Filename)%(Extension)" Condition="'%(Extension)' == '.dll' or '%(Extension)' == '.pdb' or '%(Extension)' == '.config'" />
<None Include="*.targets" Pack="true" PackagePath="build" />
</ItemGroup>
</Target>
</Project>
================================================
FILE: StackExchange.Precompilation.Build/StackExchange.Precompilation.Build.packages.config
================================================
<!--
HACK
We need to include the native DiaSymReader Native runtime files in order to support sourcelink etc.
Roslyn does it too: https://github.com/dotnet/roslyn/blob/1fe72cd3f196005a1a407c582f60145d096b2f43/src/Compilers/Core/Portable/Microsoft.CodeAnalysis.csproj#L26-L37
We make build/Microsoft.DiaSymRerader.Native.props from the package do it, via the existance of this dummy packages.config file.
-->
================================================
FILE: StackExchange.Precompilation.Build/StackExchange.Precompilation.Build.targets
================================================
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<!-- CREDITS:
https://razorgenerator.codeplex.com/SourceControl/latest#RazorGenerator.MsBuild/RazorGenerator.MsBuild.targets
http://www.nuget.org/packages/Microsoft.Net.ToolsetCompilers -> /tools/Microsoft.Net.ToolsetCompilers.props
-->
<SEPrecompilerSkip Condition="'$(SEPrecompilerSkip)' == ''">false</SEPrecompilerSkip>
<SEPrecompilerIncludeRazor Condition="'$(SEPrecompilerIncludeRazor)' == ''">false</SEPrecompilerIncludeRazor>
<CompileDependsOn>
$(CompileDependsOn);
SEPrecompilerCore;
</CompileDependsOn>
<SEPrecompilerTools>$(MSBuildThisFileDirectory)..\tools</SEPrecompilerTools>
<UseAppConfigForCompiler Condition="'$(UseAppConfigForCompiler)' == '' and '$(SEPrecompilerSkip)' != 'true'">true</UseAppConfigForCompiler>
</PropertyGroup>
<Target Name="SEPrecompilerSetup">
<PropertyGroup>
<SEPrecompilerPath Condition="'$(SEPrecompilerPath)' == ''">$(SEPrecompilerTools)</SEPrecompilerPath>
<SEPrecompilerCscToolPath>$(SEPrecompilerPath)</SEPrecompilerCscToolPath>
<SEPrecompilerCscToolExe>StackExchange.Precompiler.exe</SEPrecompilerCscToolExe>
</PropertyGroup>
</Target>
<Target Name="SEPrecompilerCore"
BeforeTargets="CoreCompile"
AfterTargets="AfterResolveReferences"
Condition="'$(BuildingProject)' == 'true' and '$(SEPrecompilerSkip)' != 'true'"
DependsOnTargets="SEPrecompilerSetup">
<PropertyGroup>
<CscToolPath>$(SEPrecompilerCscToolPath)</CscToolPath>
<CscToolExe>$(SEPrecompilerCscToolExe)</CscToolExe>
</PropertyGroup>
<ItemGroup>
<Compile Include="@(Content)" Condition="'$(SEPrecompilerIncludeRazor)' == 'true' and '%(Extension)' == '.cshtml'" />
<Compile Include="@(None)" Condition="'$(SEPrecompilerIncludeRazor)' == 'true' and '%(Extension)' == '.cshtml'" />
</ItemGroup>
</Target>
</Project>
================================================
FILE: StackExchange.Precompilation.Tests/CommandLineTests.cs
================================================
using System;
using System.IO;
using System.Linq;
using NUnit.Framework;
namespace StackExchange.Precompilation.Tests
{
[TestFixture]
public class CommandLineTests
{
// test cases from https://github.com/dotnet/roslyn/blob/9c66e81c1424d8f4999f70eb8b85f0e76f253c30/src/Compilers/Core/CodeAnalysisTest/CommonCommandLineParserTests.cs#L83
[Test]
[TestCase("", new string[0])]
[TestCase(" \t ", new string[0])]
[TestCase(" abc\tdef baz quuz ", new[] { "abc", "def", "baz", "quuz" })]
[TestCase(@" ""abc def"" fi""ddle dee de""e ""hi there ""dude he""llo there"" ", new [] { @"abc def", @"fiddle dee dee", @"hi there dude", @"hello there" })]
[TestCase(@" ""abc def \"" baz quuz"" ""\""straw berry"" fi\""zz \""buzz fizzbuzz", new [] { @"abc def "" baz quuz", @"""straw berry", @"fi""zz", @"""buzz", @"fizzbuzz" })]
[TestCase(@" \\""abc def"" \\\""abc def"" ", new [] { @"\abc def", @"\""abc", @"def" })]
[TestCase(@" \\\\""abc def"" \\\\\""abc def"" ", new [] { @"\\abc def", @"\\""abc", @"def" })]
[TestCase(@" \\\\""abc def"" \\\\\""abc def"" q a r ", new [] { @"\\abc def", @"\\""abc", @"def q a r" })]
[TestCase(@"abc #Comment ignored", new [] { @"abc" })]
public static void SplitArguments(string input, string[] expected)
{
var actual = PrecompilationCommandLineParser.SplitCommandLine(input);
CollectionAssert.AreEqual(expected, actual);
}
[Test]
public void ParseArguments()
{
Assert.DoesNotThrow(() => PrecompilationCommandLineParser.Parse(null, null));
Assert.DoesNotThrow(() => PrecompilationCommandLineParser.Parse(new string[0], null));
Assert.DoesNotThrow(() => PrecompilationCommandLineParser.Parse(null, ""));
Assert.DoesNotThrow(() => PrecompilationCommandLineParser.Parse(new string[0], ""));
}
[Test]
[TestCase("a b c", new string[0], (string)null)]
[TestCase("a b /r:c.dll", new[] { "c.dll" }, (string)null)]
[TestCase("a b /r:a=c.dll", new[] { "c.dll" }, (string)null)]
[TestCase("a b /reference:a=c.dll", new[] { "c.dll" }, (string)null)]
[TestCase("a b /r:c.dll /r:d.dll", new[] { "c.dll", "d.dll" }, (string)null)]
[TestCase("a b /r:c.dll /appconfig:moar.config /r:d.dll", new[] { "c.dll", "d.dll" }, "moar.config")]
[TestCase("a b /r:alias=c.dll /appconfig:moar.config /reference:d.dll", new[] { "c.dll", "d.dll" }, "moar.config")]
public void ParseArgumentCases(string cmdline, string[] references, string appconfig)
{
var dir = Guid.NewGuid().ToString();
var args = PrecompilationCommandLineParser.SplitCommandLine(cmdline);
var parsed = PrecompilationCommandLineParser.Parse(args, dir);
Func<string, string> resolvePath = Path.GetFullPath;
Assert.AreEqual(dir, parsed.BaseDirectory);
Assert.AreEqual(appconfig == null ? null : resolvePath(appconfig), parsed.AppConfig);
CollectionAssert.AreEqual(references.Select(resolvePath), parsed.References);
}
}
}
================================================
FILE: StackExchange.Precompilation.Tests/StackExchange.Precompilation.Tests.csproj
================================================
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net462</TargetFramework>
<Platform>x86</Platform>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
<PackageReference Include="NUnit" Version="3.11.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.11.2" />
<ProjectReference Include="..\StackExchange.Precompilation.Build\StackExchange.Precompilation.Build.csproj">
<Project>{31DFCCCC-2F44-405E-A2D7-BB1AC718E7B9}</Project>
<Name>StackExchange.Precompilation.Build</Name>
</ProjectReference>
</ItemGroup>
</Project>
================================================
FILE: StackExchange.Precompilation.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27428.2015
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StackExchange.Precompilation.Build", "StackExchange.Precompilation.Build\StackExchange.Precompilation.Build.csproj", "{31DFCCCC-2F44-405E-A2D7-BB1AC718E7B9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StackExchange.Precompilation", "StackExchange.Precompilation\StackExchange.Precompilation.csproj", "{3C0A90F1-B19E-4305-AB71-3CD31C7D0F4D}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{5958EFE5-C8D6-4759-9A8E-8C64558314FD}"
ProjectSection(SolutionItems) = preProject
.nuget\NuGet.Config = .nuget\NuGet.Config
.nuget\NuGet.exe = .nuget\NuGet.exe
.nuget\NuGet.targets = .nuget\NuGet.targets
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test.Module", "Test.Module\Test.Module.csproj", "{5FCAECC3-787B-473F-A372-783D0C235190}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test.ConsoleApp", "Test.ConsoleApp\Test.ConsoleApp.csproj", "{BA716DA2-4E3C-4D9F-B9C2-78C0EAEF66D7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test.WebApp", "Test.WebApp\Test.WebApp.csproj", "{5B0105A4-256B-4A88-852C-6F5E9D185515}"
ProjectSection(ProjectDependencies) = postProject
{31DFCCCC-2F44-405E-A2D7-BB1AC718E7B9} = {31DFCCCC-2F44-405E-A2D7-BB1AC718E7B9}
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A6462B41-5067-4F2B-B5B8-B7BD1B2D75CB}"
ProjectSection(SolutionItems) = preProject
BuildAndPack.ps1 = BuildAndPack.ps1
PrepareForPack.ps1 = PrepareForPack.ps1
semver.txt = semver.txt
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StackExchange.Precompilation.Tests", "StackExchange.Precompilation.Tests\StackExchange.Precompilation.Tests.csproj", "{B6306D9B-0770-44DF-AADE-5703B1DCFD67}"
ProjectSection(ProjectDependencies) = postProject
{C8F659BD-D0D1-4404-9CC5-3F14ED4B28F3} = {C8F659BD-D0D1-4404-9CC5-3F14ED4B28F3}
{3C0A90F1-B19E-4305-AB71-3CD31C7D0F4D} = {3C0A90F1-B19E-4305-AB71-3CD31C7D0F4D}
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test.WebApp.ExternalViews", "Test.WebApp.ExternalViews\Test.WebApp.ExternalViews.csproj", "{2BA24772-F7B0-4652-A430-2F4C2262E882}"
ProjectSection(ProjectDependencies) = postProject
{5FCAECC3-787B-473F-A372-783D0C235190} = {5FCAECC3-787B-473F-A372-783D0C235190}
{31DFCCCC-2F44-405E-A2D7-BB1AC718E7B9} = {31DFCCCC-2F44-405E-A2D7-BB1AC718E7B9}
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StackExchange.Precompilation.MVC5", "StackExhcange.Precompilation.MVC5\StackExchange.Precompilation.MVC5.csproj", "{C8F659BD-D0D1-4404-9CC5-3F14ED4B28F3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{31DFCCCC-2F44-405E-A2D7-BB1AC718E7B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{31DFCCCC-2F44-405E-A2D7-BB1AC718E7B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{31DFCCCC-2F44-405E-A2D7-BB1AC718E7B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{31DFCCCC-2F44-405E-A2D7-BB1AC718E7B9}.Release|Any CPU.Build.0 = Release|Any CPU
{3C0A90F1-B19E-4305-AB71-3CD31C7D0F4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3C0A90F1-B19E-4305-AB71-3CD31C7D0F4D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3C0A90F1-B19E-4305-AB71-3CD31C7D0F4D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3C0A90F1-B19E-4305-AB71-3CD31C7D0F4D}.Release|Any CPU.Build.0 = Release|Any CPU
{5FCAECC3-787B-473F-A372-783D0C235190}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5FCAECC3-787B-473F-A372-783D0C235190}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5FCAECC3-787B-473F-A372-783D0C235190}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5FCAECC3-787B-473F-A372-783D0C235190}.Release|Any CPU.Build.0 = Release|Any CPU
{BA716DA2-4E3C-4D9F-B9C2-78C0EAEF66D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BA716DA2-4E3C-4D9F-B9C2-78C0EAEF66D7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BA716DA2-4E3C-4D9F-B9C2-78C0EAEF66D7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BA716DA2-4E3C-4D9F-B9C2-78C0EAEF66D7}.Release|Any CPU.Build.0 = Release|Any CPU
{5B0105A4-256B-4A88-852C-6F5E9D185515}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5B0105A4-256B-4A88-852C-6F5E9D185515}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5B0105A4-256B-4A88-852C-6F5E9D185515}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5B0105A4-256B-4A88-852C-6F5E9D185515}.Release|Any CPU.Build.0 = Release|Any CPU
{B6306D9B-0770-44DF-AADE-5703B1DCFD67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B6306D9B-0770-44DF-AADE-5703B1DCFD67}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B6306D9B-0770-44DF-AADE-5703B1DCFD67}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B6306D9B-0770-44DF-AADE-5703B1DCFD67}.Release|Any CPU.Build.0 = Release|Any CPU
{2BA24772-F7B0-4652-A430-2F4C2262E882}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2BA24772-F7B0-4652-A430-2F4C2262E882}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2BA24772-F7B0-4652-A430-2F4C2262E882}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2BA24772-F7B0-4652-A430-2F4C2262E882}.Release|Any CPU.Build.0 = Release|Any CPU
{C8F659BD-D0D1-4404-9CC5-3F14ED4B28F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C8F659BD-D0D1-4404-9CC5-3F14ED4B28F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C8F659BD-D0D1-4404-9CC5-3F14ED4B28F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C8F659BD-D0D1-4404-9CC5-3F14ED4B28F3}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {153D37EE-CF3F-42D8-9703-EE953797B3A9}
EndGlobalSection
EndGlobal
================================================
FILE: StackExhcange.Precompilation.MVC5/Hacks.cs
================================================
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System;
using System.Reflection;
using System.Web.Mvc;
namespace StackExchange.Precompilation
{
static class Hacks
{
private static readonly Action<WebViewPage, string> WebViewPage_OverridenLayoutPathSetter =
(Action<WebViewPage, string>)typeof(WebViewPage)
.GetProperty("OverridenLayoutPath", BindingFlags.Instance | BindingFlags.NonPublic)
.SetMethod
.CreateDelegate(typeof(Action<WebViewPage, string>));
/// <summary>
/// Sets the WebViewPage.OverridenLayoutPath internal property, the only way to handle
/// <see cref="ViewResult.MasterName" /> values.
/// </summary>
/// <remarks>
/// Using reflection to get a mis-spelled internal property setter and calling it via reflection.
/// What could possibly go wrong?
/// </remarks>
public static void SetOverriddenLayoutPath(WebViewPage webViewPage, string overridenLayoutPath) =>
WebViewPage_OverridenLayoutPathSetter.Invoke(webViewPage, overridenLayoutPath);
/// <summary>
/// Bear with me, so, in case a the view engine is being executed in a page targeting net45+ (including net46*)
/// on a system that has net47+ installed, mscorlib contained referenced by BuildManager already
/// contains ValueTuple, but due to this package referencing CodeAnalysis.Common, which also pulls in
/// the System.ValueTuple package, that gets copied to /bin, and is therefore also picked up as a
/// reference in build manager.
/// This causes compilation.GetTypeByMetadataName("System.ValueTuple`2") to return null due to an
/// ambigous match, resulting in the lovely CS8137 and CS8179 warnings, at runtime.
/// The contents of the /bin directory get included due to the default <![CDATA[<add name="*" />]]> entry.
/// <![CDATA[<remove name="*" />]]> doesn't work since it fails to load the assembly generated for global.asax.cs
/// <![CDATA[<remove name="System.ValueTuple" />]]> doesn't work, since the wildcard takes preference
/// https://referencesource.microsoft.com/#System.Web/Configuration/CompilationSection.cs,119d7e4aae57b4b6
/// <para />
/// So when this is the case, we need to remove the reference to the System.ValueTuple.dll
/// </summary>
/// <param name="compilation"></param>
/// <returns></returns>
public static CSharpCompilation MakeValueTuplesWorkWhenRunningOn47RuntimeAndTargetingNet45Plus(CSharpCompilation compilation)
{
var mscorlibAssembly = typeof(object).Assembly;
var valueTupleAssembly = typeof(ValueTuple).Assembly;
if (mscorlibAssembly != valueTupleAssembly &&
compilation.GetAssemblyOrModuleSymbol(RoslynRazorViewEngine.ResolveReference(mscorlibAssembly)) is IAssemblySymbol mscorlib)
{
compilation = compilation.RemoveReferences(RoslynRazorViewEngine.ResolveReference(valueTupleAssembly));
}
return compilation;
}
}
}
================================================
FILE: StackExhcange.Precompilation.MVC5/PrecompilationView.cs
================================================
using System;
using System.Web.Mvc;
using System.Web.WebPages;
namespace StackExchange.Precompilation
{
internal class PrecompilationView : IView
{
private readonly string _virtualPath;
private readonly string _masterPath;
private readonly Type _viewType;
private readonly ProfiledVirtualPathProviderViewEngine _viewEngine;
private readonly bool _runViewStart;
public PrecompilationView(string virtualPath, string masterPath, Type viewType, bool runViewStart, ProfiledVirtualPathProviderViewEngine viewEngine)
{
_virtualPath = virtualPath;
_masterPath = masterPath;
_viewType = viewType;
_runViewStart = runViewStart;
_viewEngine = viewEngine;
}
private WebPageBase CreatePage(ViewContext viewContext, System.IO.TextWriter writer, out WebPageContext pageContext, out WebPageRenderingBase startPage)
{
var basePage = (WebPageBase)Activator.CreateInstance(_viewType);
basePage.VirtualPath = _virtualPath;
basePage.VirtualPathFactory = _viewEngine.VirtualPathFactory;
pageContext = new WebPageContext(viewContext.HttpContext, basePage, viewContext.ViewData?.Model);
startPage = _runViewStart
? StartPage.GetStartPage(basePage, "_ViewStart", _viewEngine.FileExtensions)
: null;
var viewPage = basePage as WebViewPage;
if (viewPage != null)
{
if (!string.IsNullOrEmpty(_masterPath))
{
Hacks.SetOverriddenLayoutPath(viewPage, _masterPath);
}
viewPage.ViewContext = viewContext;
viewPage.ViewData = viewContext.ViewData;
viewPage.InitHelpers();
}
return basePage;
}
public void Render(ViewContext viewContext, System.IO.TextWriter writer)
{
using (_viewEngine.DoProfileStep("Render"))
{
var webViewPage = CreatePage(viewContext, writer, out var pageContext, out var startPage);
using (_viewEngine.DoProfileStep("ExecutePageHierarchy"))
{
webViewPage.ExecutePageHierarchy(pageContext, writer, startPage);
}
}
}
}
}
================================================
FILE: StackExhcange.Precompilation.MVC5/PrecompilationVirtualPathFactory.cs
================================================
using System;
using System.Web.WebPages;
namespace StackExchange.Precompilation
{
/// <summary>
/// <see cref="WebPageExecutingBase.VirtualPathFactory"/> is used for resolving virtual paths once a view has
/// been resolved. Setting it to an <see cref="IVirtualPathFactory"/> assumes that all underlying virtual paths
/// are resolvable (layouts partials etc) are resolvable using the given instance. This can lead to some side
/// effect when different view engines are combined, and the matching views are intermixed.
/// </summary>
/// <remarks>
/// This is our version of the <see cref="VirtualPathFactoryManager"/>, which is meant for extending the pipeline,
/// mentioned above, but is not extendable in the sense that it always falls back to <see cref="System.Web.Compilation.BuildManager"/>,
/// which calls the old csc.exe in the framework dir, not the shiny one from our nuget package,
/// and can thus cause unexpected behavior at runtime.
/// </remarks>
internal class PrecompilationVirtualPathFactory : IVirtualPathFactory
{
private readonly PrecompiledViewEngine _precompiled;
private readonly RoslynRazorViewEngine _runtime;
public PrecompilationVirtualPathFactory(PrecompiledViewEngine precompiled = null, RoslynRazorViewEngine runtime = null)
{
_precompiled = precompiled;
_runtime = runtime;
}
public object CreateInstance(string virtualPath)
{
if (_precompiled?.TryLookupCompiledType(virtualPath) is Type precompiledType)
{
return Activator.CreateInstance(precompiledType);
}
else if (_runtime?.GetTypeFromVirtualPath(virtualPath) is Type runtimeType)
{
return Activator.CreateInstance(runtimeType);
}
else
{
return null;
}
}
public bool Exists(string virtualPath)
{
if (_precompiled?.TryLookupCompiledType(virtualPath) != null)
{
return true;
}
else if (_runtime?.FileExists(virtualPath) == true)
{
return true;
}
else
{
return false;
}
}
}
}
================================================
FILE: StackExhcange.Precompilation.MVC5/PrecompiledViewEngine.cs
================================================
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.WebPages;
namespace StackExchange.Precompilation
{
/// <summary>
/// Supports loading of precompiled views.
/// </summary>
public class PrecompiledViewEngine : ProfiledVirtualPathProviderViewEngine
{
/// <summary>
/// Gets the view paths
/// </summary>
public IEnumerable<string> ViewPaths { get; private set; }
private readonly Dictionary<string, Type> _views;
/// <summary>
/// Creates a new PrecompiledViewEngine instance, scanning all assemblies in <paramref name="findAssembliesInPath"/> for precompiled views.
/// Precompiled views are types deriving from <see cref="WebPageRenderingBase"/> decorated with a <see cref="CompiledFromFileAttribute" />
/// </summary>
/// <param name="findAssembliesInPath">The path to scan for assemblies with precompiled views.</param>
/// <remarks>
/// Use this constructor if you use aspnet_compiler.exe with it's targetDir parameter instead of StackExchange.Precompilation.Build.
/// </remarks>
public PrecompiledViewEngine(string findAssembliesInPath)
: this(FindViewAssemblies(findAssembliesInPath).ToArray())
{
}
/// <summary>
/// Creates a new PrecompiledViewEngine instance, scanning the provided <paramref name="assemblies"/> for precompiled views.
/// Precompiled views are types deriving from <see cref="WebPageRenderingBase"/> decorated with a <see cref="CompiledFromFileAttribute" />
/// </summary>
/// <param name="assemblies">The assemblies to scan for precompiled views.</param>
public PrecompiledViewEngine(params Assembly[] assemblies)
{
AreaViewLocationFormats = new[]
{
"~/Areas/{2}/Views/{1}/{0}.cshtml",
"~/Areas/{2}/Views/Shared/{0}.cshtml",
};
AreaMasterLocationFormats = new[]
{
"~/Areas/{2}/Views/{1}/{0}.cshtml",
"~/Areas/{2}/Views/Shared/{0}.cshtml",
};
AreaPartialViewLocationFormats = new[]
{
"~/Areas/{2}/Views/{1}/{0}.cshtml",
"~/Areas/{2}/Views/Shared/{0}.cshtml",
};
FileExtensions = new[]
{
"cshtml",
};
MasterLocationFormats = new[]
{
"~/Views/{1}/{0}.cshtml",
"~/Views/Shared/{0}.cshtml",
};
PartialViewLocationFormats = new[]
{
"~/Views/{1}/{0}.cshtml",
"~/Views/Shared/{0}.cshtml",
};
ViewLocationFormats = new[]
{
"~/Views/{1}/{0}.cshtml",
"~/Views/Shared/{0}.cshtml",
};
_views = new Dictionary<string, Type>(StringComparer.InvariantCultureIgnoreCase);
foreach (var asm in assemblies)
{
// https://msdn.microsoft.com/en-us/library/system.reflection.assembly.gettypes(v=vs.110).aspx#Anchor_2
Type[] asmTypes;
try
{
asmTypes = asm.GetTypes();
}
catch (ReflectionTypeLoadException thatsWhyWeCantHaveNiceThings)
{
asmTypes = thatsWhyWeCantHaveNiceThings.Types;
}
var viewTypes = asmTypes.Where(t => typeof(WebPageRenderingBase).IsAssignableFrom(t)).ToList();
var sourceDirectory = asm.GetCustomAttribute<CompiledFromDirectoryAttribute>()?.SourceDirectory;
foreach (var view in viewTypes)
{
var attr = view.GetCustomAttribute<CompiledFromFileAttribute>();
if (attr != null)
{
_views[MakeVirtualPath(attr.SourceFile, sourceDirectory)] = view;
}
}
}
ViewPaths = _views.Keys.OrderBy(_ => _).ToList();
}
/// <inheritdoc />
protected override IVirtualPathFactory CreateVirtualPathFactory() => new PrecompilationVirtualPathFactory(
precompiled: this,
runtime: ViewEngines.Engines.OfType<RoslynRazorViewEngine>().FirstOrDefault());
private static string MakeVirtualPath(string absoluteViewPath, string absoluteDirectoryPath = null)
{
if (absoluteDirectoryPath != null && absoluteViewPath.StartsWith(absoluteDirectoryPath))
{
return MakeVirtualPath(absoluteViewPath, absoluteDirectoryPath.Length - (absoluteDirectoryPath.EndsWith("\\") ? 1 : 0));
}
// we could just bail here, but let's make a best effort...
var firstArea = absoluteViewPath.IndexOf(@"\Areas\");
if (firstArea != -1)
{
return MakeVirtualPath(absoluteViewPath, firstArea);
}
else
{
var firstView = absoluteViewPath.IndexOf(@"\Views\");
if (firstView == -1) throw new Exception("Couldn't make virtual for: " + absoluteViewPath);
return MakeVirtualPath(absoluteViewPath, firstView);
}
}
private static string MakeVirtualPath(string absoluteViewPath, int startIndex)
{
var tail = absoluteViewPath.Substring(startIndex);
var vp = "~" + tail.Replace(@"\", "/");
return vp;
}
private static List<Assembly> FindViewAssemblies(string dirPath)
{
var pendingDirs = new List<string>();
pendingDirs.Add(dirPath);
var ret = new List<Assembly>();
while (pendingDirs.Count > 0)
{
var dir = pendingDirs[0];
pendingDirs.RemoveAt(0);
pendingDirs.AddRange(Directory.EnumerateDirectories(dir));
var dlls = Directory.EnumerateFiles(dir, "*.dll").Where(w => Path.GetFileNameWithoutExtension(w).Contains("_Web_"));
foreach (var dll in dlls)
{
try
{
var pdb = Path.Combine(Path.GetDirectoryName(dll), Path.GetFileNameWithoutExtension(dll) + ".pdb");
var asmBytes = File.ReadAllBytes(dll);
var pdbBytes = File.Exists(pdb) ? File.ReadAllBytes(pdb) : null;
Assembly asm;
if (pdbBytes == null)
{
asm = Assembly.Load(asmBytes);
}
else
{
asm = Assembly.Load(asmBytes, pdbBytes);
}
ret.Add(asm);
Debug.WriteLine("Loading view assembly: " + dll);
}
catch (Exception) { }
}
}
return ret;
}
/// <inheritdoc />
protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath) =>
CreateViewImpl(partialPath, masterPath: null, runViewStart: false);
/// <inheritdoc />
protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath) =>
CreateViewImpl(viewPath, masterPath, runViewStart: true);
internal Type TryLookupCompiledType(string viewPath)
{
Type compiledView;
if (!_views.TryGetValue(viewPath, out compiledView))
{
return null;
}
return compiledView;
}
private IView CreateViewImpl(string viewPath, string masterPath, bool runViewStart)
{
var compiledType = TryLookupCompiledType(viewPath);
if (compiledType == null)
{
return null;
}
return new PrecompilationView(viewPath, masterPath, compiledType, runViewStart, this);
}
/// <inheritdoc />
public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
{
if (controllerContext == null) throw new ArgumentNullException(nameof(controllerContext));
if (string.IsNullOrEmpty(partialViewName)) throw new ArgumentException($"\"{nameof(partialViewName)}\" argument cannot be null or empty.", nameof(partialViewName));
var areaName = AreaHelpers.GetAreaName(controllerContext.RouteData);
var locationsSearched = new List<string>(
DisplayModeProvider.Modes.Count * (
((PartialViewLocationFormats?.Length ?? 0) +
(areaName != null ? AreaPartialViewLocationFormats?.Length ?? 0 : 0)))
);
var viewPath = ResolveViewPath(partialViewName, areaName, PartialViewLocationFormats, AreaPartialViewLocationFormats, locationsSearched, controllerContext);
return string.IsNullOrEmpty(viewPath)
? new ViewEngineResult(locationsSearched)
: new ViewEngineResult(CreatePartialView(controllerContext, viewPath), this);
}
/// <inheritdoc />
public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
{
// All this madness is essentially re-written from the VirtualPathProviderViewEngine class, but that class
// checks on things like cache and whether the file exists and a whole bunch of stuff that's unnecessary.
// Plus: unecessary allocations :(
if (controllerContext == null) throw new ArgumentNullException(nameof(controllerContext));
if (string.IsNullOrEmpty(viewName)) throw new ArgumentException($"\"{nameof(viewName)}\" argument cannot be null or empty.", nameof(viewName));
var areaName = AreaHelpers.GetAreaName(controllerContext.RouteData);
// minimize re-allocations of List
var locationsSearched = new List<string>(
DisplayModeProvider.Modes.Count * (
((ViewLocationFormats?.Length ?? 0) +
(areaName != null ? AreaViewLocationFormats?.Length ?? 0 : 0)) +
(MasterLocationFormats?.Length ?? 0) +
(areaName != null ? AreaMasterLocationFormats?.Length ?? 0 : 0))
);
var viewPath = ResolveViewPath(viewName, areaName, ViewLocationFormats, AreaViewLocationFormats, locationsSearched, controllerContext);
var masterPath = ResolveViewPath(masterName, areaName, MasterLocationFormats, AreaMasterLocationFormats, locationsSearched, controllerContext);
if (string.IsNullOrEmpty(viewPath) ||
(string.IsNullOrEmpty(masterPath) && !string.IsNullOrEmpty(masterName)))
{
return new ViewEngineResult(locationsSearched);
}
return new ViewEngineResult(CreateView(controllerContext, viewPath, masterPath), this);
}
private string ResolveViewPath(string viewName, string areaName, string[] viewLocationFormats, string[] areaViewLocationFormats, List<string> viewLocationsSearched, ControllerContext controllerContext)
{
if (string.IsNullOrEmpty(viewName))
{
return null;
}
var controllerName = controllerContext.RouteData.GetRequiredString("controller");
if (IsSpecificPath(viewName))
{
var normalized = NormalizeViewName(viewName);
viewLocationsSearched.Add(viewName);
return _views.ContainsKey(normalized) ? normalized : null;
}
areaViewLocationFormats = (areaName == null ? null : areaViewLocationFormats) ?? new string[0];
viewLocationFormats = viewLocationFormats ?? new string[0];
var httpContext = controllerContext.HttpContext;
var availableDisplayModes = DisplayModeProvider.GetAvailableDisplayModesForContext(httpContext, controllerContext.DisplayMode);
foreach (var displayMode in availableDisplayModes)
{
for (var i = 0; i < areaViewLocationFormats.Length; i++)
{
var path = string.Format(areaViewLocationFormats[i], viewName, controllerName, areaName);
if (TryResolveView(httpContext, displayMode, ref path, viewLocationsSearched)) return path;
}
for (var i = 0; i < viewLocationFormats.Length; i++)
{
var path = string.Format(viewLocationFormats[i], viewName, controllerName);
if (TryResolveView(httpContext, displayMode, ref path, viewLocationsSearched)) return path;
}
}
return null;
}
private bool TryResolveView(HttpContextBase httpContext, IDisplayMode displayMode, ref string path, ICollection<string> viewLocationsSearched)
{
path = NormalizeViewName(VirtualPathUtility.ToAppRelative(path)); // resolve relative path portions
var displayInfo = displayMode.GetDisplayInfo(httpContext, path, _views.ContainsKey);
if (displayInfo == null || displayInfo.FilePath == null)
{
viewLocationsSearched.Add(path);
return false;
}
path = displayInfo.FilePath;
return true;
}
private static string NormalizeViewName(string viewName)
{
return viewName[0] == '/' ? ("~" + viewName) : viewName;
}
private static bool IsSpecificPath(string path) => path.Length > 0 && (path[0] == '~' || path[0] == '/');
}
// Hooray, another MVC5 class that should be public but ISN'T
internal static class AreaHelpers
{
public static string GetAreaName(RouteBase route)
{
var routeWithArea = route as IRouteWithArea;
if (routeWithArea != null)
return routeWithArea.Area;
var castRoute = route as Route;
return castRoute?.DataTokens?["area"] as string;
}
public static string GetAreaName(RouteData routeData)
{
object area;
if (routeData.DataTokens.TryGetValue("area", out area))
{
return area as string;
}
return GetAreaName(routeData.Route);
}
}
}
================================================
FILE: StackExhcange.Precompilation.MVC5/ProfiledVirtualPathProviderViewEngine.cs
================================================
using System;
using System.Web.Mvc;
using System.Web.WebPages;
namespace StackExchange.Precompilation
{
/// <summary>
/// Base class for implementing <see cref="VirtualPathProviderViewEngine"/> derived types that provide custom profiling steps.
/// </summary>
public abstract class ProfiledVirtualPathProviderViewEngine : VirtualPathProviderViewEngine
{
/// <summary>
/// Triggers when the engine performs a step that can be profiled.
/// </summary>
public Func<string, IDisposable> ProfileStep { get; set; }
internal IVirtualPathFactory VirtualPathFactory => _virtualPathFactoryFactory.Value;
protected abstract IVirtualPathFactory CreateVirtualPathFactory();
private readonly Lazy<IVirtualPathFactory> _virtualPathFactoryFactory; // sorry, I had to...
/// <inheritdoc />
protected ProfiledVirtualPathProviderViewEngine()
{
_virtualPathFactoryFactory = new Lazy<IVirtualPathFactory>(CreateVirtualPathFactory);
}
}
internal static class ProfileVirtualPathProviderViewEngineExtensions
{
/// <summary>
/// Invokes the <see cref="ProfiledVirtualPathProviderViewEngine.ProfileStep"/> if it's set.
/// </summary>
public static IDisposable DoProfileStep(this ProfiledVirtualPathProviderViewEngine instance, string name) =>
instance?.ProfileStep?.Invoke(name);
}
}
================================================
FILE: StackExhcange.Precompilation.MVC5/RazorParser.cs
================================================
using System;
using System.Linq;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Concurrent;
using System.IO;
using System.Security.Cryptography;
using System.Web.Configuration;
using System.Web.Razor;
using System.Web.WebPages.Razor;
using System.Web.WebPages.Razor.Configuration;
using Microsoft.CodeAnalysis;
using System.Threading.Tasks;
using System.Threading;
using Microsoft.CodeAnalysis.Text;
using RazorWorker = System.Func<System.Web.Razor.RazorEngineHost, Microsoft.CodeAnalysis.TextAndVersion, System.Threading.Tasks.Task<System.IO.Stream>>;
using System.Composition;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
namespace StackExchange.Precompilation
{
[ExportLanguageServiceFactoryAttribute(typeof(IDocumentExtender), LanguageNames.CSharp)]
class RazorParserFactory : ILanguageServiceFactory
{
public ILanguageService CreateLanguageService(HostLanguageServices languageServices) =>
new RazorParser(languageServices.WorkspaceServices.Workspace);
}
class RazorParser : IDocumentExtender, IDisposable
{
private readonly Workspace _workspace;
private readonly WebConfigurationFileMap _configMap;
private readonly DirectoryInfo _cacheDirectory;
private readonly BlockingCollection<RazorTextLoader> _workItems;
private readonly Lazy<Task> _backgroundWorkers;
private readonly CancellationToken _cancellationToken;
public RazorParser(Workspace workspace)
{
var dir = PrecompilerSection.Current?.RazorCache?.Directory;
// dir = string.IsNullOrWhiteSpace(dir)
// ? Environment.GetEnvironmentVariable(nameof(Precompilation) + "_" + nameof(PrecompilerSection.RazorCache) + nameof(RazorCacheElement.Directory))
// : dir;
// if (!string.IsNullOrWhiteSpace(dir) && ! dir exists)
// Directory.CreateDirectory(Path.Combine(CscArgs.OutputDirectory, dir))
// if (cacheDirectory.Exists != true)
// {
// throw new ArgumentException($"Specified directory '{cacheDirectory.FullName}' doesn't exist.", nameof(cacheDirectory));
// }
_workItems = new BlockingCollection<RazorTextLoader>();
_workspace = workspace;
_configMap = new WebConfigurationFileMap { VirtualDirectories = { { "/", new VirtualDirectoryMapping(Environment.CurrentDirectory, true) } } };
_backgroundWorkers = new Lazy<Task>(
() => _cancellationToken.IsCancellationRequested
? Task.CompletedTask
: Task.WhenAll(Enumerable.Range(0, Environment.ProcessorCount).Select(_ => Task.Run(BackgroundWorker, _cancellationToken))),
LazyThreadSafetyMode.ExecutionAndPublication);
}
private async Task BackgroundWorker()
{
foreach(var loader in _workItems.GetConsumingEnumerable(_cancellationToken))
{
if (_cancellationToken.IsCancellationRequested)
{
loader.Result.SetCanceled();
continue;
}
try
{
var originalText = await loader.OriginalLoader.LoadTextAndVersionAsync(_workspace, null, default(CancellationToken));
var viewFullPath = originalText.FilePath;
var viewVirtualPath = GetRelativeUri(originalText.FilePath, Environment.CurrentDirectory);
var viewConfig = WebConfigurationManager.OpenMappedWebConfiguration(_configMap, viewVirtualPath);
var host = viewConfig.GetSectionGroup("system.web.webPages.razor") is RazorWebSectionGroup razorConfig
? WebRazorHostFactory.CreateHostFromConfig(razorConfig, viewVirtualPath, viewFullPath)
: WebRazorHostFactory.CreateDefaultHost(viewVirtualPath, viewFullPath);
// having this as a field would require the ASP.NET MVC dependency even for console apps...
RazorWorker worker = RazorWorker;
if (_cacheDirectory != null)
{
worker = CachedRazorWorker;
}
using (var stream = await worker(host, originalText))
{
var generatedText = TextAndVersion.Create(
SourceText.From(stream, originalText.Text.Encoding, originalText.Text.ChecksumAlgorithm, canBeEmbedded: originalText.Text.CanBeEmbedded, throwIfBinaryDetected: true),
originalText.Version,
originalText.FilePath);
loader.Result.TrySetResult(generatedText);
}
}
catch (Exception ex)
{
loader.Result.TrySetException(ex);
}
}
}
void IDisposable.Dispose()
{
_workItems?.Dispose();
}
private async Task<Stream> CachedRazorWorker(RazorEngineHost host, TextAndVersion originalText)
{
var cacheFile = GetCachedFileInfo();
if (cacheFile.Exists)
{
return cacheFile.OpenRead();
}
else
{
(var success, var source) = await RazorWorkerImpl(host, originalText);
FileStream fs = null;
try
{
if (success)
{
fs = cacheFile.Create();
await source.CopyToAsync(fs, 4096, _cancellationToken);
await fs.FlushAsync(_cancellationToken);
}
}
catch (Exception ex)
{
ReportDiagnostic(Diagnostic.Create(Compilation.CachingFailed, Location.None, originalText.FilePath, cacheFile.FullName, ex));
for (var i = 0; i < 10 && cacheFile.Exists; i++)
{
await Task.Delay(100 * i);
try { cacheFile.Delete(); } catch { }
}
if (cacheFile.Exists)
{
ReportDiagnostic(Diagnostic.Create(Compilation.CachingFailedHard, Location.None, originalText.FilePath, cacheFile.FullName));
}
}
finally
{
fs?.Dispose();
source.Position = 0;
}
return source; // return the in-memory stream, since it's faster
}
FileInfo GetCachedFileInfo()
{
using (var md5 = MD5.Create())
using (var str = new MemoryStream())
using (var sw = new StreamWriter(str))
{
// all those things can affect the generated c#
// so we need to include them in the hash...
sw.WriteLine(host.CodeLanguage.LanguageName);
sw.WriteLine(host.CodeLanguage.CodeDomProviderType.FullName);
sw.WriteLine(host.DefaultBaseClass);
sw.WriteLine(host.DefaultClassName);
sw.WriteLine(host.DefaultNamespace);
sw.WriteLine(string.Join(";",host.NamespaceImports));
sw.WriteLine(host.StaticHelpers);
sw.WriteLine(host.TabSize);
sw.WriteLine(originalText.FilePath);
originalText.Text.Write(sw, _cancellationToken); // .cshtml content
sw.Flush();
str.Position = 0;
var hashBytes = md5.ComputeHash(str);
var fileName = BitConverter.ToString(hashBytes).Replace("-","") + ".cs";
var filePath = Path.Combine(_cacheDirectory.FullName, fileName);
return new FileInfo(filePath);
}
}
}
private readonly ConcurrentBag<Diagnostic> _diagnostics = new ConcurrentBag<Diagnostic>();
private void ReportDiagnostic(Diagnostic d) => _diagnostics.Add(d);
private Task<Stream> RazorWorker(RazorEngineHost host, TextAndVersion originalText) =>
RazorWorkerImpl(host, originalText).ContinueWith(x => x.Result.result, TaskContinuationOptions.OnlyOnRanToCompletion);
private Task<(bool success, Stream result)> RazorWorkerImpl(RazorEngineHost host, TextAndVersion originalText)
{
var success = true;
var generatedStream = new MemoryStream(capacity: originalText.Text.Length * 8); // generated .cs files contain a lot of additional crap vs actualy cshtml
var viewFullPath = originalText.FilePath;
using (var sourceReader = new StreamReader(generatedStream, originalText.Text.Encoding, false, 4096, leaveOpen: true))
using (var provider = CodeDomProvider.CreateProvider("csharp"))
using (var generatedWriter = new StreamWriter(generatedStream, originalText.Text.Encoding, 4096, leaveOpen: true))
{
// write cshtml into generated stream and rewind
originalText.Text.Write(generatedWriter);
generatedWriter.Flush();
generatedStream.Position = 0;
// generated code and clear memory stream
var engine = new RazorTemplateEngine(host);
var razorOut = engine.GenerateCode(sourceReader, null, null, viewFullPath);
if (!razorOut.Success)
{
success = false;
foreach(var error in razorOut.ParserErrors)
{
var position = new LinePosition(error.Location.LineIndex, error.Location.CharacterIndex - 1);
ReportDiagnostic(Diagnostic.Create(
Compilation.RazorParserError,
Location.Create(
originalText.FilePath,
new TextSpan(error.Location.AbsoluteIndex, error.Length),
new LinePositionSpan(position, position)),
error.Message));
}
}
// add the CompiledFromFileAttribute to the generated class
razorOut.GeneratedCode
.Namespaces.OfType<CodeNamespace>().FirstOrDefault()?
.Types.OfType<CodeTypeDeclaration>().FirstOrDefault()?
.CustomAttributes.Add(
new CodeAttributeDeclaration(
new CodeTypeReference(typeof(CompiledFromFileAttribute)),
new CodeAttributeArgument(new CodePrimitiveExpression(viewFullPath))
));
// reuse the memory stream for code generation
generatedStream.Position = 0;
generatedStream.SetLength(0);
var codeGenOptions = new CodeGeneratorOptions { VerbatimOrder = true, ElseOnClosing = false, BlankLinesBetweenMembers = false };
provider.GenerateCodeFromCompileUnit(razorOut.GeneratedCode, generatedWriter, codeGenOptions);
// rewind
generatedWriter.Flush();
generatedStream.Position = 0;
}
return Task.FromResult((success: success, stream: (Stream)generatedStream));
}
private string GetRelativeUri(string filespec, string folder)
{
Uri pathUri = new Uri(filespec);
if (!folder.EndsWith(Path.DirectorySeparatorChar.ToString()))
{
folder += Path.DirectorySeparatorChar;
}
Uri folderUri = new Uri(folder);
return "/" + folderUri.MakeRelativeUri(pathUri).ToString().TrimStart('/');
}
public DocumentInfo Extend(DocumentInfo document)
{
if (Path.GetExtension(document.Name) != ".cshtml") return document;
var razorLoader = new RazorTextLoader(this, document.TextLoader);
_workItems.Add(razorLoader);
return document.WithTextLoader(razorLoader);
}
public async Task<System.Collections.Generic.ICollection<Diagnostic>> Complete()
{
_workItems.CompleteAdding();
if (_backgroundWorkers.IsValueCreated || !_workItems.IsCompleted)
{
await _backgroundWorkers.Value;
}
return _diagnostics.ToList();
}
private Task EnsureWorkers() => _backgroundWorkers.Value;
private sealed class RazorTextLoader : TextLoader
{
public TextLoader OriginalLoader { get; }
public TaskCompletionSource<TextAndVersion> Result { get; }
private readonly RazorParser _parser;
public RazorTextLoader(RazorParser parser, TextLoader originalLoader)
{
_parser = parser;
OriginalLoader = originalLoader;
Result = new TaskCompletionSource<TextAndVersion>();
}
private Task _worker;
public override Task<TextAndVersion> LoadTextAndVersionAsync(Workspace workspace, DocumentId documentId, CancellationToken cancellationToken)
{
_worker = _worker ?? _parser.EnsureWorkers(); // ensuring that lazy workers are running
return Result.Task;
}
}
}
}
================================================
FILE: StackExhcange.Precompilation.MVC5/RoslynRazorViewEngine.cs
================================================
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.Text;
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Web;
using System.Web.Compilation;
using System.Web.Hosting;
using System.Web.Mvc;
using System.Web.Razor;
using System.Web.Razor.Generator;
using System.Web.Razor.Parser.SyntaxTree;
using System.Web.WebPages;
using System.Web.WebPages.Razor;
namespace StackExchange.Precompilation
{
/// <summary>
/// A replacement for the <see cref="RazorViewEngine"/> that uses roslyn (<see cref="Microsoft.CodeAnalysis"/>) instead of <see cref="System.CodeDom"/> to compile views.
/// </summary>
public class RoslynRazorViewEngine : ProfiledVirtualPathProviderViewEngine
{
/// <summary>
/// Creates a new <see cref="RoslynRazorViewEngine"/> instance.
/// </summary>
public RoslynRazorViewEngine()
{
AreaViewLocationFormats = new[] {
"~/Areas/{2}/Views/{1}/{0}.cshtml",
"~/Areas/{2}/Views/Shared/{0}.cshtml"
};
AreaMasterLocationFormats = new[] {
"~/Areas/{2}/Views/{1}/{0}.cshtml",
"~/Areas/{2}/Views/Shared/{0}.cshtml"
};
AreaPartialViewLocationFormats = new[] {
"~/Areas/{2}/Views/{1}/{0}.cshtml",
"~/Areas/{2}/Views/Shared/{0}.cshtml"
};
ViewLocationFormats = new[] {
"~/Views/{1}/{0}.cshtml",
"~/Views/Shared/{0}.cshtml"
};
MasterLocationFormats = new[] {
"~/Views/{1}/{0}.cshtml",
"~/Views/Shared/{0}.cshtml"
};
PartialViewLocationFormats = new[] {
"~/Views/{1}/{0}.cshtml",
"~/Views/Shared/{0}.cshtml"
};
FileExtensions = new[] {
"cshtml"
};
}
/// <summary>When set to <c>true</c>, configured <see cref="ICompileModule" />s are used when the views are compiled</summary>
public bool UseCompilationModules { get; set; }
private readonly ICompileModule[] _noModule = new ICompileModule[0];
private readonly PrecompilationModuleLoader _moduleLoader = new PrecompilationModuleLoader(PrecompilerSection.Current);
/// <inheritdoc />
protected override IVirtualPathFactory CreateVirtualPathFactory() => new PrecompilationVirtualPathFactory(
runtime: this,
precompiled: ViewEngines.Engines.OfType<PrecompiledViewEngine>().FirstOrDefault());
/// <inheritdoc />
protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath) =>
new PrecompilationView(partialPath, null, GetTypeFromVirtualPath(partialPath), false, this);
/// <inheritdoc />
protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath) =>
new PrecompilationView(viewPath, masterPath, GetTypeFromVirtualPath(viewPath), true, this);
internal bool FileExists(string virtualPath) =>
HostingEnvironment.VirtualPathProvider.FileExists(virtualPath);
internal Type GetTypeFromVirtualPath(string virtualPath)
{
virtualPath = VirtualPathUtility.ToAbsolute(virtualPath);
var cacheKey = "RoslynRazor_" + virtualPath;
var type = HttpRuntime.Cache[cacheKey] as Type;
if (type == null)
{
type = GetTypeFromVirtualPathNoCache(virtualPath);
// Cache it, and make it dependent on the razor file
var cacheDependency = HostingEnvironment.VirtualPathProvider.GetCacheDependency(virtualPath, new string[] { virtualPath }, DateTime.UtcNow);
HttpRuntime.Cache.Insert(cacheKey, type, cacheDependency);
}
return type;
}
private Type GetTypeFromVirtualPathNoCache(string virtualPath)
{
using (this.DoProfileStep($"{nameof(RoslynRazorViewEngine)}: Compiling {virtualPath}"))
{
OnCodeGenerationStarted();
var args = new CompilingPathEventArgs(virtualPath, WebRazorHostFactory.CreateHostFromConfig(virtualPath));
OnBeforeCompilePath(args);
var host = args.Host;
var razorResult = RunRazorGenerator(virtualPath, host);
var syntaxTree = GetSyntaxTree(host, razorResult);
var assembly = CompileToAssembly(host, syntaxTree, UseCompilationModules ? _moduleLoader.LoadedModules : _noModule);
return assembly.GetType($"{host.DefaultNamespace}.{host.DefaultClassName}");
}
}
private GeneratorResults RunRazorGenerator(string virtualPath, WebPageRazorHost host)
{
var file = HostingEnvironment.VirtualPathProvider.GetFile(virtualPath);
var engine = new RazorTemplateEngine(host);
using (var viewStream = file.Open())
using (var viewReader = new StreamReader(viewStream))
{
var razorResult = engine.GenerateCode(viewReader, className: null, rootNamespace: null, sourceFileName: host.PhysicalPath);
if (!razorResult.Success)
{
var sourceCode = (string)null;
if (viewStream.CanSeek)
{
viewStream.Seek(0, SeekOrigin.Begin);
sourceCode = viewReader.ReadToEnd();
}
throw CreateExceptionFromParserError(razorResult.ParserErrors.Last(), virtualPath, sourceCode);
}
OnCodeGenerationCompleted(razorResult.GeneratedCode, host);
return razorResult;
}
}
private static SyntaxTree GetSyntaxTree(WebPageRazorHost host, GeneratorResults razorResult)
{
// Use CodeDom to generate source code from the CodeCompileUnit
// Use roslyn to parse it back
using (var codeDomProvider = CodeDomProvider.CreateProvider(host.CodeLanguage.LanguageName))
using (var viewCodeStream = new MemoryStream())
using (var viewCodeWriter = new StreamWriter(viewCodeStream))
{
codeDomProvider.GenerateCodeFromCompileUnit(razorResult.GeneratedCode, viewCodeWriter, new CodeGeneratorOptions());
viewCodeWriter.Flush();
viewCodeStream.Position = 0;
var sourceText = SourceText.From(viewCodeStream);
// We need a different file path for the generated file, otherwise breakpoints won't get
// hit due to #line directives pointing at the original .cshtml. If we'd want breakpoint
// in the generated .cs code, we'd have to dump them somewhere on disk, and specify the path here.
var sourcePath = string.IsNullOrEmpty(host.PhysicalPath)
? host.VirtualPath // yay virtual paths, won't point at the original file
: Path.ChangeExtension(host.PhysicalPath, ".roslynviewengine");
return SyntaxFactory.ParseSyntaxTree(sourceText, path: sourcePath);
}
}
// we were getting OutOfMemory exceptions caused by MetadataReference.CreateFrom* creating
// System.Reflection.PortableExecutable.PEReader instances for the same assembly for each view being compiled
private static readonly ConcurrentDictionary<string, Lazy<MetadataReference>> ReferenceCache = new ConcurrentDictionary<string, Lazy<MetadataReference>>();
internal static MetadataReference ResolveReference(Assembly assembly)
{
var key = assembly.Location;
Uri uri;
if (Uri.TryCreate(assembly.CodeBase, UriKind.Absolute, out uri) && uri.IsFile)
{
key = uri.LocalPath;
}
return ReferenceCache.GetOrAdd(
key,
loc => new Lazy<MetadataReference>(
() => MetadataReference.CreateFromFile(loc),
LazyThreadSafetyMode.ExecutionAndPublication)).Value;
}
private static Assembly CompileToAssembly(WebPageRazorHost host, SyntaxTree syntaxTree, ICollection<ICompileModule> compilationModules)
{
var strArgs = new List<string>();
strArgs.Add("/target:library");
strArgs.Add(host.DefaultDebugCompilation ? "/o-" : "/o+");
strArgs.Add(host.DefaultDebugCompilation ? "/debug+" : "/debug-");
var cscArgs = CSharpCommandLineParser.Default.Parse(strArgs, null, null);
var compilation = CSharpCompilation.Create(
"RoslynRazor", // Note: using a fixed assembly name, which doesn't matter as long as we don't expect cross references of generated assemblies
new[] { syntaxTree },
BuildManager.GetReferencedAssemblies().OfType<Assembly>().Select(ResolveReference),
cscArgs.CompilationOptions.WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default));
compilation = Hacks.MakeValueTuplesWorkWhenRunningOn47RuntimeAndTargetingNet45Plus(compilation);
var diagnostics = new List<Diagnostic>();
var context = new CompileContext(compilationModules);
context.Before(new BeforeCompileContext
{
Arguments = cscArgs,
Compilation = compilation,
Diagnostics = diagnostics,
});
compilation = context.BeforeCompileContext.Compilation;
using (var dllStream = new MemoryStream())
using (var pdbStream = new MemoryStream())
{
EmitResult emitResult = compilation.Emit(dllStream, pdbStream);
diagnostics.AddRange(emitResult.Diagnostics);
if (!emitResult.Success)
{
Diagnostic diagnostic = diagnostics.First(x => x.Severity == DiagnosticSeverity.Error);
string message = diagnostic.ToString();
LinePosition linePosition = diagnostic.Location.GetMappedLineSpan().StartLinePosition;
throw new HttpParseException(message, null, host.VirtualPath, null, linePosition.Line + 1);
}
context.After(new AfterCompileContext
{
Arguments = context.BeforeCompileContext.Arguments,
AssemblyStream = dllStream,
Compilation = compilation,
Diagnostics = diagnostics,
SymbolStream = pdbStream,
XmlDocStream = null,
});
return Assembly.Load(dllStream.GetBuffer(), pdbStream.GetBuffer());
}
}
private static HttpParseException CreateExceptionFromParserError(RazorError error, string virtualPath, string sourceCode) =>
new HttpParseException(error.Message + Environment.NewLine, null, virtualPath, sourceCode, error.Location.LineIndex + 1);
/// <summary>
/// This is the equivalent of the <see cref="RazorBuildProvider.CompilingPath"/> event, since <see cref="PrecompiledViewEngine"/> bypasses <see cref="RazorBuildProvider"/> completely.
/// </summary>
public static event EventHandler<CompilingPathEventArgs> CompilingPath;
/// <summary>
/// Raises the <see cref="CompilingPath"/> event.
/// </summary>
/// <param name="args"></param>
protected virtual void OnBeforeCompilePath(CompilingPathEventArgs args) =>
CompilingPath?.Invoke(this, args);
/// <summary>
/// This is the equivalent of the <see cref="RazorBuildProvider.CodeGenerationStarted"/> event, since <see cref="PrecompiledViewEngine"/> bypasses <see cref="RazorBuildProvider"/> completely.
/// </summary>
public static event EventHandler CodeGenerationStarted;
private void OnCodeGenerationStarted() =>
CodeGenerationStarted?.Invoke(this, EventArgs.Empty);
/// <summary>
/// This is the equivalent of the <see cref="RazorBuildProvider.CodeGenerationCompleted"/> event, since <see cref="PrecompiledViewEngine"/> bypasses <see cref="RazorBuildProvider"/> completely.
/// </summary>
public static event EventHandler<CodeGenerationCompleteEventArgs> CodeGenerationCompleted;
private void OnCodeGenerationCompleted(CodeCompileUnit codeCompileUnit, WebPageRazorHost host) =>
CodeGenerationCompleted?.Invoke(this, new CodeGenerationCompleteEventArgs(host.VirtualPath, host.PhysicalPath, codeCompileUnit));
}
}
================================================
FILE: StackExhcange.Precompilation.MVC5/StackExchange.Precompilation.MVC5.csproj
================================================
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net462</TargetFramework>
<Description>Hooks into the ASP.NET MVC and StackExchange.Precompilation.Build pipeline to enable usage of C# 7.2, and views precompiled with StackExchange.Precompilation.Build</Description>
<IsPackable>true</IsPackable>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="System.Web" />
<PackageReference Include="Microsoft.AspNet.Mvc" Version="5.2.7" />
<ProjectReference Include="..\StackExchange.Precompilation\StackExchange.Precompilation.csproj" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="2.10.0" PrivateAssets="all" />
<ProjectReference Include="..\StackExchange.Precompilation.Build\StackExchange.Precompilation.Build.csproj" IncludeAssets="compile" PrivateAssets="all" />
</ItemGroup>
</Project>
================================================
FILE: Test.ConsoleApp/AliasTest.cs
================================================
#if NET462
extern alias aliastest;
namespace Test.ConsoleApp
{
class AliasTest
{
public const string DataSet = nameof(aliastest::System.Data.DataSet);
}
}
#endif
================================================
FILE: Test.ConsoleApp/App.config
================================================
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="stackExchange.precompiler" type="StackExchange.Precompilation.PrecompilerSection, StackExchange.Precompilation" />
</configSections>
<stackExchange.precompiler>
<modules>
<add type="Test.Module.TestCompileModule, Test.Module" />
</modules>
</stackExchange.precompiler>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" />
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.1.0" newVersion="4.1.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Runtime.Extensions" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.1.0" newVersion="4.1.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.IO.Compression" publicKeyToken="b77a5c561934e089" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Runtime.InteropServices" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Reflection" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.1.0" newVersion="4.1.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Security.Cryptography.Algorithms" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.2.1.0" newVersion="1.2.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.IO.FileSystem" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.IO.FileSystem.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Security.Cryptography.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Xml.XPath.XDocument" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Diagnostics.FileVersionInfo" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Threading.Thread" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
================================================
FILE: Test.ConsoleApp/Program.cs
================================================
using System;
using System.Runtime.CompilerServices;
using Test.Module;
namespace Test.ConsoleApp
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(PathMapTest().Dump());
#if NET462
Console.WriteLine(typeof(AliasTest).FullName);
#endif
}
// path mapping test, configured via <PathMap> property in the .csproj
static string PathMapTest([CallerFilePath] string path = null) =>
path.StartsWith("X:\\Test\\")
? path
: throw new InvalidOperationException($"CallerFilePath was expected to start with X:\\Test\\ but was {path}.");
}
}
================================================
FILE: Test.ConsoleApp/Test.ConsoleApp.csproj
================================================
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
<OutputType>Exe</OutputType>
<TargetFrameworks>net462;netcoreapp20</TargetFrameworks>
<RuntimeIdentifiers>win10-x64</RuntimeIdentifiers>
<SEPrecompilerPath Condition="'$(SEPrecompilerPath)' == ''">$(SolutionDir)StackExchange.Precompilation.Build\bin\$(Configuration)\net462\</SEPrecompilerPath>
<PathMap>$(SolutionDir)=X:\Test\</PathMap>
<DebugType>portable</DebugType>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Test.Module\Test.Module.csproj">
<Project>{5fcaecc3-787b-473f-a372-783d0c235190}</Project>
<Name>Test.Module</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Reference Include="System.Data" Aliases="aliastest" Condition="'$(TargetFramework)' == 'net462'" />
<!-- Usually, this would be pulled in by the reference to StackExchange.Precompilation.Build nuget,
but since we don't have the package yet, msbuild complains about the .csproj not targeting netstandard,
so we're pulling it's references in manually.
-->
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="2.10.0" IncludeAssets="compile" PrivateAssets="all" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0-beta-63127-02" PrivateAssets="All" />
</ItemGroup>
<Import Project="..\StackExchange.Precompilation.Build\StackExchange.Precompilation.Build.targets" />
</Project>
================================================
FILE: Test.Module/Test.Module.csproj
================================================
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net462;netstandard20</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\StackExchange.Precompilation\StackExchange.Precompilation.csproj">
<Project>{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</Project>
<Name>StackExchange.Precompilation</Name>
</ProjectReference>
</ItemGroup>
</Project>
================================================
FILE: Test.Module/TestCompileModule.cs
================================================
using System;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using StackExchange.Precompilation;
namespace Test.Module
{
public class TestCompileModule : ICompileModule
{
public void BeforeCompile(BeforeCompileContext context)
{
// this can potentially run multiple times (for every view compiled at runtime) in RoslynRazorViewEngine;
if(context.Compilation.GetTypeByMetadataName("Test.Module.Extensions") != null) return;
context.Diagnostics.Add(
Diagnostic.Create(
new DiagnosticDescriptor("TEST", "TEST", "Hello meta programming world!", "TEST", DiagnosticSeverity.Info, true),
Location.None));
context.Compilation = context.Compilation.AddSyntaxTrees(
SyntaxFactory.ParseSyntaxTree(@"
namespace Test.Module
{
public static class Extensions
{
public static T Dump<T>(this T i)
{
if (i != null)
{
System.Console.WriteLine(i);
}
return i;
}
}
}
", context.Arguments.ParseOptions));
}
public void AfterCompile(AfterCompileContext context)
{
}
}
}
================================================
FILE: Test.WebApp/Content/PartialExternalContent.cshtml
================================================
Partial External Content
================================================
FILE: Test.WebApp/Controllers/HomeController.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using StackExchange.Precompilation;
namespace Test.WebApp.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
IEnumerable<string> viewPaths;
#if DEBUG
viewPaths = new string[] { "We don't keep track of the views in the RoslynRazorViewEngine." };
#else
var viewEngine = ViewEngines.Engines.OfType<PrecompiledViewEngine>().Single();
viewPaths = viewEngine.ViewPaths;
#endif
return View(new Models.SampleModel { ViewPaths = viewPaths });
}
public ActionResult IndexOverridden()
{
return new ViewResult
{
ViewName = "~/Views/Home/Index.cshtml",
MasterName = "~/Views/Shared/_Layout.Overridden.cshtml",
ViewData = new ViewDataDictionary(new Models.SampleModel { ViewPaths = new [] { "OVERRIDDDDDEN" } }),
};
}
public ActionResult ExcludedLayout() => View();
}
}
================================================
FILE: Test.WebApp/Models/SampleModel.cs
================================================
using System.Collections.Generic;
namespace Test.WebApp.Models
{
public class SampleModel
{
public IEnumerable<string> ViewPaths { get; set; }
}
}
================================================
FILE: Test.WebApp/MvcApplication.cs
================================================
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using StackExchange.Precompilation;
using Test.WebApp.Controllers;
namespace Test.WebApp
{
public static class MvcApplicationInitializer
{
public static void PreApplicationStart() =>
System.Web.UI.PageParser.DefaultApplicationBaseType = typeof(MvcApplication);
}
public class MvcApplication : HttpApplication
{
public static bool IsDebug =>
#if DEBUG
true;
#else
false;
#endif
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalFilters.Filters.Add(new HandleErrorAttribute());
RouteTable.Routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
RouteTable.Routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
ViewEngines.Engines.Clear();
#if !DEBUG
// use precompiled engine first (supports some C# 6),
ViewEngines.Engines.Add(new PrecompiledViewEngine(typeof(HomeController).Assembly, typeof(ExternalViews).Assembly));
#endif
// fallback to RoslynRazorViewEngine (RazorViewEngine doesn't support C# 6).
ViewEngines.Engines.Add(new RoslynRazorViewEngine() { UseCompilationModules = true });
}
}
}
================================================
FILE: Test.WebApp/Properties/AssemblyInfo.cs
================================================
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Web;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Test.WebApp")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Test.WebApp")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("09bb37e2-0d7e-472d-b74c-aa02018c89c6")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: PreApplicationStartMethod(typeof(Test.WebApp.MvcApplicationInitializer), nameof(Test.WebApp.MvcApplicationInitializer.PreApplicationStart))]
================================================
FILE: Test.WebApp/Test.WebApp.csproj
================================================
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>
</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{5B0105A4-256B-4A88-852C-6F5E9D185515}</ProjectGuid>
<ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Test.WebApp</RootNamespace>
<AssemblyName>Test.WebApp</AssemblyName>
<TargetFramework>net462</TargetFramework>
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
<MvcBuildViews>false</MvcBuildViews>
<UseIISExpress>true</UseIISExpress>
<IISExpressSSLPort />
<IISExpressAnonymousAuthentication />
<IISExpressWindowsAuthentication />
<IISExpressUseClassicPipelineMode />
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<UseGlobalApplicationHostFile />
<TargetFrameworkProfile />
<RuntimeIdentifiers>win</RuntimeIdentifiers>
<DependsOnNETStandard>false</DependsOnNETStandard><!-- lies -->
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\StackExchange.Precompilation\StackExchange.Precompilation.csproj">
<Project>{3C0A90F1-B19E-4305-AB71-3CD31C7D0F4D}</Project>
<Name>StackExchange.Precompilation</Name>
</ProjectReference>
<ProjectReference Include="..\StackExhcange.Precompilation.MVC5\StackExchange.Precompilation.MVC5.csproj" />
<ProjectReference Include="..\Test.WebApp.ExternalViews\Test.WebApp.ExternalViews.csproj">
<Project>{2ba24772-f7b0-4652-a430-2f4c2262e882}</Project>
<Name>Test.WebApp.ExternalViews</Name>
</ProjectReference>
<ProjectReference Include="..\Test.Module\Test.Module.csproj">
<Project>{5fcaecc3-787b-473f-a372-783d0c235190}</Project>
<Name>Test.Module</Name>
</ProjectReference>
<Reference Include="netstandard" />
</ItemGroup>
<ItemGroup>
<Compile Include="**\*.cs" Exclude="obj\**\*" />
<Content Include="**\*.cshtml" Exclude="Views\Home\ExcludedLayout.cshtml" />
<None Include="Web.config" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Web" />
<Reference Include="Microsoft.CSharp" />
<PackageReference Include="Microsoft.AspNet.Mvc" Version="5.2.7" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="2.10.0" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
<PackageReference Include="MSBuild.Microsoft.VisualStudio.Web.targets" Version="14.0.0.3" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0-beta-63127-02" PrivateAssets="All" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Target Name="MvcBuildViews" AfterTargets="AfterBuild" Condition="'$(MvcBuildViews)'=='true'">
<AspNetCompiler VirtualPath="temp" PhysicalPath="$(WebProjectOutputDir)" />
</Target>
<ProjectExtensions>
<VisualStudio>
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
<WebProjectProperties>
<SaveServerSettingsInUserFile>True</SaveServerSettingsInUserFile>
</WebProjectProperties>
</FlavorProperties>
</VisualStudio>
</ProjectExtensions>
<PropertyGroup>
<SEPrecompilerPath Condition="'$(SEPrecompilerPath)' == ''">$(SolutionDir)StackExchange.Precompilation.Build\bin\$(Configuration)\$(TargetFramework)\</SEPrecompilerPath>
<!-- Using DEBUG build configuration to test RoslynRazorViewEngine in VS, SECompilerPath is set in the build script -->
<SEPrecompilerIncludeRazor Condition="'$(Configuration)' == 'Release' or '(SECompilerPath)' != ''">true</SEPrecompilerIncludeRazor>
</PropertyGroup>
<Import Project="..\StackExchange.Precompilation.Build\StackExchange.Precompilation.Build.targets" />
<Target Name="Pack">
<!-- this target is just a dummy to enable the pack target solution wide, since this is the only non-SDK project in the solution -->
</Target>
</Project>
================================================
FILE: Test.WebApp/Views/Home/ExcludedLayout.cshtml
================================================
@{
Layout = "~/Views/Shared/_Layout.Excluded.cshtml";
}
<h2>ExcludedLayout</h2>
================================================
FILE: Test.WebApp/Views/Home/Index.Mobile.cshtml
================================================
@model SampleModel
@{
ViewBag.Title = "Test Page";
}
Mobile Precompiled View Paths:
<ul>
@foreach (var path in Model.ViewPaths)
{
<li>@path</li>
}
</ul>
@Html.EditorForModel()
@Helpers.Test()
================================================
FILE: Test.WebApp/Views/Home/Index.cshtml
================================================
@model SampleModel
@{
ViewBag.Title = "Test Page";
}
Precompiled View Paths:
<ul>
@foreach (var path in Model.ViewPaths)
{
<li>@path</li>
}
</ul>
@Html.EditorForModel()
@Html.Partial("../Other/../Other/RelativePartial")
@Helpers.Test()
@if (!MvcApplication.IsDebug)
{
@Html.Partial("ExternalPartial");
}
@{
// c# 7 features
(string title, string url) GetTitle() => ("ValueTuple", "`2");
@GetTitle().Item1
}
================================================
FILE: Test.WebApp/Views/Other/RelativePartial.cshtml
================================================
RelativePartial.cshtml
@{
@*
code bellow is a repro case for a Razer parser errors, that were only caught
in RoslynRazorViewEngine but not during precompilation...
to repro use `@foreach` instead of `foreach`
*@
foreach(var x in new []{1,2,3})
{
@:@x,
}
}
================================================
FILE: Test.WebApp/Views/Shared/EditorTemplates/SampleModel.Mobile.cshtml
================================================
@model Test.WebApp.Models.SampleModel
<hr/>
EditorTemplates.Mobile
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
@Html.EditorFor(m => m.ViewPaths)
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" disabled="disabled" class="btn btn-default" />
</div>
</div>
</div>
}
<hr/>
================================================
FILE: Test.WebApp/Views/Shared/EditorTemplates/SampleModel.cshtml
================================================
@model Test.WebApp.Models.SampleModel
<hr/>
EditorTemplates
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
@Html.EditorFor(m => m.ViewPaths)
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" disabled="disabled" class="btn btn-default" />
</div>
</div>
</div>
}
<hr/>
================================================
FILE: Test.WebApp/Views/Shared/EditorTemplates/String.cshtml
================================================
@model System.String
<div>
<input readonly="readonly" disabled="disabled" value="@Model" />
</div>
================================================
FILE: Test.WebApp/Views/Shared/_Footer.Mobile.cshtml
================================================
@model DateTime
<footer>
<p>© @Model.Year Mobile Partial Footer</p>
</footer>
================================================
FILE: Test.WebApp/Views/Shared/_Footer.cshtml
================================================
@model DateTime
<footer>
<p>© @Model.Year Partial Footer</p>
</footer>
================================================
FILE: Test.WebApp/Views/Shared/_Layout.Excluded.cshtml
================================================
Layout
@RenderBody()
/Layout
================================================
FILE: Test.WebApp/Views/Shared/_Layout.Mobile.cshtml
================================================
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>@ViewBag.Title - Test.WebApp - Mobile</title>
</head>
<body>
<h1>Mobile</h1>
<hr/>
<div class="body-content">
@RenderBody()
<hr />
</div>
@Html.Partial("_Footer", DateTime.Now)
@Html.Partial("~/Content/PartialExternalContent.cshtml")
</body>
</html>
================================================
FILE: Test.WebApp/Views/Shared/_Layout.Overridden.cshtml
================================================
<h1>OVERRIDDDDDEN</h1>
<h2>@ViewBag.Title - Test.WebApp</h2>
@RenderBody()
<h1>/OVERRIDDDDDEN</h1>
================================================
FILE: Test.WebApp/Views/Shared/_Layout.cshtml
================================================
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>@ViewBag.Title - Test.WebApp</title>
</head>
<body>
<div class="body-content">
@RenderBody()
<hr />
</div>
@Html.ActionLink("Overridden layout", "IndexOverridden", new { controller = "Home".Dump() })
@Html.ActionLink("Excluded layout", "ExcludedLayout", new { controller = "Home" })
@Html.Partial("_Footer", DateTime.Now)
@Html.Partial("~/Content/PartialExternalContent.cshtml")
</body>
</html>
================================================
FILE: Test.WebApp/Views/Web.config
================================================
<?xml version="1.0"?>
<configuration>
<configSections>
<sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
<section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
</sectionGroup>
</configSections>
<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
<add namespace="Test.Module" />
<add namespace="Test.WebApp" />
<add namespace="Test.WebApp.Models" />
</namespaces>
</pages>
</system.web.webPages.razor>
<appSettings>
<add key="webpages:Enabled" value="false" />
</appSettings>
<system.webServer>
<handlers>
<remove name="BlockViewHandler"/>
<add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
</handlers>
</system.webServer>
</configuration>
================================================
FILE: Test.WebApp/Views/_ViewStart.cshtml
================================================
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
_ViewStart
<hr />
================================================
FILE: Test.WebApp/Web.config
================================================
<?xml version="1.0" encoding="utf-8"?>
<!--
For more information on how to configure your ASP.NET application, please visit
http://go.microsoft.com/fwlink/?LinkId=301880
-->
<configuration>
<configSections>
<section name="stackExchange.precompiler" type="StackExchange.Precompilation.PrecompilerSection, StackExchange.Precompilation" />
</configSections>
<stackExchange.precompiler>
<modules>
<add type="Test.Module.TestCompileModule, Test.Module" />
</modules>
</stackExchange.precompiler>
<appSettings>
<add key="owin:AutomaticAppStartup" value="false" />
<add key="webpages:Version" value="3.0.0.0" />
<add key="webpages:Enabled" value="true" />
</appSettings>
<!--
For a description of web.config changes see http://go.microsoft.com/fwlink/?LinkId=235367.
The following attributes can be set on the <httpRuntime> tag.
<system.Web>
<httpRuntime targetFramework="4.5.2" />
</system.Web>
-->
<system.web>
<authentication mode="None" />
<httpRuntime targetFramework="4.6.2" />
<compilation debug="true" targetFramework="4.6.2">
<assemblies>
<add assembly="System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<add assembly="System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</assemblies>
</compilation>
</system.web>
<!-- /langversion needed for cshtml editor -->
<system.codedom>
<compilers>
<compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CSharp.CSharpCodeProvider, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" warningLevel="4" compilerOptions="/langversion:7 /nowarn:1659;1699;1701" />
</compilers>
</system.codedom>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.IO.Compression" publicKeyToken="b77a5c561934e089" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.1.0" newVersion="4.1.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Runtime.Extensions" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.1.0" newVersion="4.1.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Runtime.InteropServices" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Reflection" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.1.0" newVersion="4.1.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Security.Cryptography.Algorithms" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.2.1.0" newVersion="1.2.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.IO.FileSystem" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.IO.FileSystem.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Security.Cryptography.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Xml.XPath.XDocument" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Diagnostics.FileVersionInfo" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.ValueTuple" culture="neutral" publicKeyToken="cc7b13ffcd2ddd51" />
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
================================================
FILE: Test.WebApp.ExternalViews/App_Code/Helpers.cshtml
================================================
@helper Test()
{
<div>HELPERS</div>
}
================================================
FILE: Test.WebApp.ExternalViews/ExternalViews.cs
================================================
namespace Test.WebApp
{
public class ExternalViews
{
}
}
================================================
FILE: Test.WebApp.ExternalViews/Test.WebApp.ExternalViews.csproj
================================================
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Test.WebApp</RootNamespace>
<TargetFramework>net462</TargetFramework>
<DebugType>portable</DebugType>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\StackExchange.Precompilation.Build\StackExchange.Precompilation.Build.csproj">
<Project>{31dfcccc-2f44-405e-a2d7-bb1ac718e7b9}</Project>
<Name>StackExchange.Precompilation.Build</Name>
</ProjectReference>
<ProjectReference Include="..\StackExchange.Precompilation\StackExchange.Precompilation.csproj">
<Project>{3c0a90f1-b19e-4305-ab71-3cd31c7d0f4d}</Project>
<Name>StackExchange.Precompilation</Name>
</ProjectReference>
<ProjectReference Include="..\StackExhcange.Precompilation.MVC5\StackExchange.Precompilation.MVC5.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Web" />
<PackageReference Include="Microsoft.AspNet.Mvc" Version="5.2.7" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="2.10.0" />
</ItemGroup>
<PropertyGroup>
<SEPrecompilerPath Condition="'$(SEPrecompilerPath)' == ''">$(SolutionDir)StackExchange.Precompilation.Build\bin\$(Configuration)\$(TargetFramework)\</SEPrecompilerPath>
<!-- Always precompile -->
<SEPrecompilerIncludeRazor>true</SEPrecompilerIncludeRazor>
</PropertyGroup>
<Import Project="..\StackExchange.Precompilation.Build\StackExchange.Precompilation.Build.targets" />
</Project>
================================================
FILE: Test.WebApp.ExternalViews/Views/Shared/ExternalPartial.cshtml
================================================
ExternalPartial.cshtml
================================================
FILE: Test.WebApp.ExternalViews/Views/Shared/ExternalView.cshtml
================================================
ExternalView.cshtml
@{ Html.RenderPartial("ExternalPartial"); }
================================================
FILE: Test.WebApp.ExternalViews/Views/Web.config
================================================
<?xml version="1.0"?>
<configuration>
<configSections>
<sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
<section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
</sectionGroup>
</configSections>
<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
</namespaces>
</pages>
</system.web.webPages.razor>
<appSettings>
<add key="webpages:Enabled" value="false" />
</appSettings>
<system.webServer>
<handlers>
<remove name="BlockViewHandler"/>
<add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
</handlers>
</system.webServer>
</configuration>
================================================
FILE: appveyor.yml
================================================
version: '{build}'
image: Visual Studio 2017
assembly_info:
patch: true
file: '**\AssemblyInfo.*'
assembly_version: $(semver)
assembly_file_version: $(semver).{build}
assembly_informational_version: '{version}'
init:
- git config --global core.autocrlf input
install:
- ps: >-
set -name semver -scope global -value (get-content .\semver.txt)
$env:semver = $semver
if ("$env:appveyor_repo_tag_name" -ne "releases/$semver") {
$env:package_suffix = "-alpha$env:appveyor_build_number" }
update-appveyorbuild -Version "$env:semver$env:package_suffix"
nuget:
disable_publish_on_pr: true
build_script:
- ps: .\BuildAndPack.ps1 -VersionSuffix "$env:package_suffix" -GitCommitId "$env:appveyor_repo_commit" -MsBuildArgs @(, "/logger:C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll") -CIBuild
skip_branch_with_pr: true
skip_tags: false
skip_commits:
files:
- '**/*.md'
artifacts:
- path: packages/obj/*.nupkg
deploy:
- provider: NuGet
name: alpha
on:
branch: master
server: https://www.myget.org/F/stackoverflow/api/v2
api_key:
secure: P/UHxq2DEs0GI1SoDXDesHjRVsSVgdywz5vmsnhFQQY5aJgO3kP+QfhwfhXz19Rw
symbol_server: https://www.myget.org/F/stackoverflow/symbols/api/v2/package
- provider: NuGet
name: release
on:
appveyor_repo_tag: true
server: https://www.myget.org/F/stackoverflow/api/v2
api_key:
secure: P/UHxq2DEs0GI1SoDXDesHjRVsSVgdywz5vmsnhFQQY5aJgO3kP+QfhwfhXz19Rw
symbol_server: https://www.myget.org/F/stackoverflow/symbols/api/v2/package
================================================
FILE: license.txt
================================================
The MIT License (MIT)
Copyright (c) 2015 Stack Exchange
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
================================================
FILE: semver.txt
================================================
5.1.0
gitextract_e7pohamh/ ├── .gitignore ├── BuildAndPack.ps1 ├── Directory.Build.props ├── README.md ├── Release.ps1 ├── StackExchange.Precompilation/ │ ├── AfterCompileContext.cs │ ├── AppDomainHelper.cs │ ├── Attributes.cs │ ├── BeforeCompileContext.cs │ ├── CompileContext.cs │ ├── CompileModuleElement.cs │ ├── CompileModulesCollection.cs │ ├── CompiledFromDirectoryAttribute.cs │ ├── CompiledFromFileAttribute.cs │ ├── ICompileContext.cs │ ├── ICompileModule.cs │ ├── IMetadataReference.cs │ ├── PrecompilationModuleLoader.cs │ ├── PrecompilerSection.cs │ ├── RazorCacheElement.cs │ └── StackExchange.Precompilation.csproj ├── StackExchange.Precompilation.Build/ │ ├── App.config │ ├── Attributes.cs │ ├── Compilation.cs │ ├── CompilationAssemblyResolver.cs │ ├── CompilationProxy.cs │ ├── ICompilationProxy.cs │ ├── PrecompilationCommandLineArgs.cs │ ├── PrecompilationCommandLineParser.cs │ ├── Program.cs │ ├── StackExchange.Precompilation.Build.csproj │ ├── StackExchange.Precompilation.Build.packages.config │ └── StackExchange.Precompilation.Build.targets ├── StackExchange.Precompilation.Tests/ │ ├── CommandLineTests.cs │ └── StackExchange.Precompilation.Tests.csproj ├── StackExchange.Precompilation.sln ├── StackExhcange.Precompilation.MVC5/ │ ├── Hacks.cs │ ├── PrecompilationView.cs │ ├── PrecompilationVirtualPathFactory.cs │ ├── PrecompiledViewEngine.cs │ ├── ProfiledVirtualPathProviderViewEngine.cs │ ├── RazorParser.cs │ ├── RoslynRazorViewEngine.cs │ └── StackExchange.Precompilation.MVC5.csproj ├── Test.ConsoleApp/ │ ├── AliasTest.cs │ ├── App.config │ ├── Program.cs │ └── Test.ConsoleApp.csproj ├── Test.Module/ │ ├── Test.Module.csproj │ └── TestCompileModule.cs ├── Test.WebApp/ │ ├── Content/ │ │ └── PartialExternalContent.cshtml │ ├── Controllers/ │ │ └── HomeController.cs │ ├── Models/ │ │ └── SampleModel.cs │ ├── MvcApplication.cs │ ├── Properties/ │ │ └── AssemblyInfo.cs │ ├── Test.WebApp.csproj │ ├── Views/ │ │ ├── Home/ │ │ │ ├── ExcludedLayout.cshtml │ │ │ ├── Index.Mobile.cshtml │ │ │ └── Index.cshtml │ │ ├── Other/ │ │ │ └── RelativePartial.cshtml │ │ ├── Shared/ │ │ │ ├── EditorTemplates/ │ │ │ │ ├── SampleModel.Mobile.cshtml │ │ │ │ ├── SampleModel.cshtml │ │ │ │ └── String.cshtml │ │ │ ├── _Footer.Mobile.cshtml │ │ │ ├── _Footer.cshtml │ │ │ ├── _Layout.Excluded.cshtml │ │ │ ├── _Layout.Mobile.cshtml │ │ │ ├── _Layout.Overridden.cshtml │ │ │ └── _Layout.cshtml │ │ ├── Web.config │ │ └── _ViewStart.cshtml │ └── Web.config ├── Test.WebApp.ExternalViews/ │ ├── App_Code/ │ │ └── Helpers.cshtml │ ├── ExternalViews.cs │ ├── Test.WebApp.ExternalViews.csproj │ └── Views/ │ ├── Shared/ │ │ ├── ExternalPartial.cshtml │ │ └── ExternalView.cshtml │ └── Web.config ├── appveyor.yml ├── license.txt └── semver.txt
SYMBOL INDEX (164 symbols across 35 files)
FILE: StackExchange.Precompilation.Build/Compilation.cs
class Compilation (line 23) | internal class Compilation
method Compilation (line 60) | public Compilation(PrecompilationCommandLineArgs precompilationCommand...
method RunAsync (line 74) | public async Task<bool> RunAsync(CancellationToken cancellationToken =...
class CompilationAnalyzerService (line 257) | [ExportWorkspaceService(typeof(IAnalyzerService), WorkspaceKind), Shared]
method GetLoader (line 262) | public IAnalyzerAssemblyLoader GetLoader() => _loader;
class CompilationAnalyzerAssemblyLoader (line 265) | private class CompilationAnalyzerAssemblyLoader : IAnalyzerAssemblyLoader
method ResolvePath (line 270) | private string ResolvePath(string path) => Path.IsPathRooted(path) ?...
method AddDependencyLocation (line 272) | public void AddDependencyLocation(string fullPath) => _desktopLoader...
method LoadFromPath (line 274) | public Assembly LoadFromPath(string fullPath) => _desktopLoader.Load...
method CreateCompositionHost (line 277) | private CompositionHost CreateCompositionHost()
method CreateWokspace (line 312) | private static AdhocWorkspace CreateWokspace(CompositionHost container)
method CreateProject (line 320) | private Project CreateProject(AdhocWorkspace workspace, List<IDocument...
method TryOpenFile (line 335) | private bool TryOpenFile(string path, out Stream stream)
method CreateWin32Resource (line 359) | private Stream CreateWin32Resource(CSharpCompilation compilation)
method DumpToFileAsync (line 368) | private static async Task DumpToFileAsync(string path, MemoryStream st...
class NaiveReferenceResolver (line 381) | private sealed class NaiveReferenceResolver : MetadataReferenceResolver
method NaiveReferenceResolver (line 383) | private NaiveReferenceResolver() { }
method Equals (line 385) | public override bool Equals(object other) => other is NaiveReference...
method GetHashCode (line 387) | public override int GetHashCode() => 42;
method ResolveReference (line 389) | public override ImmutableArray<PortableExecutableReference> ResolveR...
method GeneratedSyntaxTrees (line 393) | private IEnumerable<SyntaxTree> GeneratedSyntaxTrees()
method AsLocation (line 398) | public Location AsLocation(string path)
type IDocumentExtender (line 404) | public interface IDocumentExtender : ILanguageService
method Extend (line 406) | DocumentInfo Extend(DocumentInfo document);
method Complete (line 407) | Task<ICollection<Diagnostic>> Complete();
FILE: StackExchange.Precompilation.Build/CompilationAssemblyResolver.cs
class CompilationAssemblyResolver (line 11) | class CompilationAssemblyResolver : MarshalByRefObject
method Register (line 13) | internal static void Register(AppDomain domain, string[] references)
method Setup (line 26) | private void Setup(string[] references)
method RegisterDomain (line 85) | private void RegisterDomain(AppDomain domain)
method ApplyPolicy (line 91) | private string ApplyPolicy(string name)
method ResolveAssembly (line 100) | private Assembly ResolveAssembly(object sender, ResolveEventArgs e)
method NullAssembly (line 109) | private static Lazy<Assembly> NullAssembly(string key) => new Lazy<Ass...
FILE: StackExchange.Precompilation.Build/CompilationProxy.cs
class CompilationProxy (line 10) | class CompilationProxy : MarshalByRefObject
method RunCs (line 12) | public static bool RunCs(string[] args)
method InitializeLifetimeService (line 66) | public override object InitializeLifetimeService() => null;
method RunCs (line 72) | private bool RunCs(PrecompilationCommandLineArgs precompilationArgs)
method ForceStop (line 78) | private void ForceStop()
FILE: StackExchange.Precompilation.Build/ICompilationProxy.cs
type ICompilationProxy (line 3) | interface ICompilationProxy
method InitializeLifetimeService (line 5) | object InitializeLifetimeService();
FILE: StackExchange.Precompilation.Build/PrecompilationCommandLineArgs.cs
class PrecompilationCommandLineArgs (line 5) | [Serializable]
FILE: StackExchange.Precompilation.Build/PrecompilationCommandLineParser.cs
class PrecompilationCommandLineParser (line 12) | public class PrecompilationCommandLineParser
method SplitCommandLine (line 18) | public static string[] SplitCommandLine(string commandLine)
method Split (line 30) | private static IEnumerable<string> Split(string commandLine)
method Parse (line 76) | public static PrecompilationCommandLineArgs Parse(string[] arguments, ...
method ParseFileFromArg (line 107) | private static string ParseFileFromArg(string arg, char delimiter = ':')
FILE: StackExchange.Precompilation.Build/Program.cs
class Program (line 9) | static class Program
method Main (line 11) | static void Main(string[] args)
FILE: StackExchange.Precompilation.Tests/CommandLineTests.cs
class CommandLineTests (line 8) | [TestFixture]
method SplitArguments (line 12) | [Test]
method ParseArguments (line 29) | [Test]
method ParseArgumentCases (line 38) | [Test]
FILE: StackExchange.Precompilation/AfterCompileContext.cs
class AfterCompileContext (line 8) | public class AfterCompileContext : ICompileContext
FILE: StackExchange.Precompilation/AppDomainHelper.cs
class AppDomainHelper (line 8) | public static class AppDomainHelper
method IsPrecompilation (line 19) | public static bool IsPrecompilation(this AppDomain appDomain)
FILE: StackExchange.Precompilation/BeforeCompileContext.cs
class BeforeCompileContext (line 7) | public class BeforeCompileContext : ICompileContext
FILE: StackExchange.Precompilation/CompileContext.cs
class CompileContext (line 8) | internal class CompileContext
method CompileContext (line 13) | public CompileContext(ICollection<ICompileModule> modules)
method Before (line 17) | public void Before(BeforeCompileContext context)
method After (line 21) | public void After(AfterCompileContext context)
method Apply (line 25) | private void Apply<TContext>(TContext ctx, Action<TContext> setter, Fu...
class PrecompilationModuleException (line 45) | internal class PrecompilationModuleException : Exception
method PrecompilationModuleException (line 47) | public PrecompilationModuleException(string message, Exception inner) ...
FILE: StackExchange.Precompilation/CompileModuleElement.cs
class CompileModuleElement (line 9) | public class CompileModuleElement : ConfigurationElement
FILE: StackExchange.Precompilation/CompileModulesCollection.cs
class CompileModulesCollection (line 8) | public class CompileModulesCollection : ConfigurationElementCollection
method CreateNewElement (line 10) | protected override ConfigurationElement CreateNewElement()
method GetElementKey (line 15) | protected override object GetElementKey(ConfigurationElement element)
FILE: StackExchange.Precompilation/CompiledFromDirectoryAttribute.cs
class CompiledFromDirectoryAttribute (line 8) | [AttributeUsage(AttributeTargets.Assembly)]
method CompiledFromDirectoryAttribute (line 18) | public CompiledFromDirectoryAttribute(string sourceDirectory)
FILE: StackExchange.Precompilation/CompiledFromFileAttribute.cs
class CompiledFromFileAttribute (line 8) | [AttributeUsage(AttributeTargets.Class)]
method CompiledFromFileAttribute (line 18) | public CompiledFromFileAttribute(string sourceFile)
FILE: StackExchange.Precompilation/ICompileContext.cs
type ICompileContext (line 7) | public interface ICompileContext
FILE: StackExchange.Precompilation/ICompileModule.cs
type ICompileModule (line 22) | public interface ICompileModule
method BeforeCompile (line 28) | void BeforeCompile(BeforeCompileContext context);
method AfterCompile (line 35) | void AfterCompile(AfterCompileContext context);
FILE: StackExchange.Precompilation/PrecompilationModuleLoader.cs
class PrecompilationModuleLoader (line 7) | internal class PrecompilationModuleLoader
method PrecompilationModuleLoader (line 19) | public PrecompilationModuleLoader(PrecompilerSection configuration)
FILE: StackExchange.Precompilation/PrecompilerSection.cs
class PrecompilerSection (line 9) | public class PrecompilerSection : ConfigurationSection
FILE: StackExchange.Precompilation/RazorCacheElement.cs
class RazorCacheElement (line 5) | public class RazorCacheElement : ConfigurationElement
FILE: StackExhcange.Precompilation.MVC5/Hacks.cs
class Hacks (line 9) | static class Hacks
method SetOverriddenLayoutPath (line 25) | public static void SetOverriddenLayoutPath(WebViewPage webViewPage, st...
method MakeValueTuplesWorkWhenRunningOn47RuntimeAndTargetingNet45Plus (line 45) | public static CSharpCompilation MakeValueTuplesWorkWhenRunningOn47Runt...
FILE: StackExhcange.Precompilation.MVC5/PrecompilationView.cs
class PrecompilationView (line 7) | internal class PrecompilationView : IView
method PrecompilationView (line 15) | public PrecompilationView(string virtualPath, string masterPath, Type ...
method CreatePage (line 24) | private WebPageBase CreatePage(ViewContext viewContext, System.IO.Text...
method Render (line 52) | public void Render(ViewContext viewContext, System.IO.TextWriter writer)
FILE: StackExhcange.Precompilation.MVC5/PrecompilationVirtualPathFactory.cs
class PrecompilationVirtualPathFactory (line 18) | internal class PrecompilationVirtualPathFactory : IVirtualPathFactory
method PrecompilationVirtualPathFactory (line 23) | public PrecompilationVirtualPathFactory(PrecompiledViewEngine precompi...
method CreateInstance (line 29) | public object CreateInstance(string virtualPath)
method Exists (line 45) | public bool Exists(string virtualPath)
FILE: StackExhcange.Precompilation.MVC5/PrecompiledViewEngine.cs
class PrecompiledViewEngine (line 19) | public class PrecompiledViewEngine : ProfiledVirtualPathProviderViewEngine
method PrecompiledViewEngine (line 36) | public PrecompiledViewEngine(string findAssembliesInPath)
method PrecompiledViewEngine (line 46) | public PrecompiledViewEngine(params Assembly[] assemblies)
method CreateVirtualPathFactory (line 115) | protected override IVirtualPathFactory CreateVirtualPathFactory() => n...
method MakeVirtualPath (line 119) | private static string MakeVirtualPath(string absoluteViewPath, string ...
method MakeVirtualPath (line 141) | private static string MakeVirtualPath(string absoluteViewPath, int sta...
method FindViewAssemblies (line 149) | private static List<Assembly> FindViewAssemblies(string dirPath)
method CreatePartialView (line 197) | protected override IView CreatePartialView(ControllerContext controlle...
method CreateView (line 201) | protected override IView CreateView(ControllerContext controllerContex...
method TryLookupCompiledType (line 205) | internal Type TryLookupCompiledType(string viewPath)
method CreateViewImpl (line 215) | private IView CreateViewImpl(string viewPath, string masterPath, bool ...
method FindPartialView (line 227) | public override ViewEngineResult FindPartialView(ControllerContext con...
method FindView (line 248) | public override ViewEngineResult FindView(ControllerContext controller...
method ResolveViewPath (line 280) | private string ResolveViewPath(string viewName, string areaName, strin...
method TryResolveView (line 319) | private bool TryResolveView(HttpContextBase httpContext, IDisplayMode ...
method NormalizeViewName (line 334) | private static string NormalizeViewName(string viewName)
method IsSpecificPath (line 339) | private static bool IsSpecificPath(string path) => path.Length > 0 && ...
class AreaHelpers (line 343) | internal static class AreaHelpers
method GetAreaName (line 345) | public static string GetAreaName(RouteBase route)
method GetAreaName (line 355) | public static string GetAreaName(RouteData routeData)
FILE: StackExhcange.Precompilation.MVC5/ProfiledVirtualPathProviderViewEngine.cs
class ProfiledVirtualPathProviderViewEngine (line 10) | public abstract class ProfiledVirtualPathProviderViewEngine : VirtualPat...
method CreateVirtualPathFactory (line 19) | protected abstract IVirtualPathFactory CreateVirtualPathFactory();
method ProfiledVirtualPathProviderViewEngine (line 24) | protected ProfiledVirtualPathProviderViewEngine()
class ProfileVirtualPathProviderViewEngineExtensions (line 30) | internal static class ProfileVirtualPathProviderViewEngineExtensions
method DoProfileStep (line 35) | public static IDisposable DoProfileStep(this ProfiledVirtualPathProvid...
FILE: StackExhcange.Precompilation.MVC5/RazorParser.cs
class RazorParserFactory (line 23) | [ExportLanguageServiceFactoryAttribute(typeof(IDocumentExtender), Langua...
method CreateLanguageService (line 26) | public ILanguageService CreateLanguageService(HostLanguageServices lan...
class RazorParser (line 30) | class RazorParser : IDocumentExtender, IDisposable
method RazorParser (line 39) | public RazorParser(Workspace workspace)
method BackgroundWorker (line 63) | private async Task BackgroundWorker()
method Dispose (line 106) | void IDisposable.Dispose()
method CachedRazorWorker (line 111) | private async Task<Stream> CachedRazorWorker(RazorEngineHost host, Tex...
method ReportDiagnostic (line 185) | private void ReportDiagnostic(Diagnostic d) => _diagnostics.Add(d);
method RazorWorker (line 187) | private Task<Stream> RazorWorker(RazorEngineHost host, TextAndVersion ...
method RazorWorkerImpl (line 190) | private Task<(bool success, Stream result)> RazorWorkerImpl(RazorEngin...
method GetRelativeUri (line 248) | private string GetRelativeUri(string filespec, string folder)
method Extend (line 259) | public DocumentInfo Extend(DocumentInfo document)
method Complete (line 268) | public async Task<System.Collections.Generic.ICollection<Diagnostic>> ...
method EnsureWorkers (line 278) | private Task EnsureWorkers() => _backgroundWorkers.Value;
class RazorTextLoader (line 280) | private sealed class RazorTextLoader : TextLoader
method RazorTextLoader (line 287) | public RazorTextLoader(RazorParser parser, TextLoader originalLoader)
method LoadTextAndVersionAsync (line 295) | public override Task<TextAndVersion> LoadTextAndVersionAsync(Workspa...
FILE: StackExhcange.Precompilation.MVC5/RoslynRazorViewEngine.cs
class RoslynRazorViewEngine (line 29) | public class RoslynRazorViewEngine : ProfiledVirtualPathProviderViewEngine
method RoslynRazorViewEngine (line 34) | public RoslynRazorViewEngine()
method CreateVirtualPathFactory (line 74) | protected override IVirtualPathFactory CreateVirtualPathFactory() => n...
method CreatePartialView (line 79) | protected override IView CreatePartialView(ControllerContext controlle...
method CreateView (line 83) | protected override IView CreateView(ControllerContext controllerContex...
method FileExists (line 86) | internal bool FileExists(string virtualPath) =>
method GetTypeFromVirtualPath (line 89) | internal Type GetTypeFromVirtualPath(string virtualPath)
method GetTypeFromVirtualPathNoCache (line 107) | private Type GetTypeFromVirtualPathNoCache(string virtualPath)
method RunRazorGenerator (line 122) | private GeneratorResults RunRazorGenerator(string virtualPath, WebPage...
method GetSyntaxTree (line 145) | private static SyntaxTree GetSyntaxTree(WebPageRazorHost host, Generat...
method ResolveReference (line 171) | internal static MetadataReference ResolveReference(Assembly assembly)
method CompileToAssembly (line 186) | private static Assembly CompileToAssembly(WebPageRazorHost host, Synta...
method CreateExceptionFromParserError (line 241) | private static HttpParseException CreateExceptionFromParserError(Razor...
method OnBeforeCompilePath (line 253) | protected virtual void OnBeforeCompilePath(CompilingPathEventArgs args...
method OnCodeGenerationStarted (line 261) | private void OnCodeGenerationStarted() =>
method OnCodeGenerationCompleted (line 269) | private void OnCodeGenerationCompleted(CodeCompileUnit codeCompileUnit...
FILE: Test.ConsoleApp/AliasTest.cs
class AliasTest (line 6) | class AliasTest
FILE: Test.ConsoleApp/Program.cs
class Program (line 7) | class Program
method Main (line 9) | static void Main(string[] args)
method PathMapTest (line 18) | static string PathMapTest([CallerFilePath] string path = null) =>
FILE: Test.Module/TestCompileModule.cs
class TestCompileModule (line 10) | public class TestCompileModule : ICompileModule
method BeforeCompile (line 12) | public void BeforeCompile(BeforeCompileContext context)
method AfterCompile (line 41) | public void AfterCompile(AfterCompileContext context)
FILE: Test.WebApp.ExternalViews/ExternalViews.cs
class ExternalViews (line 3) | public class ExternalViews
FILE: Test.WebApp/Controllers/HomeController.cs
class HomeController (line 9) | public class HomeController : Controller
method Index (line 11) | public ActionResult Index()
method IndexOverridden (line 24) | public ActionResult IndexOverridden()
method ExcludedLayout (line 34) | public ActionResult ExcludedLayout() => View();
FILE: Test.WebApp/Models/SampleModel.cs
class SampleModel (line 5) | public class SampleModel
FILE: Test.WebApp/MvcApplication.cs
class MvcApplicationInitializer (line 9) | public static class MvcApplicationInitializer
method PreApplicationStart (line 11) | public static void PreApplicationStart() =>
class MvcApplication (line 15) | public class MvcApplication : HttpApplication
method Application_Start (line 24) | protected void Application_Start()
Condensed preview — 81 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (167K chars).
[
{
"path": ".gitignore",
"chars": 107,
"preview": "*.suo\n*/bin/\n*/obj/\n*.orig\n*.user\n*.nupkg\n*.GhostDoc.xml\nMoonSpeak.sln.ide/\ntools\npackages\n.vs\n_ReSharper*\n"
},
{
"path": "BuildAndPack.ps1",
"chars": 1235,
"preview": "param(\n [parameter(Position=0)]\n [string] $VersionSuffix,\n [parameter(Position=1)]\n [string] $GitCommitId,\n "
},
{
"path": "Directory.Build.props",
"chars": 2555,
"preview": "<Project>\n <PropertyGroup>\n <DebugSymbols>true</DebugSymbols>\n <DebugType>full</DebugType>\n <IsPackable>false<"
},
{
"path": "README.md",
"chars": 2524,
"preview": "StackExchange.Precompilation\n============================\n\n[\n\ngit tag -a \"releases/$semver\" -m \"creating $s"
},
{
"path": "StackExchange.Precompilation/AfterCompileContext.cs",
"chars": 620,
"preview": "using System.Collections.Generic;\nusing System.IO;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\n\nn"
},
{
"path": "StackExchange.Precompilation/AppDomainHelper.cs",
"chars": 786,
"preview": "using System;\n\nnamespace StackExchange.Precompilation\n{\n /// <summary>\n /// Precompilation helper methods.\n ///"
},
{
"path": "StackExchange.Precompilation/Attributes.cs",
"chars": 316,
"preview": "[assembly:System.Runtime.CompilerServices.InternalsVisibleToAttribute(\"StackExchange.Precompiler\")]\n[assembly:System.Run"
},
{
"path": "StackExchange.Precompilation/BeforeCompileContext.cs",
"chars": 407,
"preview": "using System.Collections.Generic;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\n\nnamespace StackExc"
},
{
"path": "StackExchange.Precompilation/CompileContext.cs",
"chars": 1814,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace StackExchange.Precompilation\n{\n\n intern"
},
{
"path": "StackExchange.Precompilation/CompileModuleElement.cs",
"chars": 550,
"preview": "using System.Configuration;\n\nnamespace StackExchange.Precompilation\n{\n /// <summary>\n /// A compile module configu"
},
{
"path": "StackExchange.Precompilation/CompileModulesCollection.cs",
"chars": 555,
"preview": "using System.Configuration;\n\nnamespace StackExchange.Precompilation\n{\n /// <summary>\n /// A collection of <see cre"
},
{
"path": "StackExchange.Precompilation/CompiledFromDirectoryAttribute.cs",
"chars": 670,
"preview": "using System;\n\nnamespace StackExchange.Precompilation\n{\n /// <summary>\n /// Decorates a precompiled MVC assembly."
},
{
"path": "StackExchange.Precompilation/CompiledFromFileAttribute.cs",
"chars": 585,
"preview": "using System;\n\nnamespace StackExchange.Precompilation\n{\n /// <summary>\n /// Decorates a precompiled MVC page.\n "
},
{
"path": "StackExchange.Precompilation/ICompileContext.cs",
"chars": 345,
"preview": "using System.Collections.Generic;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\n\nnamespace StackEx"
},
{
"path": "StackExchange.Precompilation/ICompileModule.cs",
"chars": 1341,
"preview": "namespace StackExchange.Precompilation\n{\n /// <summary>\n /// Allows plugging into the compilation pipeline. Has to"
},
{
"path": "StackExchange.Precompilation/IMetadataReference.cs",
"chars": 1,
"preview": ""
},
{
"path": "StackExchange.Precompilation/PrecompilationModuleLoader.cs",
"chars": 2080,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace StackExchange.Precompilation\n{\n interna"
},
{
"path": "StackExchange.Precompilation/PrecompilerSection.cs",
"chars": 1088,
"preview": "using System.Configuration;\n\nnamespace StackExchange.Precompilation\n{\n /// <summary>\n /// Defines the <c>stackExch"
},
{
"path": "StackExchange.Precompilation/RazorCacheElement.cs",
"chars": 420,
"preview": "using System.Configuration;\n\nnamespace StackExchange.Precompilation\n{\n public class RazorCacheElement : Configuration"
},
{
"path": "StackExchange.Precompilation/StackExchange.Precompilation.csproj",
"chars": 666,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project Sdk=\"Microsoft.NET.Sdk\">\n <PropertyGroup>\n <TargetFrameworks>net462"
},
{
"path": "StackExchange.Precompilation.Build/App.config",
"chars": 287,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n <startup>\n <supportedRuntime version=\"v4.0\" sku=\".NET"
},
{
"path": "StackExchange.Precompilation.Build/Attributes.cs",
"chars": 107,
"preview": "[assembly:System.Runtime.CompilerServices.InternalsVisibleToAttribute(\"StackExchange.Precompilation.MVC5\")]"
},
{
"path": "StackExchange.Precompilation.Build/Compilation.cs",
"chars": 21399,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Reflection;\nusing Syste"
},
{
"path": "StackExchange.Precompilation.Build/CompilationAssemblyResolver.cs",
"chars": 4249,
"preview": "using System;\nusing System.Collections.Concurrent;\nusing System.IO;\nusing System.Linq;\nusing System.Reflection;\nusing S"
},
{
"path": "StackExchange.Precompilation.Build/CompilationProxy.cs",
"chars": 3408,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Reflection;\nusing Syste"
},
{
"path": "StackExchange.Precompilation.Build/ICompilationProxy.cs",
"chars": 131,
"preview": "namespace StackExchange.Precompilation\n{\n interface ICompilationProxy\n {\n object InitializeLifetimeService"
},
{
"path": "StackExchange.Precompilation.Build/PrecompilationCommandLineArgs.cs",
"chars": 749,
"preview": "using System;\n\nnamespace StackExchange.Precompilation\n{\n [Serializable]\n public class PrecompilationCommandLineArg"
},
{
"path": "StackExchange.Precompilation.Build/PrecompilationCommandLineParser.cs",
"chars": 4696,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Text.RegularExpressions"
},
{
"path": "StackExchange.Precompilation.Build/Program.cs",
"chars": 1066,
"preview": "using System;\nusing System.IO;\nusing System.Linq;\nusing System.Reflection;\nusing Microsoft.CodeAnalysis.CSharp;\n\nnamesp"
},
{
"path": "StackExchange.Precompilation.Build/StackExchange.Precompilation.Build.csproj",
"chars": 1577,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project Sdk=\"Microsoft.NET.Sdk\">\n<PropertyGroup>\n <OutputType>Exe</OutputTyp"
},
{
"path": "StackExchange.Precompilation.Build/StackExchange.Precompilation.Build.packages.config",
"chars": 431,
"preview": " <!--\n HACK\n\n We need to include the native DiaSymReader Native runtime files in order to support sourcelink etc"
},
{
"path": "StackExchange.Precompilation.Build/StackExchange.Precompilation.Build.targets",
"chars": 2132,
"preview": "<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n <PropertyGroup>\n <!-- CREDITS:\n "
},
{
"path": "StackExchange.Precompilation.Tests/CommandLineTests.cs",
"chars": 3211,
"preview": "using System;\nusing System.IO;\nusing System.Linq;\nusing NUnit.Framework;\n\nnamespace StackExchange.Precompilation.Tests\n"
},
{
"path": "StackExchange.Precompilation.Tests/StackExchange.Precompilation.Tests.csproj",
"chars": 724,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project Sdk=\"Microsoft.NET.Sdk\">\n <PropertyGroup>\n <TargetFramework>net462<"
},
{
"path": "StackExchange.Precompilation.sln",
"chars": 6025,
"preview": "\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio 15\nVisualStudioVersion = 15.0.27428.2015\nM"
},
{
"path": "StackExhcange.Precompilation.MVC5/Hacks.cs",
"chars": 3191,
"preview": "using Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\nusing System;\nusing System.Reflection;\nusing System."
},
{
"path": "StackExhcange.Precompilation.MVC5/PrecompilationView.cs",
"chars": 2390,
"preview": "using System;\nusing System.Web.Mvc;\nusing System.Web.WebPages;\n\nnamespace StackExchange.Precompilation\n{\n internal c"
},
{
"path": "StackExhcange.Precompilation.MVC5/PrecompilationVirtualPathFactory.cs",
"chars": 2354,
"preview": "using System;\nusing System.Web.WebPages;\n\nnamespace StackExchange.Precompilation\n{\n /// <summary>\n /// <see cref="
},
{
"path": "StackExhcange.Precompilation.MVC5/PrecompiledViewEngine.cs",
"chars": 14990,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Globalization;\nusing System.IO;\n"
},
{
"path": "StackExhcange.Precompilation.MVC5/ProfiledVirtualPathProviderViewEngine.cs",
"chars": 1453,
"preview": "using System;\nusing System.Web.Mvc;\nusing System.Web.WebPages;\n\nnamespace StackExchange.Precompilation\n{\n /// <summa"
},
{
"path": "StackExhcange.Precompilation.MVC5/RazorParser.cs",
"chars": 13784,
"preview": "using System;\nusing System.Linq;\nusing System.CodeDom;\nusing System.CodeDom.Compiler;\nusing System.Collections.Concurren"
},
{
"path": "StackExhcange.Precompilation.MVC5/RoslynRazorViewEngine.cs",
"chars": 13102,
"preview": "using Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.Emit;\nusing Microsoft.C"
},
{
"path": "StackExhcange.Precompilation.MVC5/StackExchange.Precompilation.MVC5.csproj",
"chars": 976,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project Sdk=\"Microsoft.NET.Sdk\">\n <PropertyGroup>\n <TargetFramework>net462<"
},
{
"path": "Test.ConsoleApp/AliasTest.cs",
"chars": 184,
"preview": "#if NET462\nextern alias aliastest;\n\nnamespace Test.ConsoleApp\n{\n class AliasTest\n {\n public const string D"
},
{
"path": "Test.ConsoleApp/App.config",
"chars": 3852,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n <configSections>\n <section name=\"stackExchange.precom"
},
{
"path": "Test.ConsoleApp/Program.cs",
"chars": 671,
"preview": "using System;\nusing System.Runtime.CompilerServices;\nusing Test.Module;\n\nnamespace Test.ConsoleApp\n{\n class Program\n"
},
{
"path": "Test.ConsoleApp/Test.ConsoleApp.csproj",
"chars": 1565,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project Sdk=\"Microsoft.NET.Sdk\">\n <PropertyGroup>\n <RestoreProjectStyle>Pac"
},
{
"path": "Test.Module/Test.Module.csproj",
"chars": 449,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project Sdk=\"Microsoft.NET.Sdk\">\n <PropertyGroup>\n <TargetFrameworks>net462"
},
{
"path": "Test.Module/TestCompileModule.cs",
"chars": 1307,
"preview": "using System;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.Code"
},
{
"path": "Test.WebApp/Content/PartialExternalContent.cshtml",
"chars": 25,
"preview": "Partial External Content"
},
{
"path": "Test.WebApp/Controllers/HomeController.cs",
"chars": 1097,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Web.Mvc;\nusing StackExchange.Precompila"
},
{
"path": "Test.WebApp/Models/SampleModel.cs",
"chars": 169,
"preview": "using System.Collections.Generic;\n\nnamespace Test.WebApp.Models\n{\n public class SampleModel\n {\n public IEn"
},
{
"path": "Test.WebApp/MvcApplication.cs",
"chars": 1452,
"preview": "using System.Web;\nusing System.Web.Mvc;\nusing System.Web.Routing;\nusing StackExchange.Precompilation;\nusing Test.WebApp."
},
{
"path": "Test.WebApp/Properties/AssemblyInfo.cs",
"chars": 1521,
"preview": "using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\nusing System.Web;"
},
{
"path": "Test.WebApp/Test.WebApp.csproj",
"chars": 5254,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"15.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.micros"
},
{
"path": "Test.WebApp/Views/Home/ExcludedLayout.cshtml",
"chars": 88,
"preview": "\n@{\n Layout = \"~/Views/Shared/_Layout.Excluded.cshtml\";\n}\n\n<h2>ExcludedLayout</h2>\n\n"
},
{
"path": "Test.WebApp/Views/Home/Index.Mobile.cshtml",
"chars": 219,
"preview": "@model SampleModel\n@{\n ViewBag.Title = \"Test Page\";\n}\nMobile Precompiled View Paths:\n<ul>\n @foreach (var path in "
},
{
"path": "Test.WebApp/Views/Home/Index.cshtml",
"chars": 452,
"preview": "@model SampleModel\n@{\n ViewBag.Title = \"Test Page\";\n}\nPrecompiled View Paths:\n<ul>\n @foreach (var path in Model.V"
},
{
"path": "Test.WebApp/Views/Other/RelativePartial.cshtml",
"chars": 298,
"preview": "RelativePartial.cshtml\n@{\n @*\n code bellow is a repro case for a Razer parser errors, that were only caught\n i"
},
{
"path": "Test.WebApp/Views/Shared/EditorTemplates/SampleModel.Mobile.cshtml",
"chars": 510,
"preview": "@model Test.WebApp.Models.SampleModel\n<hr/>\nEditorTemplates.Mobile\n@using (Html.BeginForm())\n{\n @Html.AntiForgeryTok"
},
{
"path": "Test.WebApp/Views/Shared/EditorTemplates/SampleModel.cshtml",
"chars": 503,
"preview": "@model Test.WebApp.Models.SampleModel\n<hr/>\nEditorTemplates\n@using (Html.BeginForm())\n{\n @Html.AntiForgeryToken()\n "
},
{
"path": "Test.WebApp/Views/Shared/EditorTemplates/String.cshtml",
"chars": 104,
"preview": "@model System.String\n<div>\n <input readonly=\"readonly\" disabled=\"disabled\" value=\"@Model\" />\n</div>\n"
},
{
"path": "Test.WebApp/Views/Shared/_Footer.Mobile.cshtml",
"chars": 88,
"preview": "@model DateTime\n<footer>\n <p>© @Model.Year Mobile Partial Footer</p>\n</footer>\n"
},
{
"path": "Test.WebApp/Views/Shared/_Footer.cshtml",
"chars": 81,
"preview": "@model DateTime\n<footer>\n <p>© @Model.Year Partial Footer</p>\n</footer>\n"
},
{
"path": "Test.WebApp/Views/Shared/_Layout.Excluded.cshtml",
"chars": 31,
"preview": "Layout\n\n@RenderBody()\n\n/Layout"
},
{
"path": "Test.WebApp/Views/Shared/_Layout.Mobile.cshtml",
"chars": 361,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"utf-8\" />\n <title>@ViewBag.Title - Test.WebApp - Mobile</title>\n</h"
},
{
"path": "Test.WebApp/Views/Shared/_Layout.Overridden.cshtml",
"chars": 100,
"preview": "<h1>OVERRIDDDDDEN</h1>\n<h2>@ViewBag.Title - Test.WebApp</h2>\n@RenderBody()\n<h1>/OVERRIDDDDDEN</h1>\n"
},
{
"path": "Test.WebApp/Views/Shared/_Layout.cshtml",
"chars": 506,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"utf-8\" />\n <title>@ViewBag.Title - Test.WebApp</title>\n</head>\n<bod"
},
{
"path": "Test.WebApp/Views/Web.config",
"chars": 1706,
"preview": "<?xml version=\"1.0\"?>\n\n<configuration>\n <configSections>\n <sectionGroup name=\"system.web.webPages.razor\" type=\"Syst"
},
{
"path": "Test.WebApp/Views/_ViewStart.cshtml",
"chars": 70,
"preview": "@{\n Layout = \"~/Views/Shared/_Layout.cshtml\";\n}\n_ViewStart\n<hr />\n"
},
{
"path": "Test.WebApp/Web.config",
"chars": 5773,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n For more information on how to configure your ASP.NET application, please"
},
{
"path": "Test.WebApp.ExternalViews/App_Code/Helpers.cshtml",
"chars": 43,
"preview": "@helper Test()\n{\n <div>HELPERS</div>\n}\n"
},
{
"path": "Test.WebApp.ExternalViews/ExternalViews.cs",
"chars": 70,
"preview": "namespace Test.WebApp\n{\n public class ExternalViews\n {\n }\n}\n"
},
{
"path": "Test.WebApp.ExternalViews/Test.WebApp.ExternalViews.csproj",
"chars": 1607,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project Sdk=\"Microsoft.NET.Sdk\">\n <PropertyGroup>\n <OutputType>Library</Out"
},
{
"path": "Test.WebApp.ExternalViews/Views/Shared/ExternalPartial.cshtml",
"chars": 24,
"preview": "ExternalPartial.cshtml\n"
},
{
"path": "Test.WebApp.ExternalViews/Views/Shared/ExternalView.cshtml",
"chars": 64,
"preview": "ExternalView.cshtml\n@{ Html.RenderPartial(\"ExternalPartial\"); }"
},
{
"path": "Test.WebApp.ExternalViews/Views/Web.config",
"chars": 1579,
"preview": "<?xml version=\"1.0\"?>\n\n<configuration>\n <configSections>\n <sectionGroup name=\"system.web.webPages.razor\" type=\"Syst"
},
{
"path": "appveyor.yml",
"chars": 1535,
"preview": "version: '{build}'\nimage: Visual Studio 2017\nassembly_info:\n patch: true\n file: '**\\AssemblyInfo.*'\n assembly_version"
},
{
"path": "license.txt",
"chars": 1080,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2015 Stack Exchange\n\nPermission is hereby granted, free of charge, to any person ob"
},
{
"path": "semver.txt",
"chars": 6,
"preview": "5.1.0\n"
}
]
About this extraction
This page contains the full source code of the StackExchange/StackExchange.Precompilation GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 81 files (152.0 KB), approximately 37.5k tokens, and a symbol index with 164 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.