* Moving DNX dependencies to test only

* Updating Mvc tests to use dotnet test to run on dnxcore50
This commit is contained in:
Pranav K 2016-02-23 08:10:46 -08:00
parent c259f82615
commit 80b6996701
39 changed files with 696 additions and 1532 deletions

View File

@ -58,14 +58,6 @@ namespace Microsoft.Extensions.DependencyInjection
// To enable unit testing
internal static void AddMvcCoreServices(IServiceCollection services)
{
//
// RuntimeServices
//
if (DnxPlatformServices.Default?.LibraryManager != null)
{
services.TryAddSingleton(DnxPlatformServices.Default.LibraryManager);
}
//
// Options
//
@ -78,14 +70,7 @@ namespace Microsoft.Extensions.DependencyInjection
// Action Discovery
//
// These are consumed only when creating action descriptors, then they can be de-allocated
if (DnxPlatformServices.Default?.LibraryManager != null)
{
services.TryAddTransient<IAssemblyProvider, DefaultAssemblyProvider>();
}
else
{
services.TryAddTransient<IAssemblyProvider, DependencyContextAssemblyProvider>();
}
services.TryAddTransient<IAssemblyProvider, DefaultAssemblyProvider>();
services.TryAddTransient<IControllerTypeProvider, DefaultControllerTypeProvider>();
services.TryAddEnumerable(

View File

@ -6,17 +6,27 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using Microsoft.Extensions.DependencyModel;
using Microsoft.Extensions.PlatformAbstractions;
namespace Microsoft.AspNetCore.Mvc.Infrastructure
{
/// <summary>
/// An <see cref="IAssemblyProvider"/> that uses <see cref="DependencyContext"/> to discover assemblies that may
/// contain Mvc specific types such as controllers, and view components.
/// </summary>
public class DefaultAssemblyProvider : IAssemblyProvider
{
private readonly ILibraryManager _libraryManager;
private readonly DependencyContext _dependencyContext;
public DefaultAssemblyProvider(ILibraryManager libraryManager)
/// <summary>
/// Initializes a new instance of <see cref="DefaultAssemblyProvider"/>.
/// </summary>
/// <param name="environment">The <see cref="IApplicationEnvironment"/>.</param>
public DefaultAssemblyProvider(IApplicationEnvironment environment)
{
_libraryManager = libraryManager;
var applicationAssembly = Assembly.Load(new AssemblyName(environment.ApplicationName));
_dependencyContext = DependencyContext.Load(applicationAssembly);
}
/// <summary>
@ -49,8 +59,9 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
{
get
{
return GetCandidateLibraries().SelectMany(l => l.Assemblies)
.Select(Load);
return GetCandidateLibraries()
.SelectMany(l => l.Assemblies)
.Select(Load);
}
}
@ -60,29 +71,25 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
/// while ignoring MVC assemblies.
/// </summary>
/// <returns>A set of <see cref="Library"/>.</returns>
protected virtual IEnumerable<Library> GetCandidateLibraries()
protected virtual IEnumerable<RuntimeLibrary> GetCandidateLibraries()
{
if (ReferenceAssemblies == null)
{
return Enumerable.Empty<Library>();
return Enumerable.Empty<RuntimeLibrary>();
}
// GetReferencingLibraries returns the transitive closure of referencing assemblies
// for a given assembly.
return ReferenceAssemblies.SelectMany(_libraryManager.GetReferencingLibraries)
.Distinct()
.Where(IsCandidateLibrary);
return DependencyContext.Default.RuntimeLibraries.Where(IsCandidateLibrary);
}
private static Assembly Load(AssemblyName assemblyName)
private static Assembly Load(RuntimeAssembly assembly)
{
return Assembly.Load(assemblyName);
return Assembly.Load(assembly.Name);
}
private bool IsCandidateLibrary(Library library)
private bool IsCandidateLibrary(RuntimeLibrary library)
{
Debug.Assert(ReferenceAssemblies != null);
return !ReferenceAssemblies.Contains(library.Name);
return library.Dependencies.Any(dependency => ReferenceAssemblies.Contains(dependency.Name));
}
}
}
}

View File

@ -1,95 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using Microsoft.Extensions.DependencyModel;
using Microsoft.Extensions.PlatformAbstractions;
namespace Microsoft.AspNetCore.Mvc.Infrastructure
{
/// <summary>
/// An <see cref="IAssemblyProvider"/> that uses <see cref="DependencyContext"/> to discover assemblies that may
/// contain Mvc specific types such as controllers, and view components.
/// </summary>
public class DependencyContextAssemblyProvider : IAssemblyProvider
{
private readonly DependencyContext _dependencyContext;
/// <summary>
/// Initializes a new instance of <see cref="DependencyContextAssemblyProvider"/>.
/// </summary>
/// <param name="environment">The <see cref="IApplicationEnvironment"/>.</param>
public DependencyContextAssemblyProvider(IApplicationEnvironment environment)
{
var applicationAssembly = Assembly.Load(new AssemblyName(environment.ApplicationName));
_dependencyContext = DependencyContext.Load(applicationAssembly);
}
/// <summary>
/// Gets the set of assembly names that are used as root for discovery of
/// MVC controllers, view components and views.
/// </summary>
// DefaultControllerTypeProvider uses CandidateAssemblies to determine if the base type of a POCO controller
// lives in an assembly that references MVC. CandidateAssemblies excludes all assemblies from the
// ReferenceAssemblies set. Consequently adding WebApiCompatShim to this set would cause the ApiController to
// fail this test.
protected virtual HashSet<string> ReferenceAssemblies { get; } = new HashSet<string>(StringComparer.Ordinal)
{
"Microsoft.AspNetCore.Mvc",
"Microsoft.AspNetCore.Mvc.Abstractions",
"Microsoft.AspNetCore.Mvc.ApiExplorer",
"Microsoft.AspNetCore.Mvc.Core",
"Microsoft.AspNetCore.Mvc.Cors",
"Microsoft.AspNetCore.Mvc.DataAnnotations",
"Microsoft.AspNetCore.Mvc.Formatters.Json",
"Microsoft.AspNetCore.Mvc.Formatters.Xml",
"Microsoft.AspNetCore.Mvc.Localization",
"Microsoft.AspNetCore.Mvc.Razor",
"Microsoft.AspNetCore.Mvc.Razor.Host",
"Microsoft.AspNetCore.Mvc.TagHelpers",
"Microsoft.AspNetCore.Mvc.ViewFeatures"
};
/// <inheritdoc />
public IEnumerable<Assembly> CandidateAssemblies
{
get
{
return GetCandidateLibraries()
.SelectMany(l => l.Assemblies)
.Select(Load);
}
}
/// <summary>
/// Returns a list of libraries that references the assemblies in <see cref="ReferenceAssemblies"/>.
/// By default it returns all assemblies that reference any of the primary MVC assemblies
/// while ignoring MVC assemblies.
/// </summary>
/// <returns>A set of <see cref="Library"/>.</returns>
protected virtual IEnumerable<RuntimeLibrary> GetCandidateLibraries()
{
if (ReferenceAssemblies == null)
{
return Enumerable.Empty<RuntimeLibrary>();
}
return DependencyContext.Default.RuntimeLibraries.Where(IsCandidateLibrary);
}
private static Assembly Load(RuntimeAssembly assembly)
{
return Assembly.Load(assembly.Name);
}
private bool IsCandidateLibrary(RuntimeLibrary library)
{
Debug.Assert(ReferenceAssemblies != null);
return library.Dependencies.Any(dependency => ReferenceAssemblies.Contains(dependency.Name));
}
}
}

View File

@ -21,7 +21,6 @@
},
"Microsoft.Extensions.FileProviders.Abstractions": "1.0.0-*",
"Microsoft.Extensions.PlatformAbstractions": "1.0.0-*",
"Microsoft.Extensions.PlatformAbstractions.Dnx": "1.0.0-*",
"Microsoft.Extensions.DependencyModel": "1.0.0-*",
"Microsoft.Extensions.ClosedGenericMatcher.Sources": {
"version": "1.0.0-*",

View File

@ -13,8 +13,7 @@
"Microsoft.Extensions.PropertyHelper.Sources": {
"version": "1.0.0-*",
"type": "build"
},
"Microsoft.NETCore.Platforms": "1.0.1-*"
}
},
"frameworks": {
"net451": {},

View File

@ -2,8 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
@ -12,7 +10,6 @@ using Microsoft.AspNetCore.Mvc.Razor.Internal;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.CompilationAbstractions;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.PlatformAbstractions;
@ -94,30 +91,22 @@ namespace Microsoft.Extensions.DependencyInjection
// Internal for testing.
internal static void AddRazorViewEngineServices(IServiceCollection services)
{
var compilationServicesAvailible = CompilationServices.Default != null;
services.TryAddEnumerable(
ServiceDescriptor.Transient<
IConfigureOptions<RazorViewEngineOptions>,
DependencyContextRazorViewEngineOptionsSetup>());
if (compilationServicesAvailible)
{
services.TryAddSingleton(CompilationServices.Default.LibraryExporter);
// This caches compilation related details that are valid across the lifetime of the application.
services.TryAddSingleton<ICompilationService, DefaultRoslynCompilationService>();
}
else
{
services.TryAddEnumerable(
ServiceDescriptor.Transient<IConfigureOptions<RazorViewEngineOptions>, DependencyContextRazorViewEngineOptionsSetup>());
// This caches compilation related details that are valid across the lifetime of the application.
services.TryAddSingleton<ICompilationService, DependencyContextCompilationService>();
}
// This caches compilation related details that are valid across the lifetime of the application.
services.TryAddSingleton<ICompilationService, DefaultRoslynCompilationService>();
services.TryAddEnumerable(
ServiceDescriptor.Transient<IConfigureOptions<MvcViewOptions>, MvcRazorMvcViewOptionsSetup>());
services.TryAddEnumerable(
ServiceDescriptor.Transient<IConfigureOptions<RazorViewEngineOptions>, RazorViewEngineOptionsSetup>());
services.TryAddSingleton<IRazorViewEngineFileProviderAccessor, DefaultRazorViewEngineFileProviderAccessor>();
services.TryAddSingleton<
IRazorViewEngineFileProviderAccessor,
DefaultRazorViewEngineFileProviderAccessor>();
services.TryAddSingleton<IRazorViewEngine, RazorViewEngine>();
@ -144,11 +133,6 @@ namespace Microsoft.Extensions.DependencyInjection
// Consumed by the Cache tag helper to cache results across the lifetime of the application.
services.TryAddSingleton<IMemoryCache, MemoryCache>();
if (DnxPlatformServices.Default?.AssemblyLoadContextAccessor != null)
{
services.TryAddSingleton(DnxPlatformServices.Default.AssemblyLoadContextAccessor);
}
}
}
}

