* Moving DNX dependencies to test only
* Updating Mvc tests to use dotnet test to run on dnxcore50
This commit is contained in:
parent
c259f82615
commit
80b6996701
|
|
@ -58,14 +58,6 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
// To enable unit testing
|
// To enable unit testing
|
||||||
internal static void AddMvcCoreServices(IServiceCollection services)
|
internal static void AddMvcCoreServices(IServiceCollection services)
|
||||||
{
|
{
|
||||||
//
|
|
||||||
// RuntimeServices
|
|
||||||
//
|
|
||||||
if (DnxPlatformServices.Default?.LibraryManager != null)
|
|
||||||
{
|
|
||||||
services.TryAddSingleton(DnxPlatformServices.Default.LibraryManager);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Options
|
// Options
|
||||||
//
|
//
|
||||||
|
|
@ -78,14 +70,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
// Action Discovery
|
// Action Discovery
|
||||||
//
|
//
|
||||||
// These are consumed only when creating action descriptors, then they can be de-allocated
|
// These are consumed only when creating action descriptors, then they can be de-allocated
|
||||||
if (DnxPlatformServices.Default?.LibraryManager != null)
|
services.TryAddTransient<IAssemblyProvider, DefaultAssemblyProvider>();
|
||||||
{
|
|
||||||
services.TryAddTransient<IAssemblyProvider, DefaultAssemblyProvider>();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
services.TryAddTransient<IAssemblyProvider, DependencyContextAssemblyProvider>();
|
|
||||||
}
|
|
||||||
|
|
||||||
services.TryAddTransient<IControllerTypeProvider, DefaultControllerTypeProvider>();
|
services.TryAddTransient<IControllerTypeProvider, DefaultControllerTypeProvider>();
|
||||||
services.TryAddEnumerable(
|
services.TryAddEnumerable(
|
||||||
|
|
|
||||||
|
|
@ -6,17 +6,27 @@ using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using Microsoft.Extensions.DependencyModel;
|
||||||
using Microsoft.Extensions.PlatformAbstractions;
|
using Microsoft.Extensions.PlatformAbstractions;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
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
|
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>
|
/// <summary>
|
||||||
|
|
@ -49,8 +59,9 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return GetCandidateLibraries().SelectMany(l => l.Assemblies)
|
return GetCandidateLibraries()
|
||||||
.Select(Load);
|
.SelectMany(l => l.Assemblies)
|
||||||
|
.Select(Load);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -60,29 +71,25 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
||||||
/// while ignoring MVC assemblies.
|
/// while ignoring MVC assemblies.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A set of <see cref="Library"/>.</returns>
|
/// <returns>A set of <see cref="Library"/>.</returns>
|
||||||
protected virtual IEnumerable<Library> GetCandidateLibraries()
|
protected virtual IEnumerable<RuntimeLibrary> GetCandidateLibraries()
|
||||||
{
|
{
|
||||||
if (ReferenceAssemblies == null)
|
if (ReferenceAssemblies == null)
|
||||||
{
|
{
|
||||||
return Enumerable.Empty<Library>();
|
return Enumerable.Empty<RuntimeLibrary>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetReferencingLibraries returns the transitive closure of referencing assemblies
|
return DependencyContext.Default.RuntimeLibraries.Where(IsCandidateLibrary);
|
||||||
// for a given assembly.
|
|
||||||
return ReferenceAssemblies.SelectMany(_libraryManager.GetReferencingLibraries)
|
|
||||||
.Distinct()
|
|
||||||
.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);
|
Debug.Assert(ReferenceAssemblies != null);
|
||||||
return !ReferenceAssemblies.Contains(library.Name);
|
return library.Dependencies.Any(dependency => ReferenceAssemblies.Contains(dependency.Name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -21,7 +21,6 @@
|
||||||
},
|
},
|
||||||
"Microsoft.Extensions.FileProviders.Abstractions": "1.0.0-*",
|
"Microsoft.Extensions.FileProviders.Abstractions": "1.0.0-*",
|
||||||
"Microsoft.Extensions.PlatformAbstractions": "1.0.0-*",
|
"Microsoft.Extensions.PlatformAbstractions": "1.0.0-*",
|
||||||
"Microsoft.Extensions.PlatformAbstractions.Dnx": "1.0.0-*",
|
|
||||||
"Microsoft.Extensions.DependencyModel": "1.0.0-*",
|
"Microsoft.Extensions.DependencyModel": "1.0.0-*",
|
||||||
"Microsoft.Extensions.ClosedGenericMatcher.Sources": {
|
"Microsoft.Extensions.ClosedGenericMatcher.Sources": {
|
||||||
"version": "1.0.0-*",
|
"version": "1.0.0-*",
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,7 @@
|
||||||
"Microsoft.Extensions.PropertyHelper.Sources": {
|
"Microsoft.Extensions.PropertyHelper.Sources": {
|
||||||
"version": "1.0.0-*",
|
"version": "1.0.0-*",
|
||||||
"type": "build"
|
"type": "build"
|
||||||
},
|
}
|
||||||
"Microsoft.NETCore.Platforms": "1.0.1-*"
|
|
||||||
},
|
},
|
||||||
"frameworks": {
|
"frameworks": {
|
||||||
"net451": {},
|
"net451": {},
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,6 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc.Razor;
|
using Microsoft.AspNetCore.Mvc.Razor;
|
||||||
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
|
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
|
||||||
|
|
@ -12,7 +10,6 @@ using Microsoft.AspNetCore.Mvc.Razor.Internal;
|
||||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||||
using Microsoft.Extensions.Caching.Memory;
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using Microsoft.Extensions.CompilationAbstractions;
|
|
||||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Microsoft.Extensions.PlatformAbstractions;
|
using Microsoft.Extensions.PlatformAbstractions;
|
||||||
|
|
@ -94,30 +91,22 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
// Internal for testing.
|
// Internal for testing.
|
||||||
internal static void AddRazorViewEngineServices(IServiceCollection services)
|
internal static void AddRazorViewEngineServices(IServiceCollection services)
|
||||||
{
|
{
|
||||||
var compilationServicesAvailible = CompilationServices.Default != null;
|
services.TryAddEnumerable(
|
||||||
|
ServiceDescriptor.Transient<
|
||||||
|
IConfigureOptions<RazorViewEngineOptions>,
|
||||||
|
DependencyContextRazorViewEngineOptionsSetup>());
|
||||||
|
|
||||||
if (compilationServicesAvailible)
|
// This caches compilation related details that are valid across the lifetime of the application.
|
||||||
{
|
services.TryAddSingleton<ICompilationService, DefaultRoslynCompilationService>();
|
||||||
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>();
|
|
||||||
}
|
|
||||||
|
|
||||||
services.TryAddEnumerable(
|
services.TryAddEnumerable(
|
||||||
ServiceDescriptor.Transient<IConfigureOptions<MvcViewOptions>, MvcRazorMvcViewOptionsSetup>());
|
ServiceDescriptor.Transient<IConfigureOptions<MvcViewOptions>, MvcRazorMvcViewOptionsSetup>());
|
||||||
services.TryAddEnumerable(
|
services.TryAddEnumerable(
|
||||||
ServiceDescriptor.Transient<IConfigureOptions<RazorViewEngineOptions>, RazorViewEngineOptionsSetup>());
|
ServiceDescriptor.Transient<IConfigureOptions<RazorViewEngineOptions>, RazorViewEngineOptionsSetup>());
|
||||||
|
|
||||||
services.TryAddSingleton<IRazorViewEngineFileProviderAccessor, DefaultRazorViewEngineFileProviderAccessor>();
|
services.TryAddSingleton<
|
||||||
|
IRazorViewEngineFileProviderAccessor,
|
||||||
|
DefaultRazorViewEngineFileProviderAccessor>();
|
||||||
|
|
||||||
services.TryAddSingleton<IRazorViewEngine, RazorViewEngine>();
|
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.
|
// Consumed by the Cache tag helper to cache results across the lifetime of the application.
|
||||||
services.TryAddSingleton<IMemoryCache, MemoryCache>();
|
services.TryAddSingleton<IMemoryCache, MemoryCache>();
|
||||||
|
|
||||||
if (DnxPlatformServices.Default?.AssemblyLoadContextAccessor != null)
|
|
||||||
{
|
|
||||||
services.TryAddSingleton(DnxPlatformServices.Default.AssemblyLoadContextAccessor);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -2,12 +2,25 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
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.CodeAnalysis;
|
||||||
using Microsoft.Dnx.Compilation.CSharp;
|
using Microsoft.CodeAnalysis.CSharp;
|
||||||
using Microsoft.Extensions.CompilationAbstractions;
|
using Microsoft.CodeAnalysis.Emit;
|
||||||
|
using Microsoft.CodeAnalysis.Text;
|
||||||
|
using Microsoft.Extensions.DependencyModel;
|
||||||
|
using Microsoft.Extensions.FileProviders;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Microsoft.Extensions.PlatformAbstractions;
|
using Microsoft.Extensions.PlatformAbstractions;
|
||||||
|
|
@ -15,107 +28,293 @@ using Microsoft.Extensions.PlatformAbstractions;
|
||||||
namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <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>
|
/// </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 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>
|
/// <summary>
|
||||||
/// Initalizes a new instance of the <see cref="DefaultRoslynCompilationService"/> class.
|
/// Initalizes a new instance of the <see cref="DefaultRoslynCompilationService"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="environment">The environment for the executing application.</param>
|
/// <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="host">The <see cref="IMvcRazorHost"/> that was used to generate the code.</param>
|
||||||
/// <param name="optionsAccessor">Accessor to <see cref="RazorViewEngineOptions"/>.</param>
|
/// <param name="optionsAccessor">Accessor to <see cref="RazorViewEngineOptions"/>.</param>
|
||||||
/// <param name="fileProviderAccessor">The <see cref="IRazorViewEngineFileProviderAccessor"/>.</param>
|
/// <param name="fileProviderAccessor">The <see cref="IRazorViewEngineFileProviderAccessor"/>.</param>
|
||||||
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
|
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
|
||||||
public DefaultRoslynCompilationService(IApplicationEnvironment environment,
|
public DefaultRoslynCompilationService(
|
||||||
ILibraryExporter libraryExporter,
|
IApplicationEnvironment environment,
|
||||||
IMvcRazorHost host,
|
IMvcRazorHost host,
|
||||||
IOptions<RazorViewEngineOptions> optionsAccessor,
|
IOptions<RazorViewEngineOptions> optionsAccessor,
|
||||||
IRazorViewEngineFileProviderAccessor fileProviderAccessor,
|
IRazorViewEngineFileProviderAccessor fileProviderAccessor,
|
||||||
ILoggerFactory loggerFactory)
|
ILoggerFactory loggerFactory)
|
||||||
: base(environment, host, optionsAccessor, fileProviderAccessor, loggerFactory)
|
|
||||||
{
|
{
|
||||||
_environment = environment;
|
_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>();
|
if (fileInfo == null)
|
||||||
|
|
||||||
// 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,
|
throw new ArgumentNullException(nameof(fileInfo));
|
||||||
"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 (compilationContent == null)
|
||||||
if (export != null)
|
|
||||||
{
|
{
|
||||||
foreach (var metadataReference in export.MetadataReferences)
|
throw new ArgumentNullException(nameof(compilationContent));
|
||||||
{
|
|
||||||
// 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;
|
_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 sourceFilePath = group.Key;
|
||||||
}
|
string sourceFileContent;
|
||||||
|
if (string.Equals(assemblyName, sourceFilePath, StringComparison.Ordinal))
|
||||||
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);
|
// 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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.AspNetCore.Mvc.Razor.Host": "1.0.0-*",
|
"Microsoft.AspNetCore.Mvc.Razor.Host": "1.0.0-*",
|
||||||
"Microsoft.AspNetCore.Mvc.ViewFeatures": "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.FileProviders.Composite": "1.0.0-*",
|
||||||
"Microsoft.Extensions.HashCodeCombiner.Sources": {
|
"Microsoft.Extensions.HashCodeCombiner.Sources": {
|
||||||
"version": "1.0.0-*",
|
"version": "1.0.0-*",
|
||||||
|
|
@ -24,10 +25,7 @@
|
||||||
"Microsoft.Extensions.PropertyHelper.Sources": {
|
"Microsoft.Extensions.PropertyHelper.Sources": {
|
||||||
"version": "1.0.0-*",
|
"version": "1.0.0-*",
|
||||||
"type": "build"
|
"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": {
|
"frameworks": {
|
||||||
"net451": {
|
"net451": {
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,7 @@
|
||||||
"Microsoft.Extensions.PropertyHelper.Sources": {
|
"Microsoft.Extensions.PropertyHelper.Sources": {
|
||||||
"version": "1.0.0-*",
|
"version": "1.0.0-*",
|
||||||
"type": "build"
|
"type": "build"
|
||||||
},
|
}
|
||||||
"Microsoft.NETCore.Platforms": "1.0.1-*"
|
|
||||||
},
|
},
|
||||||
"frameworks": {
|
"frameworks": {
|
||||||
"net451": {},
|
"net451": {},
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,13 @@
|
||||||
"test": "xunit.runner.aspnet"
|
"test": "xunit.runner.aspnet"
|
||||||
},
|
},
|
||||||
"frameworks": {
|
"frameworks": {
|
||||||
|
"dnxcore50": {
|
||||||
|
"imports": "portable-net451+win8",
|
||||||
|
"dependencies": {
|
||||||
|
"moq.netcore": "4.4.0-beta8",
|
||||||
|
"dotnet-test-xunit": "1.0.0-dev-*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"dnx451": {
|
"dnx451": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Moq": "4.2.1312.1622",
|
"Moq": "4.2.1312.1622",
|
||||||
|
|
@ -23,13 +30,6 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Moq": "4.2.1312.1622"
|
"Moq": "4.2.1312.1622"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"dnxcore50": {
|
|
||||||
"imports": "portable-net451+win8",
|
|
||||||
"dependencies": {
|
|
||||||
"moq.netcore": "4.4.0-beta8",
|
|
||||||
"xunit.runner.aspnet": "2.0.0-aspnet-*"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -18,6 +18,13 @@
|
||||||
"test": "xunit.runner.aspnet"
|
"test": "xunit.runner.aspnet"
|
||||||
},
|
},
|
||||||
"frameworks": {
|
"frameworks": {
|
||||||
|
"dnxcore50": {
|
||||||
|
"imports": "portable-net451+win8",
|
||||||
|
"dependencies": {
|
||||||
|
"moq.netcore": "4.4.0-beta8",
|
||||||
|
"dotnet-test-xunit": "1.0.0-dev-*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"dnx451": {
|
"dnx451": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Moq": "4.2.1312.1622",
|
"Moq": "4.2.1312.1622",
|
||||||
|
|
@ -28,13 +35,6 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Moq": "4.2.1312.1622"
|
"Moq": "4.2.1312.1622"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"dnxcore50": {
|
|
||||||
"imports": "portable-net451+win8",
|
|
||||||
"dependencies": {
|
|
||||||
"moq.netcore": "4.4.0-beta8",
|
|
||||||
"xunit.runner.aspnet": "2.0.0-aspnet-*"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -27,6 +27,13 @@
|
||||||
"test": "xunit.runner.aspnet"
|
"test": "xunit.runner.aspnet"
|
||||||
},
|
},
|
||||||
"frameworks": {
|
"frameworks": {
|
||||||
|
"dnxcore50": {
|
||||||
|
"imports": "portable-net451+win8",
|
||||||
|
"dependencies": {
|
||||||
|
"moq.netcore": "4.4.0-beta8",
|
||||||
|
"dotnet-test-xunit": "1.0.0-dev-*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"dnx451": {
|
"dnx451": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Moq": "4.2.1312.1622",
|
"Moq": "4.2.1312.1622",
|
||||||
|
|
@ -37,13 +44,6 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Moq": "4.2.1312.1622"
|
"Moq": "4.2.1312.1622"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"dnxcore50": {
|
|
||||||
"imports": "portable-net451+win8",
|
|
||||||
"dependencies": {
|
|
||||||
"moq.netcore": "4.4.0-beta8",
|
|
||||||
"xunit.runner.aspnet": "2.0.0-aspnet-*"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -20,6 +20,13 @@
|
||||||
"test": "xunit.runner.aspnet"
|
"test": "xunit.runner.aspnet"
|
||||||
},
|
},
|
||||||
"frameworks": {
|
"frameworks": {
|
||||||
|
"dnxcore50": {
|
||||||
|
"imports": "portable-net451+win8",
|
||||||
|
"dependencies": {
|
||||||
|
"moq.netcore": "4.4.0-beta8",
|
||||||
|
"dotnet-test-xunit": "1.0.0-dev-*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"dnx451": {
|
"dnx451": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Moq": "4.2.1312.1622",
|
"Moq": "4.2.1312.1622",
|
||||||
|
|
@ -30,13 +37,6 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Moq": "4.2.1312.1622"
|
"Moq": "4.2.1312.1622"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"dnxcore50": {
|
|
||||||
"imports": "portable-net451+win8",
|
|
||||||
"dependencies": {
|
|
||||||
"moq.netcore": "4.4.0-beta8",
|
|
||||||
"xunit.runner.aspnet": "2.0.0-aspnet-*"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -20,6 +20,13 @@
|
||||||
"test": "xunit.runner.aspnet"
|
"test": "xunit.runner.aspnet"
|
||||||
},
|
},
|
||||||
"frameworks": {
|
"frameworks": {
|
||||||
|
"dnxcore50": {
|
||||||
|
"imports": "portable-net451+win8",
|
||||||
|
"dependencies": {
|
||||||
|
"moq.netcore": "4.4.0-beta8",
|
||||||
|
"dotnet-test-xunit": "1.0.0-dev-*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"dnx451": {
|
"dnx451": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Moq": "4.2.1312.1622",
|
"Moq": "4.2.1312.1622",
|
||||||
|
|
@ -30,13 +37,6 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Moq": "4.2.1312.1622"
|
"Moq": "4.2.1312.1622"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"dnxcore50": {
|
|
||||||
"imports": "portable-net451+win8",
|
|
||||||
"dependencies": {
|
|
||||||
"moq.netcore": "4.4.0-beta8",
|
|
||||||
"xunit.runner.aspnet": "2.0.0-aspnet-*"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -20,6 +20,13 @@
|
||||||
"test": "xunit.runner.aspnet"
|
"test": "xunit.runner.aspnet"
|
||||||
},
|
},
|
||||||
"frameworks": {
|
"frameworks": {
|
||||||
|
"dnxcore50": {
|
||||||
|
"imports": "portable-net451+win8",
|
||||||
|
"dependencies": {
|
||||||
|
"moq.netcore": "4.4.0-beta8",
|
||||||
|
"dotnet-test-xunit": "1.0.0-dev-*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"dnx451": {
|
"dnx451": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Moq": "4.2.1312.1622",
|
"Moq": "4.2.1312.1622",
|
||||||
|
|
@ -30,13 +37,6 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Moq": "4.2.1312.1622"
|
"Moq": "4.2.1312.1622"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"dnxcore50": {
|
|
||||||
"imports": "portable-net451+win8",
|
|
||||||
"dependencies": {
|
|
||||||
"moq.netcore": "4.4.0-beta8",
|
|
||||||
"xunit.runner.aspnet": "2.0.0-aspnet-*"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -19,6 +19,13 @@
|
||||||
"test": "xunit.runner.aspnet"
|
"test": "xunit.runner.aspnet"
|
||||||
},
|
},
|
||||||
"frameworks": {
|
"frameworks": {
|
||||||
|
"dnxcore50": {
|
||||||
|
"imports": "portable-net451+win8",
|
||||||
|
"dependencies": {
|
||||||
|
"moq.netcore": "4.4.0-beta8",
|
||||||
|
"dotnet-test-xunit": "1.0.0-dev-*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"dnx451": {
|
"dnx451": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Moq": "4.2.1312.1622",
|
"Moq": "4.2.1312.1622",
|
||||||
|
|
@ -29,13 +36,6 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Moq": "4.2.1312.1622"
|
"Moq": "4.2.1312.1622"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"dnxcore50": {
|
|
||||||
"imports": "portable-net451+win8",
|
|
||||||
"dependencies": {
|
|
||||||
"moq.netcore": "4.4.0-beta8",
|
|
||||||
"xunit.runner.aspnet": "2.0.0-aspnet-*"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
@ -6,7 +6,11 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||||
public class MvcSampleFixture<TStartup> : MvcTestFixture<TStartup>
|
public class MvcSampleFixture<TStartup> : MvcTestFixture<TStartup>
|
||||||
{
|
{
|
||||||
public MvcSampleFixture()
|
public MvcSampleFixture()
|
||||||
|
#if DNXCORE50
|
||||||
|
:base("../../../../../../samples/")
|
||||||
|
#else
|
||||||
: base("../../../../samples/")
|
: base("../../../../samples/")
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,13 @@ using System.Net.Http;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Razor.Internal;
|
||||||
using Microsoft.AspNetCore.TestHost;
|
using Microsoft.AspNetCore.TestHost;
|
||||||
using Microsoft.AspNetCore.Testing;
|
using Microsoft.AspNetCore.Testing;
|
||||||
|
#if DNX451
|
||||||
|
using Microsoft.Extensions.CompilationAbstractions;
|
||||||
|
#endif
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.PlatformAbstractions;
|
using Microsoft.Extensions.PlatformAbstractions;
|
||||||
|
|
||||||
|
|
@ -19,7 +24,11 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||||
private readonly TestServer _server;
|
private readonly TestServer _server;
|
||||||
|
|
||||||
public MvcTestFixture()
|
public MvcTestFixture()
|
||||||
|
#if DNXCORE50
|
||||||
|
: this("../../../../../Websites/")
|
||||||
|
#else
|
||||||
: this("../../../Websites/")
|
: this("../../../Websites/")
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -61,11 +70,14 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||||
var applicationName = startupAssembly.GetName().Name;
|
var applicationName = startupAssembly.GetName().Name;
|
||||||
|
|
||||||
var applicationEnvironment = PlatformServices.Default.Application;
|
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 libraryManager = DnxPlatformServices.Default.LibraryManager;
|
||||||
var library = libraryManager.GetLibrary(applicationName);
|
var library = libraryManager.GetLibrary(applicationName);
|
||||||
var applicationRoot = Path.GetDirectoryName(library.Path);
|
var applicationRoot = Path.GetDirectoryName(library.Path);
|
||||||
#else
|
#else
|
||||||
var applicationRoot = Path.GetFullPath(Path.Combine(
|
var applicationRoot = Path.GetFullPath(Path.Combine(
|
||||||
applicationEnvironment.ApplicationBasePath,
|
applicationEnvironment.ApplicationBasePath,
|
||||||
relativePath,
|
relativePath,
|
||||||
|
|
|
||||||
|
|
@ -57,18 +57,22 @@
|
||||||
"test": "xunit.runner.aspnet"
|
"test": "xunit.runner.aspnet"
|
||||||
},
|
},
|
||||||
"frameworks": {
|
"frameworks": {
|
||||||
"dnx451": {
|
|
||||||
"dependencies": {
|
|
||||||
"xunit.runner.aspnet": "2.0.0-aspnet-*"
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"net451": { },
|
|
||||||
"dnxcore50": {
|
"dnxcore50": {
|
||||||
"dependencies": {
|
"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"
|
"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": [
|
"exclude": [
|
||||||
"wwwroot",
|
"wwwroot",
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,13 @@
|
||||||
"test": "xunit.runner.aspnet"
|
"test": "xunit.runner.aspnet"
|
||||||
},
|
},
|
||||||
"frameworks": {
|
"frameworks": {
|
||||||
|
"dnxcore50": {
|
||||||
|
"imports": "portable-net451+win8",
|
||||||
|
"dependencies": {
|
||||||
|
"moq.netcore": "4.4.0-beta8",
|
||||||
|
"dotnet-test-xunit": "1.0.0-dev-*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"dnx451": {
|
"dnx451": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Moq": "4.2.1312.1622",
|
"Moq": "4.2.1312.1622",
|
||||||
|
|
@ -29,13 +36,6 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Moq": "4.2.1312.1622"
|
"Moq": "4.2.1312.1622"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"dnxcore50": {
|
|
||||||
"imports": "portable-net451+win8",
|
|
||||||
"dependencies": {
|
|
||||||
"moq.netcore": "4.4.0-beta8",
|
|
||||||
"xunit.runner.aspnet": "2.0.0-aspnet-*"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -18,6 +18,13 @@
|
||||||
"test": "xunit.runner.aspnet"
|
"test": "xunit.runner.aspnet"
|
||||||
},
|
},
|
||||||
"frameworks": {
|
"frameworks": {
|
||||||
|
"dnxcore50": {
|
||||||
|
"imports": "portable-net451+win8",
|
||||||
|
"dependencies": {
|
||||||
|
"moq.netcore": "4.4.0-beta8",
|
||||||
|
"dotnet-test-xunit": "1.0.0-dev-*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"dnx451": {
|
"dnx451": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Moq": "4.2.1312.1622",
|
"Moq": "4.2.1312.1622",
|
||||||
|
|
@ -28,13 +35,6 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Moq": "4.2.1312.1622"
|
"Moq": "4.2.1312.1622"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"dnxcore50": {
|
|
||||||
"imports": "portable-net451+win8",
|
|
||||||
"dependencies": {
|
|
||||||
"moq.netcore": "4.4.0-beta8",
|
|
||||||
"xunit.runner.aspnet": "2.0.0-aspnet-*"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -25,6 +25,13 @@
|
||||||
"keyFile": "../../tools/Key.snk"
|
"keyFile": "../../tools/Key.snk"
|
||||||
},
|
},
|
||||||
"frameworks": {
|
"frameworks": {
|
||||||
|
"dnxcore50": {
|
||||||
|
"imports": "portable-net451+win8",
|
||||||
|
"dependencies": {
|
||||||
|
"moq.netcore": "4.4.0-beta8",
|
||||||
|
"dotnet-test-xunit": "1.0.0-dev-*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"dnx451": {
|
"dnx451": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Moq": "4.2.1312.1622",
|
"Moq": "4.2.1312.1622",
|
||||||
|
|
@ -35,13 +42,6 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Moq": "4.2.1312.1622"
|
"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": [
|
"exclude": [
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -8,9 +8,6 @@ using System.Reflection;
|
||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
using Microsoft.CodeAnalysis.CSharp;
|
using Microsoft.CodeAnalysis.CSharp;
|
||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
using Microsoft.Dnx.Compilation.CSharp;
|
|
||||||
using Microsoft.Extensions.CompilationAbstractions;
|
|
||||||
using Microsoft.Extensions.PlatformAbstractions;
|
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
||||||
|
|
@ -567,28 +564,13 @@ public class Person
|
||||||
|
|
||||||
private IEnumerable<MetadataReference> GetReferences()
|
private IEnumerable<MetadataReference> GetReferences()
|
||||||
{
|
{
|
||||||
var libraryExporter = CompilationServices.Default?.LibraryExporter;
|
var types = new[]
|
||||||
if (libraryExporter == null)
|
|
||||||
{
|
{
|
||||||
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));
|
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,13 @@
|
||||||
"test": "xunit.runner.aspnet"
|
"test": "xunit.runner.aspnet"
|
||||||
},
|
},
|
||||||
"frameworks": {
|
"frameworks": {
|
||||||
|
"dnxcore50": {
|
||||||
|
"imports": "portable-net451+win8",
|
||||||
|
"dependencies": {
|
||||||
|
"moq.netcore": "4.4.0-beta8",
|
||||||
|
"dotnet-test-xunit": "1.0.0-dev-*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"dnx451": {
|
"dnx451": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Moq": "4.2.1312.1622",
|
"Moq": "4.2.1312.1622",
|
||||||
|
|
@ -43,13 +50,6 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Moq": "4.2.1312.1622"
|
"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": [
|
"exclude": [
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,13 @@
|
||||||
"test": "xunit.runner.aspnet"
|
"test": "xunit.runner.aspnet"
|
||||||
},
|
},
|
||||||
"frameworks": {
|
"frameworks": {
|
||||||
|
"dnxcore50": {
|
||||||
|
"imports": "portable-net451+win8",
|
||||||
|
"dependencies": {
|
||||||
|
"moq.netcore": "4.4.0-beta8",
|
||||||
|
"dotnet-test-xunit": "1.0.0-dev-*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"dnx451": {
|
"dnx451": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Moq": "4.2.1312.1622",
|
"Moq": "4.2.1312.1622",
|
||||||
|
|
@ -31,13 +38,6 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Moq": "4.2.1312.1622"
|
"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": [
|
"exclude": [
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Threading;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
|
@ -17,7 +17,6 @@ using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
||||||
using Microsoft.AspNetCore.Mvc.Razor;
|
using Microsoft.AspNetCore.Mvc.Razor;
|
||||||
using Microsoft.Extensions.CompilationAbstractions;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|
@ -34,7 +33,7 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
public void Setup_SetsUpViewEngines()
|
public void Setup_SetsUpViewEngines()
|
||||||
{
|
{
|
||||||
// Arrange & Act
|
// Arrange & Act
|
||||||
var options = GetOptions<MvcViewOptions>(AddDnxServices);
|
var options = GetOptions<MvcViewOptions>(AddViewEngineOptionsServices);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var viewEngine = Assert.Single(options.ViewEngines);
|
var viewEngine = Assert.Single(options.ViewEngines);
|
||||||
|
|
@ -119,7 +118,7 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
public void Setup_SetsUpClientModelValidatorProviders()
|
public void Setup_SetsUpClientModelValidatorProviders()
|
||||||
{
|
{
|
||||||
// Arrange & Act
|
// Arrange & Act
|
||||||
var options = GetOptions<MvcViewOptions>(AddDnxServices);
|
var options = GetOptions<MvcViewOptions>(AddViewEngineOptionsServices);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Collection(options.ClientModelValidatorProviders,
|
Assert.Collection(options.ClientModelValidatorProviders,
|
||||||
|
|
@ -236,6 +235,7 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
var serviceCollection = new ServiceCollection();
|
var serviceCollection = new ServiceCollection();
|
||||||
serviceCollection.AddMvc();
|
serviceCollection.AddMvc();
|
||||||
serviceCollection.AddTransient<ILoggerFactory, LoggerFactory>();
|
serviceCollection.AddTransient<ILoggerFactory, LoggerFactory>();
|
||||||
|
|
||||||
if (action != null)
|
if (action != null)
|
||||||
{
|
{
|
||||||
action(serviceCollection);
|
action(serviceCollection);
|
||||||
|
|
@ -245,14 +245,10 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
return serviceProvider;
|
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>());
|
serviceCollection.AddSingleton(Mock.Of<IHostingEnvironment>());
|
||||||
var applicationEnvironment = new Mock<IApplicationEnvironment>();
|
var applicationEnvironment = new Mock<IApplicationEnvironment>();
|
||||||
|
|
||||||
applicationEnvironment.SetupGet(e => e.ApplicationName)
|
applicationEnvironment.SetupGet(e => e.ApplicationName)
|
||||||
.Returns(typeof(MvcOptionsSetupTest).GetTypeInfo().Assembly.GetName().Name);
|
.Returns(typeof(MvcOptionsSetupTest).GetTypeInfo().Assembly.GetName().Name);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ using Microsoft.AspNetCore.Mvc.ActionConstraints;
|
||||||
using Microsoft.AspNetCore.Mvc.ApiExplorer;
|
using Microsoft.AspNetCore.Mvc.ApiExplorer;
|
||||||
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
||||||
using Microsoft.AspNetCore.Mvc.Controllers;
|
using Microsoft.AspNetCore.Mvc.Controllers;
|
||||||
using Microsoft.AspNetCore.Mvc.Cors;
|
|
||||||
using Microsoft.AspNetCore.Mvc.Cors.Internal;
|
using Microsoft.AspNetCore.Mvc.Cors.Internal;
|
||||||
using Microsoft.AspNetCore.Mvc.DataAnnotations.Internal;
|
using Microsoft.AspNetCore.Mvc.DataAnnotations.Internal;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
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;
|
||||||
using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;
|
using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;
|
||||||
using Microsoft.AspNetCore.Routing;
|
using Microsoft.AspNetCore.Routing;
|
||||||
using Microsoft.Extensions.CompilationAbstractions;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|
@ -139,24 +137,6 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
Type[] razorViewEngineOptionsRegistrations;
|
|
||||||
if (CompilationServices.Default == null)
|
|
||||||
{
|
|
||||||
razorViewEngineOptionsRegistrations = new[]
|
|
||||||
{
|
|
||||||
typeof(RazorViewEngineOptionsSetup),
|
|
||||||
typeof(DependencyContextRazorViewEngineOptionsSetup)
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
razorViewEngineOptionsRegistrations = new[]
|
|
||||||
{
|
|
||||||
typeof(RazorViewEngineOptionsSetup)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Dictionary<Type, Type[]>()
|
return new Dictionary<Type, Type[]>()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
|
|
@ -186,7 +166,11 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
typeof(IConfigureOptions<RazorViewEngineOptions>),
|
typeof(IConfigureOptions<RazorViewEngineOptions>),
|
||||||
razorViewEngineOptionsRegistrations
|
new[]
|
||||||
|
{
|
||||||
|
typeof(RazorViewEngineOptionsSetup),
|
||||||
|
typeof(DependencyContextRazorViewEngineOptionsSetup)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
typeof(IActionConstraintProvider),
|
typeof(IActionConstraintProvider),
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,21 @@
|
||||||
"Microsoft.AspNetCore.Mvc.Formatters.Xml": "1.0.0-*",
|
"Microsoft.AspNetCore.Mvc.Formatters.Xml": "1.0.0-*",
|
||||||
"Microsoft.Extensions.DependencyInjection": "1.0.0-*",
|
"Microsoft.Extensions.DependencyInjection": "1.0.0-*",
|
||||||
"Microsoft.Extensions.Logging": "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",
|
"testRunner": "xunit",
|
||||||
"commands": {
|
"commands": {
|
||||||
"test": "xunit.runner.aspnet"
|
"test": "xunit.runner.aspnet"
|
||||||
},
|
},
|
||||||
"frameworks": {
|
"frameworks": {
|
||||||
|
"dnxcore50": {
|
||||||
|
"imports": "portable-net451+win8",
|
||||||
|
"dependencies": {
|
||||||
|
"moq.netcore": "4.4.0-beta8",
|
||||||
|
"dotnet-test-xunit": "1.0.0-dev-*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"dnx451": {
|
"dnx451": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Moq": "4.2.1312.1622",
|
"Moq": "4.2.1312.1622",
|
||||||
|
|
@ -22,15 +30,7 @@
|
||||||
},
|
},
|
||||||
"net451": {
|
"net451": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Moq": "4.2.1312.1622",
|
"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-*"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,13 @@
|
||||||
"test": "xunit.runner.aspnet"
|
"test": "xunit.runner.aspnet"
|
||||||
},
|
},
|
||||||
"frameworks": {
|
"frameworks": {
|
||||||
|
"dnxcore50": {
|
||||||
|
"imports": "portable-net451+win8",
|
||||||
|
"dependencies": {
|
||||||
|
"moq.netcore": "4.4.0-beta8",
|
||||||
|
"dotnet-test-xunit": "1.0.0-dev-*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"dnx451": {
|
"dnx451": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Moq": "4.2.1312.1622",
|
"Moq": "4.2.1312.1622",
|
||||||
|
|
@ -36,13 +43,6 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Moq": "4.2.1312.1622"
|
"Moq": "4.2.1312.1622"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"dnxcore50": {
|
|
||||||
"imports": "portable-net451+win8",
|
|
||||||
"dependencies": {
|
|
||||||
"moq.netcore": "4.4.0-beta8",
|
|
||||||
"xunit.runner.aspnet": "2.0.0-aspnet-*"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -16,18 +16,18 @@
|
||||||
"test": "xunit.runner.aspnet"
|
"test": "xunit.runner.aspnet"
|
||||||
},
|
},
|
||||||
"frameworks": {
|
"frameworks": {
|
||||||
|
"dnxcore50": {
|
||||||
|
"imports": "portable-net451+win8",
|
||||||
|
"dependencies": {
|
||||||
|
"moq.netcore": "4.4.0-beta8",
|
||||||
|
"dotnet-test-xunit": "1.0.0-dev-*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"dnx451": {
|
"dnx451": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Moq": "4.2.1312.1622",
|
"Moq": "4.2.1312.1622",
|
||||||
"xunit.runner.aspnet": "2.0.0-aspnet-*"
|
"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-*"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -7,7 +7,7 @@ namespace RazorWebSite
|
||||||
{
|
{
|
||||||
public string ExecuteOperation()
|
public string ExecuteOperation()
|
||||||
{
|
{
|
||||||
#if NET451
|
#if NET451 || DNX451
|
||||||
return "This method is running from NET451";
|
return "This method is running from NET451";
|
||||||
#elif DNXCORE50
|
#elif DNXCORE50
|
||||||
return "This method is running from DNXCORE50";
|
return "This method is running from DNXCORE50";
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,8 @@ namespace RazorWebSite
|
||||||
.AddRazorOptions(options =>
|
.AddRazorOptions(options =>
|
||||||
{
|
{
|
||||||
options.ViewLocationExpanders.Add(new NonMainPageViewLocationExpander());
|
options.ViewLocationExpanders.Add(new NonMainPageViewLocationExpander());
|
||||||
#if DNXCORE50
|
#if NET451
|
||||||
options.ParseOptions = options.ParseOptions.WithPreprocessorSymbols("DNXCORE50", "DNXCORE50_CUSTOM_DEFINE");
|
options.ParseOptions = options.ParseOptions.WithPreprocessorSymbols("DNX451", "NET451_CUSTOM_DEFINE");
|
||||||
#endif
|
#endif
|
||||||
})
|
})
|
||||||
.AddViewOptions(options =>
|
.AddViewOptions(options =>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue