From 385c21fbe2af2d61e697b9df826681e6d064d85c Mon Sep 17 00:00:00 2001 From: Pranav K Date: Fri, 26 Feb 2016 12:01:40 -0800 Subject: [PATCH] Add Microsoft.AspNetCore.Mvc.Dnx to allow using Mvc with DNX --- Mvc.NoFun.sln | 16 +++- Mvc.sln | 16 +++- NuGetPackageVerifier.json | 1 + samples/MvcSandbox/Startup.cs | 3 + samples/MvcSandbox/project.json | 7 +- .../DnxAssemblyProvider.cs | 88 +++++++++++++++++++ .../DnxRoslynCompilationService.cs | 37 ++++++-- .../Microsoft.AspNetCore.Mvc.Dnx.xproj | 19 ++++ .../MvcDnxServiceCollectionExtensions.cs | 35 ++++++++ .../Properties/AssemblyInfo.cs | 9 ++ src/Microsoft.AspNetCore.Mvc.Dnx/project.json | 27 ++++++ .../project.json | 3 +- 12 files changed, 249 insertions(+), 12 deletions(-) create mode 100644 src/Microsoft.AspNetCore.Mvc.Dnx/DnxAssemblyProvider.cs rename {test/Microsoft.AspNetCore.Mvc.FunctionalTests => src/Microsoft.AspNetCore.Mvc.Dnx}/DnxRoslynCompilationService.cs (92%) create mode 100644 src/Microsoft.AspNetCore.Mvc.Dnx/Microsoft.AspNetCore.Mvc.Dnx.xproj create mode 100644 src/Microsoft.AspNetCore.Mvc.Dnx/MvcDnxServiceCollectionExtensions.cs create mode 100644 src/Microsoft.AspNetCore.Mvc.Dnx/Properties/AssemblyInfo.cs create mode 100644 src/Microsoft.AspNetCore.Mvc.Dnx/project.json diff --git a/Mvc.NoFun.sln b/Mvc.NoFun.sln index 166b89b514..f8139aef79 100644 --- a/Mvc.NoFun.sln +++ b/Mvc.NoFun.sln @@ -1,4 +1,3 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 VisualStudioVersion = 14.0.24720.0 @@ -102,6 +101,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ActionConstraintSample.Web" EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MvcSubAreaSample.Web", "samples\MvcSubAreaSample.Web\MvcSubAreaSample.Web.xproj", "{45F6B3B6-D114-4D77-84D6-561B3957F341}" EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Mvc.Dnx", "src\Microsoft.AspNetCore.Mvc.Dnx\Microsoft.AspNetCore.Mvc.Dnx.xproj", "{8FB691C2-DFD8-4FEE-9628-2BB8466A691C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -606,6 +607,18 @@ Global {45F6B3B6-D114-4D77-84D6-561B3957F341}.Release|Mixed Platforms.Build.0 = Release|Any CPU {45F6B3B6-D114-4D77-84D6-561B3957F341}.Release|x86.ActiveCfg = Release|Any CPU {45F6B3B6-D114-4D77-84D6-561B3957F341}.Release|x86.Build.0 = Release|Any CPU + {8FB691C2-DFD8-4FEE-9628-2BB8466A691C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8FB691C2-DFD8-4FEE-9628-2BB8466A691C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8FB691C2-DFD8-4FEE-9628-2BB8466A691C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {8FB691C2-DFD8-4FEE-9628-2BB8466A691C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {8FB691C2-DFD8-4FEE-9628-2BB8466A691C}.Debug|x86.ActiveCfg = Debug|Any CPU + {8FB691C2-DFD8-4FEE-9628-2BB8466A691C}.Debug|x86.Build.0 = Debug|Any CPU + {8FB691C2-DFD8-4FEE-9628-2BB8466A691C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8FB691C2-DFD8-4FEE-9628-2BB8466A691C}.Release|Any CPU.Build.0 = Release|Any CPU + {8FB691C2-DFD8-4FEE-9628-2BB8466A691C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {8FB691C2-DFD8-4FEE-9628-2BB8466A691C}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {8FB691C2-DFD8-4FEE-9628-2BB8466A691C}.Release|x86.ActiveCfg = Release|Any CPU + {8FB691C2-DFD8-4FEE-9628-2BB8466A691C}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -654,5 +667,6 @@ Global {FCFE6024-2720-49B4-8257-9DBC6114F0F1} = {DAAE4C74-D06F-4874-A166-33305D2643CE} {EE0BD773-4D47-4AA8-8472-5A938A3953BA} = {DAAE4C74-D06F-4874-A166-33305D2643CE} {45F6B3B6-D114-4D77-84D6-561B3957F341} = {DAAE4C74-D06F-4874-A166-33305D2643CE} + {8FB691C2-DFD8-4FEE-9628-2BB8466A691C} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E} EndGlobalSection EndGlobal diff --git a/Mvc.sln b/Mvc.sln index 0fb0a89ab9..ff8a96289a 100644 --- a/Mvc.sln +++ b/Mvc.sln @@ -1,4 +1,3 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 VisualStudioVersion = 14.0.24720.0 @@ -144,6 +143,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "InlineConstraintSample.Web" EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MvcSubAreaSample.Web", "samples\MvcSubAreaSample.Web\MvcSubAreaSample.Web.xproj", "{45F6B3B6-D114-4D77-84D6-561B3957F341}" EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Mvc.Dnx", "src\Microsoft.AspNetCore.Mvc.Dnx\Microsoft.AspNetCore.Mvc.Dnx.xproj", "{8FB691C2-DFD8-4FEE-9628-2BB8466A691C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -867,6 +868,18 @@ Global {45F6B3B6-D114-4D77-84D6-561B3957F341}.Release|Mixed Platforms.Build.0 = Release|Any CPU {45F6B3B6-D114-4D77-84D6-561B3957F341}.Release|x86.ActiveCfg = Release|Any CPU {45F6B3B6-D114-4D77-84D6-561B3957F341}.Release|x86.Build.0 = Release|Any CPU + {8FB691C2-DFD8-4FEE-9628-2BB8466A691C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8FB691C2-DFD8-4FEE-9628-2BB8466A691C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8FB691C2-DFD8-4FEE-9628-2BB8466A691C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {8FB691C2-DFD8-4FEE-9628-2BB8466A691C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {8FB691C2-DFD8-4FEE-9628-2BB8466A691C}.Debug|x86.ActiveCfg = Debug|Any CPU + {8FB691C2-DFD8-4FEE-9628-2BB8466A691C}.Debug|x86.Build.0 = Debug|Any CPU + {8FB691C2-DFD8-4FEE-9628-2BB8466A691C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8FB691C2-DFD8-4FEE-9628-2BB8466A691C}.Release|Any CPU.Build.0 = Release|Any CPU + {8FB691C2-DFD8-4FEE-9628-2BB8466A691C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {8FB691C2-DFD8-4FEE-9628-2BB8466A691C}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {8FB691C2-DFD8-4FEE-9628-2BB8466A691C}.Release|x86.ActiveCfg = Release|Any CPU + {8FB691C2-DFD8-4FEE-9628-2BB8466A691C}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -937,5 +950,6 @@ Global {396B40D7-AC70-49A7-B33C-ED42129FEBE3} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C} {EA34877F-1AC1-42B7-B4E6-15A093F40CAE} = {DAAE4C74-D06F-4874-A166-33305D2643CE} {45F6B3B6-D114-4D77-84D6-561B3957F341} = {DAAE4C74-D06F-4874-A166-33305D2643CE} + {8FB691C2-DFD8-4FEE-9628-2BB8466A691C} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E} EndGlobalSection EndGlobal diff --git a/NuGetPackageVerifier.json b/NuGetPackageVerifier.json index 21c36d6f60..392bb1a748 100644 --- a/NuGetPackageVerifier.json +++ b/NuGetPackageVerifier.json @@ -10,6 +10,7 @@ "Microsoft.AspNetCore.Mvc.Core": { }, "Microsoft.AspNetCore.Mvc.Cors": { }, "Microsoft.AspNetCore.Mvc.DataAnnotations": { }, + "Microsoft.AspNetCore.Mvc.Dnx": { }, "Microsoft.AspNetCore.Mvc.Formatters.Json": { }, "Microsoft.AspNetCore.Mvc.Formatters.Xml": { }, "Microsoft.AspNetCore.Mvc.Localization": { }, diff --git a/samples/MvcSandbox/Startup.cs b/samples/MvcSandbox/Startup.cs index d7f3fcafdf..8e8e822946 100644 --- a/samples/MvcSandbox/Startup.cs +++ b/samples/MvcSandbox/Startup.cs @@ -14,6 +14,9 @@ namespace MvcSandbox public void ConfigureServices(IServiceCollection services) { services.AddMvc(); +#if DNX451 + services.AddMvcDnx(); +#endif } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. diff --git a/samples/MvcSandbox/project.json b/samples/MvcSandbox/project.json index 3d46c43a93..ed2d20a344 100644 --- a/samples/MvcSandbox/project.json +++ b/samples/MvcSandbox/project.json @@ -21,7 +21,12 @@ "dotnet-razor-tooling": "1.0.0-*" }, "frameworks": { - "net451": {}, + "dnx451": { + "dependencies": { + "Microsoft.AspNetCore.Mvc.Dnx": "1.0.0-*" + } + }, + "net451": { }, "dnxcore50": { "imports": "portable-net451+win8", "dependencies": { diff --git a/src/Microsoft.AspNetCore.Mvc.Dnx/DnxAssemblyProvider.cs b/src/Microsoft.AspNetCore.Mvc.Dnx/DnxAssemblyProvider.cs new file mode 100644 index 0000000000..a28590fb08 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Dnx/DnxAssemblyProvider.cs @@ -0,0 +1,88 @@ +// 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.PlatformAbstractions; + +namespace Microsoft.AspNetCore.Mvc.Infrastructure +{ + public class DnxAssemblyProvider : IAssemblyProvider + { + private readonly ILibraryManager _libraryManager; + + public DnxAssemblyProvider(ILibraryManager libraryManager) + { + _libraryManager = libraryManager; + } + + /// + /// Gets the set of assembly names that are used as root for discovery of + /// MVC controllers, view components and views. + /// + // 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 ReferenceAssemblies { get; } = new HashSet(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" + }; + + /// + public IEnumerable CandidateAssemblies + { + get + { + return GetCandidateLibraries().SelectMany(l => l.Assemblies) + .Select(Load); + } + } + + /// + /// Returns a list of libraries that references the assemblies in . + /// By default it returns all assemblies that reference any of the primary MVC assemblies + /// while ignoring MVC assemblies. + /// + /// A set of . + protected virtual IEnumerable GetCandidateLibraries() + { + if (ReferenceAssemblies == null) + { + return Enumerable.Empty(); + } + + // GetReferencingLibraries returns the transitive closure of referencing assemblies + // for a given assembly. + return ReferenceAssemblies.SelectMany(_libraryManager.GetReferencingLibraries) + .Distinct() + .Where(IsCandidateLibrary); + } + + private static Assembly Load(AssemblyName assemblyName) + { + return Assembly.Load(assemblyName); + } + + private bool IsCandidateLibrary(Library library) + { + Debug.Assert(ReferenceAssemblies != null); + return !ReferenceAssemblies.Contains(library.Name); + } + } +} diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/DnxRoslynCompilationService.cs b/src/Microsoft.AspNetCore.Mvc.Dnx/DnxRoslynCompilationService.cs similarity index 92% rename from test/Microsoft.AspNetCore.Mvc.FunctionalTests/DnxRoslynCompilationService.cs rename to src/Microsoft.AspNetCore.Mvc.Dnx/DnxRoslynCompilationService.cs index cd3f48ddc2..c756a41f86 100644 --- a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/DnxRoslynCompilationService.cs +++ b/src/Microsoft.AspNetCore.Mvc.Dnx/DnxRoslynCompilationService.cs @@ -1,7 +1,6 @@ // 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; @@ -10,11 +9,13 @@ 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.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; @@ -35,19 +36,20 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal private readonly ILibraryExporter _libraryExporter; private readonly RazorViewEngineOptions _options; private readonly Lazy> _applicationReferences; +#if DOTNET5_6 + private readonly RazorLoadContext _razorLoadContext; +#endif /// /// Initalizes a new instance of the class. /// /// The environment for the executing application. /// The library manager that provides export and reference information. - /// The that was used to generate the code. /// Accessor to . /// The . - /// The . - public DnxRoslynCompilationService(IApplicationEnvironment environment, + public DnxRoslynCompilationService( + IApplicationEnvironment environment, ILibraryExporter libraryExporter, - IMvcRazorHost host, IOptions optionsAccessor, IRazorViewEngineFileProviderAccessor fileProviderAccessor) { @@ -55,6 +57,10 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal _libraryExporter = libraryExporter; _options = optionsAccessor.Value; _applicationReferences = new Lazy>(GetApplicationReferences); + +#if DOTNET5_6 + _razorLoadContext = new RazorLoadContext(); +#endif } public CompilationResult Compile(RelativeFileInfo fileInfo, string compilationContent) @@ -143,7 +149,11 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal private Assembly LoadStream(MemoryStream ms, MemoryStream assemblySymbols) { +#if DOTNET5_6 + return _razorLoadContext.Load(ms, assemblySymbols); +#else return Assembly.Load(ms.ToArray(), assemblySymbols?.ToArray()); +#endif } private List GetApplicationReferences() @@ -234,6 +244,19 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal return metadata.GetReference(filePath: path); } +#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 } } -#endif \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Dnx/Microsoft.AspNetCore.Mvc.Dnx.xproj b/src/Microsoft.AspNetCore.Mvc.Dnx/Microsoft.AspNetCore.Mvc.Dnx.xproj new file mode 100644 index 0000000000..86261a2e22 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Dnx/Microsoft.AspNetCore.Mvc.Dnx.xproj @@ -0,0 +1,19 @@ + + + + 14.0.24720 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 8fb691c2-dfd8-4fee-9628-2bb8466a691c + Microsoft.AspNetCore.Mvc.Dnx + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin\$(MSBuildProjectName)\ + + + + 2.0 + + + \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Dnx/MvcDnxServiceCollectionExtensions.cs b/src/Microsoft.AspNetCore.Mvc.Dnx/MvcDnxServiceCollectionExtensions.cs new file mode 100644 index 0000000000..be216f209a --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Dnx/MvcDnxServiceCollectionExtensions.cs @@ -0,0 +1,35 @@ +// 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 Microsoft.AspNetCore.Mvc.Infrastructure; +using Microsoft.AspNetCore.Mvc.Razor.Compilation; +using Microsoft.AspNetCore.Mvc.Razor.Internal; +using Microsoft.Extensions.CompilationAbstractions; +using Microsoft.Extensions.PlatformAbstractions; + +namespace Microsoft.Extensions.DependencyInjection +{ + public static class MvcDnxServiceCollectionExtensions + { + /// + /// Adds services required for Mvc applications to work with DNX to the specified . + /// + /// The . + /// A reference to this instance after the operation has completed. + public static IServiceCollection AddMvcDnx(this IServiceCollection services) + { + if (DnxPlatformServices.Default.LibraryManager != null) + { + // Add IAssemblyProvider services + services.AddSingleton(DnxPlatformServices.Default.LibraryManager); + services.AddTransient(); + + // Add compilation services + services.AddSingleton(CompilationServices.Default.LibraryExporter); + services.AddSingleton(); + } + + return services; + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Dnx/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.Mvc.Dnx/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..1bbf723e7d --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Dnx/Properties/AssemblyInfo.cs @@ -0,0 +1,9 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; + +[assembly: AssemblyMetadata("Serviceable", "True")] +[assembly: NeutralResourcesLanguage("en-us")] \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Dnx/project.json b/src/Microsoft.AspNetCore.Mvc.Dnx/project.json new file mode 100644 index 0000000000..277cebee8b --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Dnx/project.json @@ -0,0 +1,27 @@ +{ + "description": "Bridge for keeping compat with DNX.", + "version": "1.0.0-*", + "repository": { + "type": "git", + "url": "git://github.com/aspnet/mvc" + }, + "compilationOptions": { + "warningsAsErrors": true, + "keyFile": "../../tools/Key.snk", + "nowarn": [ "CS1591" ], + "xmlDoc": true + }, + "dependencies": { + "Microsoft.AspNetCore.Mvc.Razor": "1.0.0-*", + "Microsoft.Dnx.Compilation.CSharp.Common": "1.0.0-*", + "Microsoft.Dnx.Compilation.CSharp.Abstractions": "1.0.0-*", + "Microsoft.Extensions.DependencyInjection": "1.0.0-*", + "Microsoft.Extensions.PlatformAbstractions.Dnx": "1.0.0-*" + }, + "frameworks": { + "dnx451": {}, + "dotnet5.6": { + "imports": "portable-net451+win8" + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/project.json index 19b5a6e630..2fd6f380f7 100644 --- a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/project.json @@ -67,8 +67,7 @@ }, "dnx451": { "dependencies": { - "Microsoft.Dnx.Compilation.CSharp.Common": "1.0.0-*", - "Microsoft.Dnx.Compilation.CSharp.Abstractions": "1.0.0-*", + "Microsoft.AspNetCore.Mvc.Dnx": "1.0.0-*", "xunit.runner.aspnet": "2.0.0-aspnet-*" } },