View File

@ -1,57 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.Dnx.Compilation.CSharp;
using Microsoft.Extensions.CompilationAbstractions;
using Microsoft.Extensions.PlatformAbstractions;
namespace Microsoft.AspNetCore.Mvc.Razor.Internal
{
/// <summary>
/// Extension methods for <see cref="ICompilerOptionsProvider"/>.
/// </summary>
public static class CompilationOptionsProviderExtension
{
/// <summary>
/// Parses the <see cref="ICompilerOptions"/> for the current executing application and returns a
/// <see cref="CompilationSettings"/> used for Roslyn compilation.
/// </summary>
/// <param name="compilerOptionsProvider">
/// A <see cref="ICompilerOptionsProvider"/> that reads compiler options.
/// </param>
/// <param name="applicationEnvironment">
/// The <see cref="IApplicationEnvironment"/> for the executing application.
/// </param>
/// <param name="configuration">
/// The configuration name to use for compilation.
/// </param>
/// <returns>The <see cref="CompilationSettings"/> for the current application.</returns>
public static CompilationSettings GetCompilationSettings(
this ICompilerOptionsProvider compilerOptionsProvider,
IApplicationEnvironment applicationEnvironment,
string configuration)
{
if (compilerOptionsProvider == null)
{
throw new ArgumentNullException(nameof(compilerOptionsProvider));
}
if (applicationEnvironment == null)
{
throw new ArgumentNullException(nameof(applicationEnvironment));
}
if (string.IsNullOrEmpty(configuration))
{
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(configuration));
}
return compilerOptionsProvider.GetCompilerOptions(
applicationEnvironment.ApplicationName,
applicationEnvironment.RuntimeFramework,
configuration)
.ToCompilationSettings(applicationEnvironment.RuntimeFramework, applicationEnvironment.ApplicationBasePath);
}
}
}

View File

@ -2,12 +2,25 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.PortableExecutable;
#if DOTNET5_6
using System.Runtime.Loader;
#endif
using System.Text;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
using Microsoft.CodeAnalysis;
using Microsoft.Dnx.Compilation.CSharp;
using Microsoft.Extensions.CompilationAbstractions;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.Text;
using Microsoft.Extensions.DependencyModel;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.PlatformAbstractions;
@ -15,107 +28,293 @@ using Microsoft.Extensions.PlatformAbstractions;
namespace Microsoft.AspNetCore.Mvc.Razor.Internal
{
/// <summary>
/// A type that uses Roslyn to compile C# content and <see cref="ILibraryExporter"/> to find out references.
/// A type that uses Roslyn to compile C# content.
/// </summary>
public class DefaultRoslynCompilationService : RoslynCompilationService
public class DefaultRoslynCompilationService : ICompilationService
{
private readonly Lazy<bool> _supportsPdbGeneration = new Lazy<bool>(SymbolsUtility.SupportsSymbolsGeneration);
private readonly ConcurrentDictionary<string, AssemblyMetadata> _metadataFileCache =
new ConcurrentDictionary<string, AssemblyMetadata>(StringComparer.OrdinalIgnoreCase);
private readonly IApplicationEnvironment _environment;
private readonly ILibraryExporter _libraryExporter;
private readonly IFileProvider _fileProvider;
private readonly Lazy<List<MetadataReference>> _applicationReferences;
private readonly string _classPrefix;
private readonly Action<RoslynCompilationContext> _compilationCallback;
private readonly CSharpParseOptions _parseOptions;
private readonly CSharpCompilationOptions _compilationOptions;
private readonly ILogger _logger;
private readonly DependencyContext _dependencyContext;
#if DOTNET5_6
private readonly RazorLoadContext _razorLoadContext;
#endif
/// <summary>
/// Initalizes a new instance of the <see cref="DefaultRoslynCompilationService"/> class.
/// </summary>
/// <param name="environment">The environment for the executing application.</param>
/// <param name="libraryExporter">The library manager that provides export and reference information.</param>
/// <param name="host">The <see cref="IMvcRazorHost"/> that was used to generate the code.</param>
/// <param name="optionsAccessor">Accessor to <see cref="RazorViewEngineOptions"/>.</param>
/// <param name="fileProviderAccessor">The <see cref="IRazorViewEngineFileProviderAccessor"/>.</param>
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
public DefaultRoslynCompilationService(IApplicationEnvironment environment,
ILibraryExporter libraryExporter,
public DefaultRoslynCompilationService(
IApplicationEnvironment environment,
IMvcRazorHost host,
IOptions<RazorViewEngineOptions> optionsAccessor,
IRazorViewEngineFileProviderAccessor fileProviderAccessor,
ILoggerFactory loggerFactory)
: base(environment, host, optionsAccessor, fileProviderAccessor, loggerFactory)
{
_environment = environment;
_libraryExporter = libraryExporter;
_applicationReferences = new Lazy<List<MetadataReference>>(GetApplicationReferences);
_fileProvider = fileProviderAccessor.FileProvider;
_classPrefix = host.MainClassNamePrefix;
_compilationCallback = optionsAccessor.Value.CompilationCallback;
_parseOptions = optionsAccessor.Value.ParseOptions;
_compilationOptions = optionsAccessor.Value.CompilationOptions;
_logger = loggerFactory.CreateLogger<DefaultRoslynCompilationService>();
#if DOTNET5_6
_razorLoadContext = new RazorLoadContext();
#endif
var applicationAssembly = Assembly.Load(new AssemblyName(environment.ApplicationName));
_dependencyContext = DependencyContext.Load(applicationAssembly);
}
protected override List<MetadataReference> GetApplicationReferences()
/// <inheritdoc />
public CompilationResult Compile(RelativeFileInfo fileInfo, string compilationContent)
{
var references = new List<MetadataReference>();
// Get the MetadataReference for the executing application. If it's a Roslyn reference,
// we can copy the references created when compiling the application to the Razor page being compiled.
// This avoids performing expensive calls to MetadataReference.CreateFromImage.
var libraryExport = _libraryExporter.GetExport(_environment.ApplicationName);
if (libraryExport?.MetadataReferences != null && libraryExport.MetadataReferences.Count > 0)
if (fileInfo == null)
{
Debug.Assert(libraryExport.MetadataReferences.Count == 1,
"Expected 1 MetadataReferences, found " + libraryExport.MetadataReferences.Count);
var roslynReference = libraryExport.MetadataReferences[0] as IRoslynMetadataReference;
var compilationReference = roslynReference?.MetadataReference as CompilationReference;
if (compilationReference != null)
{
references.AddRange(compilationReference.Compilation.References);
references.Add(roslynReference.MetadataReference);
return references;
}
throw new ArgumentNullException(nameof(fileInfo));
}
var export = _libraryExporter.GetAllExports(_environment.ApplicationName);
if (export != null)
if (compilationContent == null)
{
foreach (var metadataReference in export.MetadataReferences)
{
// Taken from https://github.com/aspnet/KRuntime/blob/757ba9bfdf80bd6277e715d6375969a7f44370ee/src/...
// Microsoft.Extensions.Runtime.Roslyn/RoslynCompiler.cs#L164
// We don't want to take a dependency on the Roslyn bit directly since it pulls in more dependencies
// than the view engine needs (Microsoft.Extensions.Runtime) for example
references.Add(ConvertMetadataReference(metadataReference));
}
throw new ArgumentNullException(nameof(compilationContent));
}
return references;
_logger.GeneratedCodeToAssemblyCompilationStart(fileInfo.RelativePath);
var startTimestamp = _logger.IsEnabled(LogLevel.Debug) ? Stopwatch.GetTimestamp() : 0;
var assemblyName = Path.GetRandomFileName();
var sourceText = SourceText.From(compilationContent, Encoding.UTF8);
var syntaxTree = CSharpSyntaxTree.ParseText(
sourceText,
path: assemblyName,
options: _parseOptions);
var references = _applicationReferences.Value;
var compilation = CSharpCompilation.Create(
assemblyName,
options: _compilationOptions,
syntaxTrees: new[] { syntaxTree },
references: references);
compilation = Rewrite(compilation);
var compilationContext = new RoslynCompilationContext(compilation);
_compilationCallback(compilationContext);
compilation = compilationContext.Compilation;
using (var ms = new MemoryStream())
{
using (var pdb = new MemoryStream())
{
EmitResult result;
if (_supportsPdbGeneration.Value)
{
result = compilation.Emit(ms, pdbStream: pdb);
}
else
{
result = compilation.Emit(ms);
}
if (!result.Success)
{
return GetCompilationFailedResult(
fileInfo.RelativePath,
compilationContent,
assemblyName,
result.Diagnostics);
}
Assembly assembly;
ms.Seek(0, SeekOrigin.Begin);
if (_supportsPdbGeneration.Value)
{
pdb.Seek(0, SeekOrigin.Begin);
assembly = LoadStream(ms, pdb);
}
else
{
assembly = LoadStream(ms, assemblySymbols: null);
}
var type = assembly
.GetExportedTypes()
.First(t => t.Name.StartsWith(_classPrefix, StringComparison.Ordinal));
_logger.GeneratedCodeToAssemblyCompilationEnd(fileInfo.RelativePath, startTimestamp);
return new CompilationResult(type);
}
}
}
private MetadataReference ConvertMetadataReference(IMetadataReference metadataReference)
private Assembly LoadStream(MemoryStream ms, MemoryStream assemblySymbols)
{
var roslynReference = metadataReference as IRoslynMetadataReference;
#if NET451
return Assembly.Load(ms.ToArray(), assemblySymbols?.ToArray());
#else
return _razorLoadContext.Load(ms, assemblySymbols);
#endif
}
if (roslynReference != null)
private CSharpCompilation Rewrite(CSharpCompilation compilation)
{
var rewrittenTrees = new List<SyntaxTree>();
foreach (var tree in compilation.SyntaxTrees)
{
return roslynReference.MetadataReference;
var semanticModel = compilation.GetSemanticModel(tree, ignoreAccessibility: true);
var rewriter = new ExpressionRewriter(semanticModel);
var rewrittenTree = tree.WithRootAndOptions(rewriter.Visit(tree.GetRoot()), tree.Options);
rewrittenTrees.Add(rewrittenTree);
}
var embeddedReference = metadataReference as IMetadataEmbeddedReference;
return compilation.RemoveAllSyntaxTrees().AddSyntaxTrees(rewrittenTrees);
}
if (embeddedReference != null)
private CompilationResult GetCompilationFailedResult(
string relativePath,
string compilationContent,
string assemblyName,
IEnumerable<Diagnostic> diagnostics)
{
var diagnosticGroups = diagnostics
.Where(IsError)
.GroupBy(diagnostic => GetFilePath(relativePath, diagnostic), StringComparer.Ordinal);
var failures = new List<CompilationFailure>();
foreach (var group in diagnosticGroups)
{
return MetadataReference.CreateFromImage(embeddedReference.Contents);
}
var fileMetadataReference = metadataReference as IMetadataFileReference;
if (fileMetadataReference != null)
{
return CreateMetadataFileReference(fileMetadataReference.Path);
}
var projectReference = metadataReference as IMetadataProjectReference;
if (projectReference != null)
{
using (var ms = new MemoryStream())
var sourceFilePath = group.Key;
string sourceFileContent;
if (string.Equals(assemblyName, sourceFilePath, StringComparison.Ordinal))
{
projectReference.EmitReferenceAssembly(ms);
// The error is in the generated code and does not have a mapping line pragma
sourceFileContent = compilationContent;
sourceFilePath = Resources.GeneratedCodeFileName;
}
else
{
sourceFileContent = ReadFileContentsSafely(_fileProvider, sourceFilePath);
}
return MetadataReference.CreateFromImage(ms.ToArray());
var compilationFailure = new CompilationFailure(
sourceFilePath,
sourceFileContent,
compilationContent,
group.Select(GetDiagnosticMessage));
failures.Add(compilationFailure);
}
return new CompilationResult(failures);
}
private static string GetFilePath(string relativePath, Diagnostic diagnostic)
{
if (diagnostic.Location == Location.None)
{
return relativePath;
}
return diagnostic.Location.GetMappedLineSpan().Path;
}
private List<MetadataReference> GetApplicationReferences()
{
return _dependencyContext.CompileLibraries
.SelectMany(library => library.ResolveReferencePaths())
.Select(CreateMetadataFileReference)
.ToList();
}
private MetadataReference CreateMetadataFileReference(string path)
{
var metadata = _metadataFileCache.GetOrAdd(path, _ =>
{
using (var stream = File.OpenRead(path))
{
var moduleMetadata = ModuleMetadata.CreateFromStream(stream, PEStreamOptions.PrefetchMetadata);
return AssemblyMetadata.Create(moduleMetadata);
}
});
return metadata.GetReference(filePath: path);
}
private static bool IsError(Diagnostic diagnostic)
{
return diagnostic.IsWarningAsError || diagnostic.Severity == DiagnosticSeverity.Error;
}
private static string ReadFileContentsSafely(IFileProvider fileProvider, string filePath)
{
var fileInfo = fileProvider.GetFileInfo(filePath);
if (fileInfo.Exists)
{
try
{
using (var reader = new StreamReader(fileInfo.CreateReadStream()))
{
return reader.ReadToEnd();
}
}
catch
{
// Ignore any failures
}
}
throw new NotSupportedException();
return null;
}
private static DiagnosticMessage GetDiagnosticMessage(Diagnostic diagnostic)
{
var mappedLineSpan = diagnostic.Location.GetMappedLineSpan();
return new DiagnosticMessage(
diagnostic.GetMessage(),
CSharpDiagnosticFormatter.Instance.Format(diagnostic),
mappedLineSpan.Path,
mappedLineSpan.StartLinePosition.Line + 1,
mappedLineSpan.StartLinePosition.Character + 1,
mappedLineSpan.EndLinePosition.Line + 1,
mappedLineSpan.EndLinePosition.Character + 1);
}
#if DOTNET5_6
private class RazorLoadContext : AssemblyLoadContext
{
protected override Assembly Load(AssemblyName assemblyName)
{
return Default.LoadFromAssemblyName(assemblyName);
}
public Assembly Load(Stream assembly, Stream assemblySymbols)
{
return LoadFromStream(assembly, assemblySymbols);
}
}
#endif
}
}
}

View File

@ -1,51 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.CodeAnalysis;
using Microsoft.Extensions.DependencyModel;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.PlatformAbstractions;
namespace Microsoft.AspNetCore.Mvc.Razor.Internal
{
/// <summary>
/// A type that uses Roslyn to compile C# content and <see cref="DependencyContext"/> to locate references.
/// </summary>
public class DependencyContextCompilationService : RoslynCompilationService
{
private readonly DependencyContext _dependencyContext;
/// <summary>
/// Initalizes a new instance of the <see cref="DependencyContextCompilationService"/> class.
/// </summary>
/// <param name="environment">The environment for the executing application.</param>
/// <param name="host">The <see cref="IMvcRazorHost"/> that was used to generate the code.</param>
/// <param name="optionsAccessor">Accessor to <see cref="RazorViewEngineOptions"/>.</param>
/// <param name="fileProviderAccessor">The <see cref="IRazorViewEngineFileProviderAccessor"/>.</param>
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
public DependencyContextCompilationService(
IApplicationEnvironment environment,
IMvcRazorHost host,
IOptions<RazorViewEngineOptions> optionsAccessor,
IRazorViewEngineFileProviderAccessor fileProviderAccessor,
ILoggerFactory loggerFactory)
: base(environment, host, optionsAccessor, fileProviderAccessor, loggerFactory)
{
var applicationAssembly = Assembly.Load(new AssemblyName(environment.ApplicationName));
_dependencyContext = DependencyContext.Load(applicationAssembly);
}
protected override List<MetadataReference> GetApplicationReferences()
{
return _dependencyContext.CompileLibraries
.SelectMany(library => library.ResolveReferencePaths())
.Select(CreateMetadataFileReference)
.ToList();
}
}
}

View File

@ -1,309 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.PortableExecutable;
#if DOTNET5_6
using System.Runtime.Loader;
#endif
using System.Runtime.Versioning;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.Dnx.Compilation.CSharp;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.PlatformAbstractions;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Mvc.Razor.Internal
{
/// <summary>
/// A type that uses Roslyn to compile C# content.
/// </summary>
public abstract class RoslynCompilationService : ICompilationService
{
private readonly Lazy<bool> _supportsPdbGeneration = new Lazy<bool>(SymbolsUtility.SupportsSymbolsGeneration);
private readonly ConcurrentDictionary<string, AssemblyMetadata> _metadataFileCache =
new ConcurrentDictionary<string, AssemblyMetadata>(StringComparer.OrdinalIgnoreCase);
private readonly IApplicationEnvironment _environment;
private readonly IFileProvider _fileProvider;
private readonly Lazy<List<MetadataReference>> _applicationReferences;
private readonly string _classPrefix;
private readonly Action<RoslynCompilationContext> _compilationCallback;
private readonly CSharpParseOptions _parseOptions;
private readonly CSharpCompilationOptions _compilationOptions;
private readonly ILogger _logger;
#if DOTNET5_6
private readonly RazorLoadContext _razorLoadContext;
#endif
/// <summary>
/// Initalizes a new instance of the <see cref="RoslynCompilationService"/> class.
/// </summary>
/// <param name="environment">The environment for the executing application.</param>
/// <param name="host">The <see cref="IMvcRazorHost"/> that was used to generate the code.</param>
/// <param name="optionsAccessor">Accessor to <see cref="RazorViewEngineOptions"/>.</param>
/// <param name="fileProviderAccessor">The <see cref="IRazorViewEngineFileProviderAccessor"/>.</param>
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
public RoslynCompilationService(
IApplicationEnvironment environment,
IMvcRazorHost host,
IOptions<RazorViewEngineOptions> optionsAccessor,
IRazorViewEngineFileProviderAccessor fileProviderAccessor,
ILoggerFactory loggerFactory)
{
_environment = environment;
_applicationReferences = new Lazy<List<MetadataReference>>(GetApplicationReferences);
_fileProvider = fileProviderAccessor.FileProvider;
_classPrefix = host.MainClassNamePrefix;
_compilationCallback = optionsAccessor.Value.CompilationCallback;
_parseOptions = optionsAccessor.Value.ParseOptions;
_compilationOptions = optionsAccessor.Value.CompilationOptions;
_logger = loggerFactory.CreateLogger<RoslynCompilationService>();
#if DOTNET5_6
_razorLoadContext = new RazorLoadContext();
#endif
}
/// <inheritdoc />
public CompilationResult Compile(RelativeFileInfo fileInfo, string compilationContent)
{
if (fileInfo == null)
{
throw new ArgumentNullException(nameof(fileInfo));
}
if (compilationContent == null)
{
throw new ArgumentNullException(nameof(compilationContent));
}
_logger.GeneratedCodeToAssemblyCompilationStart(fileInfo.RelativePath);
var startTimestamp = _logger.IsEnabled(LogLevel.Debug) ? Stopwatch.GetTimestamp() : 0;
var assemblyName = Path.GetRandomFileName();
var syntaxTree = SyntaxTreeGenerator.Generate(
compilationContent,
assemblyName,
_parseOptions);
var references = _applicationReferences.Value;
var compilation = CSharpCompilation.Create(
assemblyName,
options: _compilationOptions,
syntaxTrees: new[] { syntaxTree },
references: references);
compilation = Rewrite(compilation);
var compilationContext = new RoslynCompilationContext(compilation);
_compilationCallback(compilationContext);
compilation = compilationContext.Compilation;
using (var ms = new MemoryStream())
{
using (var pdb = new MemoryStream())
{
EmitResult result;
if (_supportsPdbGeneration.Value)
{
result = compilation.Emit(ms, pdbStream: pdb);
}
else
{
result = compilation.Emit(ms);
}
if (!result.Success)
{
return GetCompilationFailedResult(
fileInfo.RelativePath,
compilationContent,
assemblyName,
result.Diagnostics);
}
Assembly assembly;
ms.Seek(0, SeekOrigin.Begin);
if (_supportsPdbGeneration.Value)
{
pdb.Seek(0, SeekOrigin.Begin);
assembly = LoadStream(ms, pdb);
}
else
{
assembly = LoadStream(ms, assemblySymbols: null);
}
var type = assembly
.GetExportedTypes()
.First(t => t.Name.StartsWith(_classPrefix, StringComparison.Ordinal));
_logger.GeneratedCodeToAssemblyCompilationEnd(fileInfo.RelativePath, startTimestamp);
return new CompilationResult(type);
}
}
}
private Assembly LoadStream(MemoryStream ms, MemoryStream assemblySymbols)
{
#if NET451
return Assembly.Load(ms.ToArray(), assemblySymbols?.ToArray());
#else
return _razorLoadContext.Load(ms, assemblySymbols);
#endif
}
private CSharpCompilation Rewrite(CSharpCompilation compilation)
{
var rewrittenTrees = new List<SyntaxTree>();
foreach (var tree in compilation.SyntaxTrees)
{
var semanticModel = compilation.GetSemanticModel(tree, ignoreAccessibility: true);
var rewriter = new ExpressionRewriter(semanticModel);
var rewrittenTree = tree.WithRootAndOptions(rewriter.Visit(tree.GetRoot()), tree.Options);
rewrittenTrees.Add(rewrittenTree);
}
return compilation.RemoveAllSyntaxTrees().AddSyntaxTrees(rewrittenTrees);
}
// Internal for unit testing
internal CompilationResult GetCompilationFailedResult(
string relativePath,
string compilationContent,
string assemblyName,
IEnumerable<Diagnostic> diagnostics)
{
var diagnosticGroups = diagnostics
.Where(IsError)
.GroupBy(diagnostic => GetFilePath(relativePath, diagnostic), StringComparer.Ordinal);
var failures = new List<CompilationFailure>();
foreach (var group in diagnosticGroups)
{
var sourceFilePath = group.Key;
string sourceFileContent;
if (string.Equals(assemblyName, sourceFilePath, StringComparison.Ordinal))
{
// The error is in the generated code and does not have a mapping line pragma
sourceFileContent = compilationContent;
sourceFilePath = Resources.GeneratedCodeFileName;
}
else
{
sourceFileContent = ReadFileContentsSafely(_fileProvider, sourceFilePath);
}
var compilationFailure = new CompilationFailure(
sourceFilePath,
sourceFileContent,
compilationContent,
group.Select(diagnostic => GetDiagnosticMessage(diagnostic, _environment.RuntimeFramework)));
failures.Add(compilationFailure);
}
return new CompilationResult(failures);
}
private static string GetFilePath(string relativePath, Diagnostic diagnostic)
{
if (diagnostic.Location == Location.None)
{
return relativePath;
}
return diagnostic.Location.GetMappedLineSpan().Path;
}
protected abstract List<MetadataReference> GetApplicationReferences();
protected MetadataReference CreateMetadataFileReference(string path)
{
var metadata = _metadataFileCache.GetOrAdd(path, _ =>
{
using (var stream = File.OpenRead(path))
{
var moduleMetadata = ModuleMetadata.CreateFromStream(stream, PEStreamOptions.PrefetchMetadata);
return AssemblyMetadata.Create(moduleMetadata);
}
});
return metadata.GetReference(filePath: path);
}
private static bool IsError(Diagnostic diagnostic)
{
return diagnostic.IsWarningAsError || diagnostic.Severity == DiagnosticSeverity.Error;
}
private static string ReadFileContentsSafely(IFileProvider fileProvider, string filePath)
{
var fileInfo = fileProvider.GetFileInfo(filePath);
if (fileInfo.Exists)
{
try
{
using (var reader = new StreamReader(fileInfo.CreateReadStream()))
{
return reader.ReadToEnd();
}
}
catch
{
// Ignore any failures
}
}
return null;
}
private static DiagnosticMessage GetDiagnosticMessage(Diagnostic diagnostic, FrameworkName targetFramework)
{
var mappedLineSpan = diagnostic.Location.GetMappedLineSpan();
return new DiagnosticMessage(
diagnostic.GetMessage(),
RoslynDiagnosticFormatter.Format(diagnostic, targetFramework),
mappedLineSpan.Path,
mappedLineSpan.StartLinePosition.Line + 1,
mappedLineSpan.StartLinePosition.Character + 1,
mappedLineSpan.EndLinePosition.Line + 1,
mappedLineSpan.EndLinePosition.Character + 1);
}
#if DOTNET5_6
private class RazorLoadContext : AssemblyLoadContext
{
protected override Assembly Load(AssemblyName assemblyName)
{
return Default.LoadFromAssemblyName(assemblyName);
}
public Assembly Load(Stream assembly, Stream assemblySymbols)
{
return LoadFromStream(assembly, assemblySymbols);
}
}
#endif
}
}

View File

@ -1,63 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Text;
using Microsoft.Dnx.Compilation.CSharp;
namespace Microsoft.AspNetCore.Mvc.Razor.Internal
{
public static class SyntaxTreeGenerator
{
public static SyntaxTree Generate(
string text,
string path,
CompilationSettings compilationSettings)
{
if (compilationSettings == null)
{
throw new ArgumentNullException(nameof(compilationSettings));
}
return Generate(text, path, GetParseOptions(compilationSettings));
}
public static SyntaxTree Generate(
string text,
string path,
CSharpParseOptions parseOptions)
{
if (text == null)
{
throw new ArgumentNullException(nameof(text));
}
if (path == null)
{
throw new ArgumentNullException(nameof(path));
}
if (parseOptions == null)
{
throw new ArgumentNullException(nameof(parseOptions));
}
var sourceText = SourceText.From(text, Encoding.UTF8);
var syntaxTree = CSharpSyntaxTree.ParseText(sourceText,
path: path,
options: parseOptions);
return syntaxTree;
}
public static CSharpParseOptions GetParseOptions(CompilationSettings compilationSettings)
{
return new CSharpParseOptions(
languageVersion: compilationSettings.LanguageVersion,
preprocessorSymbols: compilationSettings.Defines);
}
}
}

View File

@ -12,6 +12,7 @@
"dependencies": {
"Microsoft.AspNetCore.Mvc.Razor.Host": "1.0.0-*",
"Microsoft.AspNetCore.Mvc.ViewFeatures": "1.0.0-*",
"Microsoft.CodeAnalysis.CSharp": "1.1.0-rc1-*",
"Microsoft.Extensions.FileProviders.Composite": "1.0.0-*",
"Microsoft.Extensions.HashCodeCombiner.Sources": {
"version": "1.0.0-*",
@ -24,10 +25,7 @@
"Microsoft.Extensions.PropertyHelper.Sources": {
"version": "1.0.0-*",
"type": "build"
},
"Microsoft.Dnx.Compilation.CSharp.Common": "1.0.0-*",
"Microsoft.Dnx.Compilation.CSharp.Abstractions": "1.0.0-*",
"Microsoft.NETCore.Platforms": "1.0.1-*"
}
},
"frameworks": {
"net451": {

View File

@ -22,8 +22,7 @@
"Microsoft.Extensions.PropertyHelper.Sources": {
"version": "1.0.0-*",
"type": "build"
},
"Microsoft.NETCore.Platforms": "1.0.1-*"
}
},
"frameworks": {
"net451": {},

View File

@ -13,6 +13,13 @@
"test": "xunit.runner.aspnet"
},
"frameworks": {
"dnxcore50": {
"imports": "portable-net451+win8",
"dependencies": {
"moq.netcore": "4.4.0-beta8",
"dotnet-test-xunit": "1.0.0-dev-*"
}
},
"dnx451": {
"dependencies": {
"Moq": "4.2.1312.1622",
@ -23,13 +30,6 @@
"dependencies": {
"Moq": "4.2.1312.1622"
}
},
"dnxcore50": {
"imports": "portable-net451+win8",
"dependencies": {
"moq.netcore": "4.4.0-beta8",
"xunit.runner.aspnet": "2.0.0-aspnet-*"
}
}
}
}

View File

@ -18,6 +18,13 @@
"test": "xunit.runner.aspnet"
},
"frameworks": {
"dnxcore50": {
"imports": "portable-net451+win8",
"dependencies": {
"moq.netcore": "4.4.0-beta8",
"dotnet-test-xunit": "1.0.0-dev-*"
}
},
"dnx451": {
"dependencies": {
"Moq": "4.2.1312.1622",
@ -28,13 +35,6 @@
"dependencies": {
"Moq": "4.2.1312.1622"
}
},
"dnxcore50": {
"imports": "portable-net451+win8",
"dependencies": {
"moq.netcore": "4.4.0-beta8",
"xunit.runner.aspnet": "2.0.0-aspnet-*"
}
}
}
}

View File

@ -1,259 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if DNXCORE50
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.PlatformAbstractions;
using Moq;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.Infrastructure
{
public class DefaultAssemblyProviderTests
{
[Fact]
public void CandidateAssemblies_IgnoresMvcAssemblies()
{
// Arrange
var manager = new Mock<ILibraryManager>();
manager.Setup(f => f.GetReferencingLibraries(It.IsAny<string>()))
.Returns(new[]
{
new Library("Microsoft.AspNetCore.Mvc.Core"),
new Library("Microsoft.AspNetCore.Mvc"),
new Library("Microsoft.AspNetCore.Mvc.Abstractions"),
new Library("SomeRandomAssembly"),
})
.Verifiable();
var provider = new TestAssemblyProvider(manager.Object);
// Act
var candidates = provider.GetCandidateLibraries();
// Assert
Assert.Equal(new[] { "SomeRandomAssembly" }, candidates.Select(a => a.Name));
var context = new Mock<HttpContext>();
}
[Fact]
public void CandidateAssemblies_ReturnsLibrariesReferencingAnyMvcAssembly()
{
// Arrange
var manager = new Mock<ILibraryManager>();
manager.Setup(f => f.GetReferencingLibraries(It.IsAny<string>()))
.Returns(Enumerable.Empty<Library>());
manager.Setup(f => f.GetReferencingLibraries("Microsoft.AspNetCore.Mvc.Core"))
.Returns(new[] { new Library("Foo") });
manager.Setup(f => f.GetReferencingLibraries("Microsoft.AspNetCore.Mvc.Abstractions"))
.Returns(new[] { new Library("Bar") });
manager.Setup(f => f.GetReferencingLibraries("Microsoft.AspNetCore.Mvc"))
.Returns(new[] { new Library("Baz") });
var provider = new TestAssemblyProvider(manager.Object);
// Act
var candidates = provider.GetCandidateLibraries();
// Assert
Assert.Equal(new[] { "Baz", "Bar", "Foo" }, candidates.Select(a => a.Name));
}
[Fact]
public void CandidateAssemblies_ReturnsLibrariesReferencingDefaultAssemblies()
{
// Arrange
var defaultProvider = new TestAssemblyProvider(CreateLibraryManager());
// Act
var defaultProviderCandidates = defaultProvider.GetCandidateLibraries();
// Assert
Assert.Equal(new[] { "Baz" }, defaultProviderCandidates.Select(a => a.Name));
}
[Fact]
public void CandidateAssemblies_ReturnsLibrariesReferencingOverriddenAssemblies()
{
// Arrange
var overriddenProvider = new OverriddenAssemblyProvider(CreateLibraryManager());
// Act
var overriddenProviderCandidates = overriddenProvider.GetCandidateLibraries();
// Assert
Assert.Equal(new[] { "Foo", "Bar" }, overriddenProviderCandidates.Select(a => a.Name));
}
[Fact]
public void CandidateAssemblies_ReturnsEmptySequenceWhenReferenceAssembliesIsNull()
{
// Arrange
var nullProvider = new NullAssemblyProvider(CreateLibraryManager());
// Act
var nullProviderCandidates = nullProvider.GetCandidateLibraries();
// Assert
Assert.Empty(nullProviderCandidates.Select(a => a.Name));
}
// This test verifies DefaultAssemblyProvider.ReferenceAssemblies reflects the actual loadable assemblies
// of the libraries that Microsoft.AspNetCore.Mvc dependes on.
// If we add or remove dependencies, this test should be changed together.
[Fact]
public void ReferenceAssemblies_ReturnsLoadableReferenceAssemblies()
{
// Arrange
var provider = new MvcAssembliesTestingProvider();
var expected = provider.LoadableReferenceAssemblies.OrderBy(p => p, StringComparer.Ordinal);
// Act
var referenceAssemblies = provider.ReferenceAssemblies.OrderBy(p => p, StringComparer.Ordinal);
// Assert
Assert.Equal(expected, referenceAssemblies);
}
private static ILibraryManager CreateLibraryManager()
{
var manager = new Mock<ILibraryManager>();
manager.Setup(f => f.GetReferencingLibraries(It.IsAny<string>()))
.Returns(Enumerable.Empty<Library>());
manager.Setup(f => f.GetReferencingLibraries("Microsoft.AspNetCore.Mvc.Core"))
.Returns(new[] { new Library("Baz") });
manager.Setup(f => f.GetReferencingLibraries("MyAssembly"))
.Returns(new[] { new Library("Foo") });
manager.Setup(f => f.GetReferencingLibraries("AnotherAssembly"))
.Returns(new[] { new Library("Bar") });
return manager.Object;
}
private class TestAssemblyProvider : DefaultAssemblyProvider
{
public new IEnumerable<Library> GetCandidateLibraries()
{
return base.GetCandidateLibraries();
}
public TestAssemblyProvider(ILibraryManager libraryManager) : base(libraryManager)
{
}
}
private class OverriddenAssemblyProvider : TestAssemblyProvider
{
protected override HashSet<string> ReferenceAssemblies
{
get
{
return new HashSet<string>
{
"MyAssembly",
"AnotherAssembly"
};
}
}
public OverriddenAssemblyProvider(ILibraryManager libraryManager) : base(libraryManager)
{
}
}
private class NullAssemblyProvider : TestAssemblyProvider
{
protected override HashSet<string> ReferenceAssemblies
{
get
{
return null;
}
}
public NullAssemblyProvider(ILibraryManager libraryManager) : base(libraryManager)
{
}
}
private class MvcAssembliesTestingProvider : DefaultAssemblyProvider
{
private static readonly ILibraryManager _libraryManager = GetLibraryManager();
private static readonly string _mvcName = "Microsoft.AspNetCore.Mvc";
public MvcAssembliesTestingProvider() : base(_libraryManager)
{ }
public HashSet<string> LoadableReferenceAssemblies
{
get
{
var dependencies = new HashSet<string>() { _mvcName };
GetAllDependencies(_mvcName, dependencies);
return new HashSet<string>(
SelectMvcAssemblies(
GetAssemblies(dependencies)));
}
}
public new HashSet<string> ReferenceAssemblies
{
get
{
return base.ReferenceAssemblies;
}
}
private static void GetAllDependencies(string libraryName, HashSet<string> dependencies)
{
var directDependencies = _libraryManager.GetLibrary(libraryName).Dependencies;
if (directDependencies != null)
{
foreach (var dependency in directDependencies)
{
GetAllDependencies(dependency, dependencies);
dependencies.Add(dependency);
}
}
}
private static IEnumerable<string> SelectMvcAssemblies(IEnumerable<string> assemblies)
{
var exceptionalAssebmlies = new string[]
{
"Microsoft.AspNetCore.Mvc.WebApiCompatShim",
};
var mvcAssemblies = assemblies
.Distinct()
.Where(n => n.StartsWith(_mvcName))
.Except(exceptionalAssebmlies)
.ToList();
// The following assemblies are not reachable from Microsoft.AspNetCore.Mvc
mvcAssemblies.Add("Microsoft.AspNetCore.Mvc.TagHelpers");
mvcAssemblies.Add("Microsoft.AspNetCore.Mvc.Formatters.Xml");
return mvcAssemblies;
}
private static IEnumerable<string> GetAssemblies(IEnumerable<string> libraries)
{
return libraries
.Select(n => _libraryManager.GetLibrary(n))
.SelectMany(n => n.Assemblies)
.Distinct()
.Select(n => n.Name);
}
private static ILibraryManager GetLibraryManager()
{
return DnxPlatformServices.Default.LibraryManager;
}
}
}
}
#endif

View File

@ -27,6 +27,13 @@
"test": "xunit.runner.aspnet"
},
"frameworks": {
"dnxcore50": {
"imports": "portable-net451+win8",
"dependencies": {
"moq.netcore": "4.4.0-beta8",
"dotnet-test-xunit": "1.0.0-dev-*"
}
},
"dnx451": {
"dependencies": {
"Moq": "4.2.1312.1622",
@ -37,13 +44,6 @@
"dependencies": {
"Moq": "4.2.1312.1622"
}
},
"dnxcore50": {
"imports": "portable-net451+win8",
"dependencies": {
"moq.netcore": "4.4.0-beta8",
"xunit.runner.aspnet": "2.0.0-aspnet-*"
}
}
}
}

View File

@ -20,6 +20,13 @@
"test": "xunit.runner.aspnet"
},
"frameworks": {
"dnxcore50": {
"imports": "portable-net451+win8",
"dependencies": {
"moq.netcore": "4.4.0-beta8",
"dotnet-test-xunit": "1.0.0-dev-*"
}
},
"dnx451": {
"dependencies": {
"Moq": "4.2.1312.1622",
@ -30,13 +37,6 @@
"dependencies": {
"Moq": "4.2.1312.1622"
}
},
"dnxcore50": {
"imports": "portable-net451+win8",
"dependencies": {
"moq.netcore": "4.4.0-beta8",
"xunit.runner.aspnet": "2.0.0-aspnet-*"
}
}
}
}

View File

@ -20,6 +20,13 @@
"test": "xunit.runner.aspnet"
},
"frameworks": {
"dnxcore50": {
"imports": "portable-net451+win8",
"dependencies": {
"moq.netcore": "4.4.0-beta8",
"dotnet-test-xunit": "1.0.0-dev-*"
}
},
"dnx451": {
"dependencies": {
"Moq": "4.2.1312.1622",
@ -30,13 +37,6 @@
"dependencies": {
"Moq": "4.2.1312.1622"
}
},
"dnxcore50": {
"imports": "portable-net451+win8",
"dependencies": {
"moq.netcore": "4.4.0-beta8",
"xunit.runner.aspnet": "2.0.0-aspnet-*"
}
}
}
}

View File

@ -20,6 +20,13 @@
"test": "xunit.runner.aspnet"
},
"frameworks": {
"dnxcore50": {
"imports": "portable-net451+win8",
"dependencies": {
"moq.netcore": "4.4.0-beta8",
"dotnet-test-xunit": "1.0.0-dev-*"
}
},
"dnx451": {
"dependencies": {
"Moq": "4.2.1312.1622",
@ -30,13 +37,6 @@
"dependencies": {
"Moq": "4.2.1312.1622"
}
},
"dnxcore50": {
"imports": "portable-net451+win8",
"dependencies": {
"moq.netcore": "4.4.0-beta8",
"xunit.runner.aspnet": "2.0.0-aspnet-*"
}
}
}
}

View File

@ -19,6 +19,13 @@
"test": "xunit.runner.aspnet"
},
"frameworks": {
"dnxcore50": {
"imports": "portable-net451+win8",
"dependencies": {
"moq.netcore": "4.4.0-beta8",
"dotnet-test-xunit": "1.0.0-dev-*"
}
},
"dnx451": {
"dependencies": {
"Moq": "4.2.1312.1622",
@ -29,13 +36,6 @@
"dependencies": {
"Moq": "4.2.1312.1622"
}
},
"dnxcore50": {
"imports": "portable-net451+win8",
"dependencies": {
"moq.netcore": "4.4.0-beta8",
"xunit.runner.aspnet": "2.0.0-aspnet-*"
}
}
}
}

View File

@ -0,0 +1,239 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if DNX451
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.PortableExecutable;
using System.Text;
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.Text;
using Microsoft.Dnx.Compilation.CSharp;
using Microsoft.Extensions.CompilationAbstractions;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.PlatformAbstractions;
namespace Microsoft.AspNetCore.Mvc.Razor.Internal
{
/// <summary>
/// A type that uses Roslyn to compile C# content and <see cref="ILibraryExporter"/> to find out references.
/// </summary>
public class DnxRoslynCompilationService : ICompilationService
{
private readonly ConcurrentDictionary<string, AssemblyMetadata> _metadataFileCache =
new ConcurrentDictionary<string, AssemblyMetadata>(StringComparer.OrdinalIgnoreCase);
private readonly IApplicationEnvironment _environment;
private readonly ILibraryExporter _libraryExporter;
private readonly RazorViewEngineOptions _options;
private readonly Lazy<List<MetadataReference>> _applicationReferences;
/// <summary>
/// Initalizes a new instance of the <see cref="DnxRoslynCompilationService"/> class.
/// </summary>
/// <param name="environment">The environment for the executing application.</param>
/// <param name="libraryExporter">The library manager that provides export and reference information.</param>
/// <param name="host">The <see cref="IMvcRazorHost"/> that was used to generate the code.</param>
/// <param name="optionsAccessor">Accessor to <see cref="RazorViewEngineOptions"/>.</param>
/// <param name="fileProviderAccessor">The <see cref="IRazorViewEngineFileProviderAccessor"/>.</param>
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
public DnxRoslynCompilationService(IApplicationEnvironment environment,
ILibraryExporter libraryExporter,
IMvcRazorHost host,
IOptions<RazorViewEngineOptions> optionsAccessor,
IRazorViewEngineFileProviderAccessor fileProviderAccessor)
{
_environment = environment;
_libraryExporter = libraryExporter;
_options = optionsAccessor.Value;
_applicationReferences = new Lazy<List<MetadataReference>>(GetApplicationReferences);
}
public CompilationResult Compile(RelativeFileInfo fileInfo, string compilationContent)
{
var assemblyName = Path.GetRandomFileName();
var sourceText = SourceText.From(compilationContent, Encoding.UTF8);
var syntaxTree = CSharpSyntaxTree.ParseText(
sourceText,
path: assemblyName,
options: _options.ParseOptions);
var references = _applicationReferences.Value;
var compilation = CSharpCompilation.Create(
assemblyName,
options: _options.CompilationOptions,
syntaxTrees: new[] { syntaxTree },
references: references);
using (var ms = new MemoryStream())
{
using (var pdb = new MemoryStream())
{
var result = compilation.Emit(ms);
if (!result.Success)
{
return GetCompilationFailedResult(
fileInfo.RelativePath,
compilationContent,
assemblyName,
result.Diagnostics);
}
ms.Seek(0, SeekOrigin.Begin);
var assembly = LoadStream(ms, assemblySymbols: null);
var type = assembly
.GetExportedTypes()[0];
return new CompilationResult(type);
}
}
}
internal CompilationResult GetCompilationFailedResult(
string relativePath,
string compilationContent,
string assemblyName,
IEnumerable<Diagnostic> diagnostics)
{
var diagnosticGroups = diagnostics
.Where(diagnostic => diagnostic.Severity == DiagnosticSeverity.Error)
.GroupBy(diagnostic => diagnostic.Location.GetMappedLineSpan().Path, StringComparer.Ordinal);
var failures = new List<Diagnostics.CompilationFailure>();
foreach (var group in diagnosticGroups)
{
var sourceFilePath = group.Key;
var compilationFailure = new Diagnostics.CompilationFailure(
sourceFilePath,
string.Empty,
compilationContent,
group.Select(GetDiagnosticMessage));
failures.Add(compilationFailure);
}
return new CompilationResult(failures);
}
private static Diagnostics.DiagnosticMessage GetDiagnosticMessage(Diagnostic diagnostic)
{
var mappedLineSpan = diagnostic.Location.GetMappedLineSpan();
return new Diagnostics.DiagnosticMessage(
diagnostic.GetMessage(),
CSharpDiagnosticFormatter.Instance.Format(diagnostic),
mappedLineSpan.Path,
mappedLineSpan.StartLinePosition.Line + 1,
mappedLineSpan.StartLinePosition.Character + 1,
mappedLineSpan.EndLinePosition.Line + 1,
mappedLineSpan.EndLinePosition.Character + 1);
}
private Assembly LoadStream(MemoryStream ms, MemoryStream assemblySymbols)
{
return Assembly.Load(ms.ToArray(), assemblySymbols?.ToArray());
}
private List<MetadataReference> GetApplicationReferences()
{
var references = new List<MetadataReference>();
// Get the MetadataReference for the executing application. If it's a Roslyn reference,
// we can copy the references created when compiling the application to the Razor page being compiled.
// This avoids performing expensive calls to MetadataReference.CreateFromImage.
var libraryExport = _libraryExporter.GetExport(_environment.ApplicationName);
if (libraryExport?.MetadataReferences != null && libraryExport.MetadataReferences.Count > 0)
{
Debug.Assert(libraryExport.MetadataReferences.Count == 1,
"Expected 1 MetadataReferences, found " + libraryExport.MetadataReferences.Count);
var roslynReference = libraryExport.MetadataReferences[0] as IRoslynMetadataReference;
var compilationReference = roslynReference?.MetadataReference as CompilationReference;
if (compilationReference != null)
{
references.AddRange(compilationReference.Compilation.References);
references.Add(roslynReference.MetadataReference);
return references;
}
}
var export = _libraryExporter.GetAllExports(_environment.ApplicationName);
if (export != null)
{
foreach (var metadataReference in export.MetadataReferences)
{
// Taken from https://github.com/aspnet/KRuntime/blob/757ba9bfdf80bd6277e715d6375969a7f44370ee/src/...
// Microsoft.Extensions.Runtime.Roslyn/RoslynCompiler.cs#L164
// We don't want to take a dependency on the Roslyn bit directly since it pulls in more dependencies
// than the view engine needs (Microsoft.Extensions.Runtime) for example
references.Add(ConvertMetadataReference(metadataReference));
}
}
return references;
}
private MetadataReference ConvertMetadataReference(IMetadataReference metadataReference)
{
var roslynReference = metadataReference as IRoslynMetadataReference;
if (roslynReference != null)
{
return roslynReference.MetadataReference;
}
var embeddedReference = metadataReference as IMetadataEmbeddedReference;
if (embeddedReference != null)
{
return MetadataReference.CreateFromImage(embeddedReference.Contents);
}
var fileMetadataReference = metadataReference as IMetadataFileReference;
if (fileMetadataReference != null)
{
return CreateMetadataFileReference(fileMetadataReference.Path);
}
var projectReference = metadataReference as IMetadataProjectReference;
if (projectReference != null)
{
using (var ms = new MemoryStream())
{
projectReference.EmitReferenceAssembly(ms);
return MetadataReference.CreateFromImage(ms.ToArray());
}
}
throw new NotSupportedException();
}
private MetadataReference CreateMetadataFileReference(string path)
{
var metadata = _metadataFileCache.GetOrAdd(path, _ =>
{
using (var stream = File.OpenRead(path))
{
var moduleMetadata = ModuleMetadata.CreateFromStream(stream, PEStreamOptions.PrefetchMetadata);
return AssemblyMetadata.Create(moduleMetadata);
}
});
return metadata.GetReference(filePath: path);
}
}
}
#endif

View File

@ -6,7 +6,11 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
public class MvcSampleFixture<TStartup> : MvcTestFixture<TStartup>
{
public MvcSampleFixture()
#if DNXCORE50
:base("../../../../../../samples/")
#else
: base("../../../../samples/")
#endif
{
}
}

View File

@ -7,8 +7,13 @@ using System.Net.Http;
using System.Reflection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
using Microsoft.AspNetCore.Mvc.Razor.Internal;
using Microsoft.AspNetCore.TestHost;
using Microsoft.AspNetCore.Testing;
#if DNX451
using Microsoft.Extensions.CompilationAbstractions;
#endif
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.PlatformAbstractions;
@ -19,7 +24,11 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
private readonly TestServer _server;
public MvcTestFixture()
#if DNXCORE50
: this("../../../../../Websites/")
#else
: this("../../../Websites/")
#endif
{
}
@ -61,11 +70,14 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
var applicationName = startupAssembly.GetName().Name;
var applicationEnvironment = PlatformServices.Default.Application;
#if DNXCORE50 || DNX451
#if DNX451
services.AddSingleton(CompilationServices.Default.LibraryExporter);
services.AddSingleton<ICompilationService, DnxRoslynCompilationService>();
var libraryManager = DnxPlatformServices.Default.LibraryManager;
var library = libraryManager.GetLibrary(applicationName);
var applicationRoot = Path.GetDirectoryName(library.Path);
#else
var applicationRoot = Path.GetDirectoryName(library.Path);
#else
var applicationRoot = Path.GetFullPath(Path.Combine(
applicationEnvironment.ApplicationBasePath,
relativePath,

View File

@ -57,18 +57,22 @@
"test": "xunit.runner.aspnet"
},
"frameworks": {
"dnx451": {
"dependencies": {
"xunit.runner.aspnet": "2.0.0-aspnet-*"
},
},
"net451": { },
"dnxcore50": {
"dependencies": {
"xunit.runner.aspnet": "2.0.0-aspnet-*"
"Microsoft.Dnx.Compilation.CSharp.Common": "1.0.0-*",
"Microsoft.Dnx.Compilation.CSharp.Abstractions": "1.0.0-*",
"dotnet-test-xunit": "1.0.0-dev-*"
},
"imports": "portable-net451+win8"
}
},
"dnx451": {
"dependencies": {
"Microsoft.Dnx.Compilation.CSharp.Common": "1.0.0-*",
"Microsoft.Dnx.Compilation.CSharp.Abstractions": "1.0.0-*",
"xunit.runner.aspnet": "2.0.0-aspnet-*"
}
},
"net451": { }
},
"exclude": [
"wwwroot",

View File

@ -19,6 +19,13 @@
"test": "xunit.runner.aspnet"
},
"frameworks": {
"dnxcore50": {
"imports": "portable-net451+win8",
"dependencies": {
"moq.netcore": "4.4.0-beta8",
"dotnet-test-xunit": "1.0.0-dev-*"
}
},
"dnx451": {
"dependencies": {
"Moq": "4.2.1312.1622",
@ -29,13 +36,6 @@
"dependencies": {
"Moq": "4.2.1312.1622"
}
},
"dnxcore50": {
"imports": "portable-net451+win8",
"dependencies": {
"moq.netcore": "4.4.0-beta8",
"xunit.runner.aspnet": "2.0.0-aspnet-*"
}
}
}
}

View File

@ -18,6 +18,13 @@
"test": "xunit.runner.aspnet"
},
"frameworks": {
"dnxcore50": {
"imports": "portable-net451+win8",
"dependencies": {
"moq.netcore": "4.4.0-beta8",
"dotnet-test-xunit": "1.0.0-dev-*"
}
},
"dnx451": {
"dependencies": {
"Moq": "4.2.1312.1622",
@ -28,13 +35,6 @@
"dependencies": {
"Moq": "4.2.1312.1622"
}
},
"dnxcore50": {
"imports": "portable-net451+win8",
"dependencies": {
"moq.netcore": "4.4.0-beta8",
"xunit.runner.aspnet": "2.0.0-aspnet-*"
}
}
}
}

View File

@ -25,6 +25,13 @@
"keyFile": "../../tools/Key.snk"
},
"frameworks": {
"dnxcore50": {
"imports": "portable-net451+win8",
"dependencies": {
"moq.netcore": "4.4.0-beta8",
"dotnet-test-xunit": "1.0.0-dev-*"
}
},
"dnx451": {
"dependencies": {
"Moq": "4.2.1312.1622",
@ -35,13 +42,6 @@
"dependencies": {
"Moq": "4.2.1312.1622"
}
},
"dnxcore50": {
"imports": "portable-net451+win8",
"dependencies": {
"moq.netcore": "4.4.0-beta8",
"xunit.runner.aspnet": "2.0.0-aspnet-*"
}
}
},
"exclude": [

View File

@ -1,393 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if DNXCORE50
using System;
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
using Microsoft.Extensions.CompilationAbstractions;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Logging.Testing;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.PlatformAbstractions;
using Moq;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.Razor.Internal
{
public class DefaultRoslynCompilationServiceTest
{
private const string ConfigurationName = "Release";
[Fact]
public void Compile_ReturnsCompilationResult()
{
// Arrange
var content = @"
public class MyTestType {}";
var applicationEnvironment = PlatformServices.Default.Application;
var libraryExporter = CompilationServices.Default.LibraryExporter;
var mvcRazorHost = new Mock<IMvcRazorHost>();
mvcRazorHost.SetupGet(m => m.MainClassNamePrefix)
.Returns(string.Empty);
var compilationService = new DefaultRoslynCompilationService(
applicationEnvironment,
libraryExporter,
mvcRazorHost.Object,
GetOptions(),
GetFileProviderAccessor(),
NullLoggerFactory.Instance);
var relativeFileInfo = new RelativeFileInfo(
new TestFileInfo { PhysicalPath = "SomePath" },
"some-relative-path");
// Act
var result = compilationService.Compile(relativeFileInfo, content);
// Assert
Assert.Equal("MyTestType", result.CompiledType.Name);
}
[Fact]
public void Compile_ReturnsCompilationFailureWithPathsFromLinePragmas()
{
// Arrange
var viewPath = "some-relative-path";
var fileContent = "test file content";
var content = $@"
#line 1 ""{viewPath}""
this should fail";
var applicationEnvironment = PlatformServices.Default.Application;
var libraryExporter = CompilationServices.Default.LibraryExporter;
var mvcRazorHost = Mock.Of<IMvcRazorHost>();
var fileProvider = new TestFileProvider();
var fileInfo = fileProvider.AddFile(viewPath, fileContent);
var compilationService = new DefaultRoslynCompilationService(
applicationEnvironment,
libraryExporter,
mvcRazorHost,
GetOptions(),
GetFileProviderAccessor(fileProvider),
NullLoggerFactory.Instance);
var relativeFileInfo = new RelativeFileInfo(fileInfo, "some-relative-path");
// Act
var result = compilationService.Compile(relativeFileInfo, content);
// Assert
Assert.IsType<CompilationResult>(result);
Assert.Null(result.CompiledType);
var compilationFailure = Assert.Single(result.CompilationFailures);
Assert.Equal(relativeFileInfo.RelativePath, compilationFailure.SourceFilePath);
Assert.Equal(fileContent, compilationFailure.SourceFileContent);
}
[Fact]
public void Compile_ReturnsGeneratedCodePath_IfLinePragmaIsNotAvailable()
{
// Arrange
var fileContent = "file content";
var content = @"this should fail";
var applicationEnvironment = PlatformServices.Default.Application;
var libraryExporter = CompilationServices.Default.LibraryExporter;
var mvcRazorHost = Mock.Of<IMvcRazorHost>();
var compilationService = new DefaultRoslynCompilationService(
applicationEnvironment,
libraryExporter,
mvcRazorHost,
GetOptions(),
GetFileProviderAccessor(),
NullLoggerFactory.Instance);
var relativeFileInfo = new RelativeFileInfo(
new TestFileInfo { Content = fileContent },
"some-relative-path");
// Act
var result = compilationService.Compile(relativeFileInfo, content);
// Assert
Assert.IsType<CompilationResult>(result);
Assert.Null(result.CompiledType);
var compilationFailure = Assert.Single(result.CompilationFailures);
Assert.Equal("Generated Code", compilationFailure.SourceFilePath);
Assert.Equal(content, compilationFailure.SourceFileContent);
}
[Fact]
public void Compile_DoesNotThrow_IfFileCannotBeRead()
{
// Arrange
var path = "some-relative-path";
var content = $@"
#line 1 ""{path}""
this should fail";
var applicationEnvironment = PlatformServices.Default.Application;
var libraryExporter = CompilationServices.Default.LibraryExporter;
var mvcRazorHost = Mock.Of<IMvcRazorHost>();
var mockFileInfo = new Mock<IFileInfo>();
mockFileInfo.Setup(f => f.CreateReadStream())
.Throws(new Exception());
var fileProvider = new TestFileProvider();
fileProvider.AddFile(path, mockFileInfo.Object);
var compilationService = new DefaultRoslynCompilationService(
applicationEnvironment,
libraryExporter,
mvcRazorHost,
GetOptions(),
GetFileProviderAccessor(fileProvider),
NullLoggerFactory.Instance);
var relativeFileInfo = new RelativeFileInfo(mockFileInfo.Object, path);
// Act
var result = compilationService.Compile(relativeFileInfo, content);
// Assert
Assert.IsType<CompilationResult>(result);
Assert.Null(result.CompiledType);
var compilationFailure = Assert.Single(result.CompilationFailures);
Assert.Equal(path, compilationFailure.SourceFilePath);
Assert.Null(compilationFailure.SourceFileContent);
}
[Fact]
public void Compile_UsesApplicationsCompilationSettings_ForParsingAndCompilation()
{
// Arrange
var content = @"
#if MY_CUSTOM_DEFINE
public class MyCustomDefinedClass {}
#else
public class MyNonCustomDefinedClass {}
#endif
";
var applicationEnvironment = PlatformServices.Default.Application;
var libraryExporter = CompilationServices.Default.LibraryExporter;
var mvcRazorHost = new Mock<IMvcRazorHost>();
mvcRazorHost.SetupGet(m => m.MainClassNamePrefix)
.Returns("My");
var options = GetOptions();
options.Value.ParseOptions = options.Value.ParseOptions.WithPreprocessorSymbols("MY_CUSTOM_DEFINE");
var compilationService = new DefaultRoslynCompilationService(
applicationEnvironment,
libraryExporter,
mvcRazorHost.Object,
options,
GetFileProviderAccessor(),
NullLoggerFactory.Instance);
var relativeFileInfo = new RelativeFileInfo(
new TestFileInfo { PhysicalPath = "SomePath" },
"some-relative-path");
// Act
var result = compilationService.Compile(relativeFileInfo, content);
// Assert
Assert.NotNull(result.CompiledType);
Assert.Equal("MyCustomDefinedClass", result.CompiledType.Name);
}
[Fact]
public void Compile_ReturnsSingleTypeThatStartsWithMainClassNamePrefix()
{
// Arrange
var content = @"
public class RazorPrefixType {}
public class NotRazorPrefixType {}";
var applicationEnvironment = PlatformServices.Default.Application;
var libraryExporter = CompilationServices.Default.LibraryExporter;
var mvcRazorHost = new Mock<IMvcRazorHost>();
mvcRazorHost.SetupGet(m => m.MainClassNamePrefix)
.Returns("RazorPrefix");
var compilationService = new DefaultRoslynCompilationService(
applicationEnvironment,
libraryExporter,
mvcRazorHost.Object,
GetOptions(),
GetFileProviderAccessor(),
NullLoggerFactory.Instance);
var relativeFileInfo = new RelativeFileInfo(
new TestFileInfo { PhysicalPath = "SomePath" },
"some-relative-path");
// Act
var result = compilationService.Compile(relativeFileInfo, content);
// Assert
Assert.NotNull(result.CompiledType);
Assert.Equal("RazorPrefixType", result.CompiledType.Name);
}
[Fact]
public void GetCompilationFailedResult_ReturnsCompilationResult_WithGroupedMessages()
{
// Arrange
var viewPath = "Views/Home/Index";
var generatedCodeFileName = "Generated Code";
var fileProvider = new TestFileProvider();
fileProvider.AddFile(viewPath, "view-content");
var options = new RazorViewEngineOptions();
options.FileProviders.Add(fileProvider);
var optionsAccessor = new Mock<IOptions<RazorViewEngineOptions>>();
optionsAccessor.SetupGet(o => o.Value)
.Returns(options);
var compilationService = new DefaultRoslynCompilationService(
PlatformServices.Default.Application,
CompilationServices.Default.LibraryExporter,
Mock.Of<IMvcRazorHost>(),
optionsAccessor.Object,
GetFileProviderAccessor(fileProvider),
NullLoggerFactory.Instance);
var assemblyName = "random-assembly-name";
var diagnostics = new[]
{
Diagnostic.Create(
GetDiagnosticDescriptor("message-1"),
Location.Create(
viewPath,
new TextSpan(10, 5),
new LinePositionSpan(new LinePosition(10, 1), new LinePosition(10, 2)))),
Diagnostic.Create(
GetDiagnosticDescriptor("message-2"),
Location.Create(
assemblyName,
new TextSpan(1, 6),
new LinePositionSpan(new LinePosition(1, 2), new LinePosition(3, 4)))),
Diagnostic.Create(
GetDiagnosticDescriptor("message-3"),
Location.Create(
viewPath,
new TextSpan(40, 50),
new LinePositionSpan(new LinePosition(30, 5), new LinePosition(40, 12)))),
};
// Act
var compilationResult = compilationService.GetCompilationFailedResult(
viewPath,
"compilation-content",
assemblyName,
diagnostics);
// Assert
Assert.Collection(compilationResult.CompilationFailures,
failure =>
{
Assert.Equal(viewPath, failure.SourceFilePath);
Assert.Equal("view-content", failure.SourceFileContent);
Assert.Collection(failure.Messages,
message =>
{
Assert.Equal("message-1", message.Message);
Assert.Equal(viewPath, message.SourceFilePath);
Assert.Equal(11, message.StartLine);
Assert.Equal(2, message.StartColumn);
Assert.Equal(11, message.EndLine);
Assert.Equal(3, message.EndColumn);
},
message =>
{
Assert.Equal("message-3", message.Message);
Assert.Equal(viewPath, message.SourceFilePath);
Assert.Equal(31, message.StartLine);
Assert.Equal(6, message.StartColumn);
Assert.Equal(41, message.EndLine);
Assert.Equal(13, message.EndColumn);
});
},
failure =>
{
Assert.Equal(generatedCodeFileName, failure.SourceFilePath);
Assert.Equal("compilation-content", failure.SourceFileContent);
Assert.Collection(failure.Messages,
message =>
{
Assert.Equal("message-2", message.Message);
Assert.Equal(assemblyName, message.SourceFilePath);
Assert.Equal(2, message.StartLine);
Assert.Equal(3, message.StartColumn);
Assert.Equal(4, message.EndLine);
Assert.Equal(5, message.EndColumn);
});
});
}
[Fact]
public void Compile_RunsCallback()
{
var content = "public class MyTestType {}";
var applicationEnvironment = PlatformServices.Default.Application;
var libraryExporter = CompilationServices.Default.LibraryExporter;
RoslynCompilationContext usedCompilation = null;
var mvcRazorHost = new Mock<IMvcRazorHost>();
mvcRazorHost.SetupGet(m => m.MainClassNamePrefix)
.Returns(string.Empty);
var compilationService = new DefaultRoslynCompilationService(
applicationEnvironment,
libraryExporter,
mvcRazorHost.Object,
GetOptions(callback: c => usedCompilation = c),
GetFileProviderAccessor(),
NullLoggerFactory.Instance);
var relativeFileInfo = new RelativeFileInfo(
new TestFileInfo { PhysicalPath = "SomePath" },
"some-relative-path");
// Act
var result = compilationService.Compile(relativeFileInfo, content);
Assert.NotNull(usedCompilation);
Assert.NotNull(usedCompilation.Compilation);
Assert.Equal(1, usedCompilation.Compilation.SyntaxTrees.Length);
}
private static DiagnosticDescriptor GetDiagnosticDescriptor(string messageFormat)
{
return new DiagnosticDescriptor(
id: "someid",
title: "sometitle",
messageFormat: messageFormat,
category: "some-category",
defaultSeverity: DiagnosticSeverity.Error,
isEnabledByDefault: true);
}
private static IOptions<RazorViewEngineOptions> GetOptions(Action<RoslynCompilationContext> callback = null)
{
var razorViewEngineOptions = new RazorViewEngineOptions
{
CompilationCallback = callback ?? (c => { }),
};
var options = new Mock<IOptions<RazorViewEngineOptions>>();
options
.SetupGet(o => o.Value)
.Returns(razorViewEngineOptions);
return options.Object;
}
private IRazorViewEngineFileProviderAccessor GetFileProviderAccessor(IFileProvider fileProvider = null)
{
var options = new Mock<IRazorViewEngineFileProviderAccessor>();
options.SetupGet(o => o.FileProvider)
.Returns(fileProvider ?? new TestFileProvider());
return options.Object;
}
}
}
#endif

View File

@ -8,9 +8,6 @@ using System.Reflection;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.Dnx.Compilation.CSharp;
using Microsoft.Extensions.CompilationAbstractions;
using Microsoft.Extensions.PlatformAbstractions;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.Razor.Internal
@ -567,28 +564,13 @@ public class Person
private IEnumerable<MetadataReference> GetReferences()
{
var libraryExporter = CompilationServices.Default?.LibraryExporter;
if (libraryExporter == null)
var types = new[]
{
var types = new[]
{
typeof(System.Linq.Expressions.Expression),
typeof(string),
};
typeof(System.Linq.Expressions.Expression),
typeof(string),
};
return types.Select(t => MetadataReference.CreateFromFile(t.GetTypeInfo().Assembly.Location));
}
var environment = PlatformServices.Default.Application;
var references = new List<MetadataReference>();
var libraryExports = libraryExporter.GetAllExports(environment.ApplicationName);
foreach (var export in libraryExports.MetadataReferences)
{
references.Add(export.ConvertMetadataReference(MetadataReferenceExtensions.CreateAssemblyMetadata));
}
return references;
return types.Select(t => MetadataReference.CreateFromFile(t.GetTypeInfo().Assembly.Location));
}
}
}

View File

@ -33,6 +33,13 @@
"test": "xunit.runner.aspnet"
},
"frameworks": {
"dnxcore50": {
"imports": "portable-net451+win8",
"dependencies": {
"moq.netcore": "4.4.0-beta8",
"dotnet-test-xunit": "1.0.0-dev-*"
}
},
"dnx451": {
"dependencies": {
"Moq": "4.2.1312.1622",
@ -43,13 +50,6 @@
"dependencies": {
"Moq": "4.2.1312.1622"
}
},
"dnxcore50": {
"imports": "portable-net451+win8",
"dependencies": {
"moq.netcore": "4.4.0-beta8",
"xunit.runner.aspnet": "2.0.0-aspnet-*"
}
}
},
"exclude": [

View File

@ -21,6 +21,13 @@
"test": "xunit.runner.aspnet"
},
"frameworks": {
"dnxcore50": {
"imports": "portable-net451+win8",
"dependencies": {
"moq.netcore": "4.4.0-beta8",
"dotnet-test-xunit": "1.0.0-dev-*"
}
},
"dnx451": {
"dependencies": {
"Moq": "4.2.1312.1622",
@ -31,13 +38,6 @@
"dependencies": {
"Moq": "4.2.1312.1622"
}
},
"dnxcore50": {
"imports": "portable-net451+win8",
"dependencies": {
"moq.netcore": "4.4.0-beta8",
"xunit.runner.aspnet": "2.0.0-aspnet-*"
}
}
},
"exclude": [

View File

@ -4,8 +4,8 @@
using System;
using System.IO;
using System.Linq;
using System.Threading;
using System.Reflection;
using System.Threading;
using System.Xml;
using System.Xml.Linq;
using Microsoft.AspNetCore.Hosting;
@ -17,7 +17,6 @@ using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.Extensions.CompilationAbstractions;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
@ -34,7 +33,7 @@ namespace Microsoft.AspNetCore.Mvc
public void Setup_SetsUpViewEngines()
{
// Arrange & Act
var options = GetOptions<MvcViewOptions>(AddDnxServices);
var options = GetOptions<MvcViewOptions>(AddViewEngineOptionsServices);
// Assert
var viewEngine = Assert.Single(options.ViewEngines);
@ -119,7 +118,7 @@ namespace Microsoft.AspNetCore.Mvc
public void Setup_SetsUpClientModelValidatorProviders()
{
// Arrange & Act
var options = GetOptions<MvcViewOptions>(AddDnxServices);
var options = GetOptions<MvcViewOptions>(AddViewEngineOptionsServices);
// Assert
Assert.Collection(options.ClientModelValidatorProviders,
@ -236,6 +235,7 @@ namespace Microsoft.AspNetCore.Mvc
var serviceCollection = new ServiceCollection();
serviceCollection.AddMvc();
serviceCollection.AddTransient<ILoggerFactory, LoggerFactory>();
if (action != null)
{
action(serviceCollection);
@ -245,14 +245,10 @@ namespace Microsoft.AspNetCore.Mvc
return serviceProvider;
}
private static void AddDnxServices(IServiceCollection serviceCollection)
private static void AddViewEngineOptionsServices(IServiceCollection serviceCollection)
{
serviceCollection.AddSingleton(Mock.Of<ILibraryManager>());
serviceCollection.AddSingleton(Mock.Of<ILibraryExporter>());
serviceCollection.AddSingleton(Mock.Of<ICompilerOptionsProvider>());
serviceCollection.AddSingleton(Mock.Of<IHostingEnvironment>());
var applicationEnvironment = new Mock<IApplicationEnvironment>();
applicationEnvironment.SetupGet(e => e.ApplicationName)
.Returns(typeof(MvcOptionsSetupTest).GetTypeInfo().Assembly.GetName().Name);

View File

@ -10,7 +10,6 @@ using Microsoft.AspNetCore.Mvc.ActionConstraints;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Cors;
using Microsoft.AspNetCore.Mvc.Cors.Internal;
using Microsoft.AspNetCore.Mvc.DataAnnotations.Internal;
using Microsoft.AspNetCore.Mvc.Filters;
@ -21,7 +20,6 @@ using Microsoft.AspNetCore.Mvc.Razor.Internal;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.CompilationAbstractions;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
@ -139,24 +137,6 @@ namespace Microsoft.AspNetCore.Mvc
{
get
{
Type[] razorViewEngineOptionsRegistrations;
if (CompilationServices.Default == null)
{
razorViewEngineOptionsRegistrations = new[]
{
typeof(RazorViewEngineOptionsSetup),
typeof(DependencyContextRazorViewEngineOptionsSetup)
};
}
else
{
razorViewEngineOptionsRegistrations = new[]
{
typeof(RazorViewEngineOptionsSetup)
};
}
return new Dictionary<Type, Type[]>()
{
{
@ -186,7 +166,11 @@ namespace Microsoft.AspNetCore.Mvc
},
{
typeof(IConfigureOptions<RazorViewEngineOptions>),
razorViewEngineOptionsRegistrations
new[]
{
typeof(RazorViewEngineOptionsSetup),
typeof(DependencyContextRazorViewEngineOptionsSetup)
}
},
{
typeof(IActionConstraintProvider),

View File

@ -7,13 +7,21 @@
"Microsoft.AspNetCore.Mvc.Formatters.Xml": "1.0.0-*",
"Microsoft.Extensions.DependencyInjection": "1.0.0-*",
"Microsoft.Extensions.Logging": "1.0.0-*",
"Microsoft.NETCore.Platforms": "1.0.1-*"
"Microsoft.NETCore.Platforms": "1.0.1-*",
"xunit": "2.1.0"
},
"testRunner": "xunit",
"commands": {
"test": "xunit.runner.aspnet"
},
"frameworks": {
"dnxcore50": {
"imports": "portable-net451+win8",
"dependencies": {
"moq.netcore": "4.4.0-beta8",
"dotnet-test-xunit": "1.0.0-dev-*"
}
},
"dnx451": {
"dependencies": {
"Moq": "4.2.1312.1622",
@ -22,15 +30,7 @@
},
"net451": {
"dependencies": {
"Moq": "4.2.1312.1622",
"xunit": "2.1.0"
}
},
"dnxcore50": {
"imports": "portable-net451+win8",
"dependencies": {
"moq.netcore": "4.4.0-beta8",
"xunit.runner.aspnet": "2.0.0-aspnet-*"
"Moq": "4.2.1312.1622"
}
}
}

View File

@ -26,6 +26,13 @@
"test": "xunit.runner.aspnet"
},
"frameworks": {
"dnxcore50": {
"imports": "portable-net451+win8",
"dependencies": {
"moq.netcore": "4.4.0-beta8",
"dotnet-test-xunit": "1.0.0-dev-*"
}
},
"dnx451": {
"dependencies": {
"Moq": "4.2.1312.1622",
@ -36,13 +43,6 @@
"dependencies": {
"Moq": "4.2.1312.1622"
}
},
"dnxcore50": {
"imports": "portable-net451+win8",
"dependencies": {
"moq.netcore": "4.4.0-beta8",
"xunit.runner.aspnet": "2.0.0-aspnet-*"
}
}
}
}

View File

@ -16,18 +16,18 @@
"test": "xunit.runner.aspnet"
},
"frameworks": {
"dnxcore50": {
"imports": "portable-net451+win8",
"dependencies": {
"moq.netcore": "4.4.0-beta8",
"dotnet-test-xunit": "1.0.0-dev-*"
}
},
"dnx451": {
"dependencies": {
"Moq": "4.2.1312.1622",
"xunit.runner.aspnet": "2.0.0-aspnet-*"
}
},
"dnxcore50": {
"imports": "portable-net451+win8",
"dependencies": {
"moq.netcore": "4.4.0-beta8",
"xunit.runner.aspnet": "2.0.0-aspnet-*"
}
}
}
}

View File

@ -7,7 +7,7 @@ namespace RazorWebSite
{
public string ExecuteOperation()
{
#if NET451
#if NET451 || DNX451
return "This method is running from NET451";
#elif DNXCORE50
return "This method is running from DNXCORE50";

View File

@ -20,8 +20,8 @@ namespace RazorWebSite
.AddRazorOptions(options =>
{
options.ViewLocationExpanders.Add(new NonMainPageViewLocationExpander());
#if DNXCORE50
options.ParseOptions = options.ParseOptions.WithPreprocessorSymbols("DNXCORE50", "DNXCORE50_CUSTOM_DEFINE");
#if NET451
options.ParseOptions = options.ParseOptions.WithPreprocessorSymbols("DNX451", "NET451_CUSTOM_DEFINE");
#endif
})
.AddViewOptions(options =>