Modify controller discovery to only look for types that reference Mvc.Core
assembly
This commit is contained in:
parent
683c5bf9b3
commit
8ea196023e
|
|
@ -1,30 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
|
||||||
{
|
|
||||||
public class AppDomainControllerAssemblyProvider : IControllerAssemblyProvider
|
|
||||||
{
|
|
||||||
public IEnumerable<Assembly> Assemblies
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies().Where(AllowAssembly))
|
|
||||||
{
|
|
||||||
yield return assembly;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool AllowAssembly(Assembly assembly)
|
|
||||||
{
|
|
||||||
// consider mechanisms to filter assemblies upfront, so scanning cost is minimized and startup improved.
|
|
||||||
// 1 - Does assembly reference the WebFx assembly (directly or indirectly). - Down side, object only controller not supported.
|
|
||||||
// 2 - Remove well known assemblies (maintenance and composability cost)
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using Microsoft.Net.Runtime;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc
|
||||||
|
{
|
||||||
|
public class DefaultControllerAssemblyProvider : IControllerAssemblyProvider
|
||||||
|
{
|
||||||
|
// List of Mvc assemblies that we'll use as roots for controller discovery.
|
||||||
|
private static readonly HashSet<string> _mvcAssemblyList = new HashSet<string>(StringComparer.Ordinal)
|
||||||
|
{
|
||||||
|
"Microsoft.AspNet.Mvc",
|
||||||
|
"Microsoft.AspNet.Mvc.Core",
|
||||||
|
"Microsoft.AspNet.Mvc.ModelBinding",
|
||||||
|
"Microsoft.AspNet.Mvc.Razor",
|
||||||
|
"Microsoft.AspNet.Mvc.Razor.Host",
|
||||||
|
"Microsoft.AspNet.Mvc.Rendering",
|
||||||
|
};
|
||||||
|
private readonly ILibraryManager _libraryManager;
|
||||||
|
private readonly Func<ILibraryInformation, Assembly> _assemblyLoader;
|
||||||
|
|
||||||
|
public DefaultControllerAssemblyProvider(ILibraryManager libraryManager)
|
||||||
|
{
|
||||||
|
_libraryManager = libraryManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<Assembly> CandidateAssemblies
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return GetCandiateLibraries().Select(Load);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal IEnumerable<ILibraryInformation> GetCandiateLibraries()
|
||||||
|
{
|
||||||
|
// GetReferencingLibraries returns the transitive closure of referencing assemblies
|
||||||
|
// for a given assembly. In our case, we'll gather all assemblies that reference
|
||||||
|
// any of the primary Mvc assemblies while ignoring Mvc assemblies.
|
||||||
|
return _mvcAssemblyList.SelectMany(_libraryManager.GetReferencingLibraries)
|
||||||
|
.Distinct()
|
||||||
|
.Where(IsCandidateLibrary);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Assembly Load(ILibraryInformation library)
|
||||||
|
{
|
||||||
|
return Assembly.Load(new AssemblyName(library.Name));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsCandidateLibrary(ILibraryInformation library)
|
||||||
|
{
|
||||||
|
return !_mvcAssemblyList.Contains(library.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,6 +5,6 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
public interface IControllerAssemblyProvider
|
public interface IControllerAssemblyProvider
|
||||||
{
|
{
|
||||||
IEnumerable<Assembly> Assemblies { get; }
|
IEnumerable<Assembly> CandidateAssemblies { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,3 +34,4 @@ using System.Runtime.InteropServices;
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
[assembly: AssemblyVersion("1.0.0.0")]
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||||
|
[assembly: InternalsVisibleTo("Microsoft.AspNet.Mvc.Core.Test")]
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
public IEnumerable<ActionDescriptor> GetDescriptors()
|
public IEnumerable<ActionDescriptor> GetDescriptors()
|
||||||
{
|
{
|
||||||
var assemblies = _controllerAssemblyProvider.Assemblies;
|
var assemblies = _controllerAssemblyProvider.CandidateAssemblies;
|
||||||
var types = assemblies.SelectMany(a => a.DefinedTypes);
|
var types = assemblies.SelectMany(a => a.DefinedTypes);
|
||||||
var controllers = types.Where(_conventions.IsController);
|
var controllers = types.Where(_conventions.IsController);
|
||||||
var controllerDescriptors = controllers.Select(t => _controllerDescriptorFactory.CreateControllerDescriptor(t)).ToArray();
|
var controllerDescriptors = controllers.Select(t => _controllerDescriptorFactory.CreateControllerDescriptor(t)).ToArray();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.Net.Runtime
|
||||||
|
{
|
||||||
|
[AssemblyNeutral]
|
||||||
|
public class AssemblyNeutralAttribute : Attribute { }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Microsoft.Net.Runtime
|
||||||
|
{
|
||||||
|
[AssemblyNeutral]
|
||||||
|
public interface ILibraryExport
|
||||||
|
{
|
||||||
|
IList<IMetadataReference> MetadataReferences { get; }
|
||||||
|
IList<ISourceReference> SourceReferences { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Microsoft.Net.Runtime
|
||||||
|
{
|
||||||
|
[AssemblyNeutral]
|
||||||
|
public interface ILibraryInformation
|
||||||
|
{
|
||||||
|
string Name { get; }
|
||||||
|
|
||||||
|
IEnumerable<string> Dependencies { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Microsoft.Net.Runtime
|
||||||
|
{
|
||||||
|
[AssemblyNeutral]
|
||||||
|
public interface ILibraryManager
|
||||||
|
{
|
||||||
|
ILibraryExport GetLibraryExport(string name);
|
||||||
|
|
||||||
|
IEnumerable<ILibraryInformation> GetReferencingLibraries(string name);
|
||||||
|
|
||||||
|
ILibraryInformation GetLibraryInformation(string name);
|
||||||
|
|
||||||
|
IEnumerable<ILibraryInformation> GetLibraries();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
|
||||||
|
namespace Microsoft.Net.Runtime
|
||||||
|
{
|
||||||
|
[AssemblyNeutral]
|
||||||
|
public interface IMetadataReference
|
||||||
|
{
|
||||||
|
string Name { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
namespace Microsoft.Net.Runtime
|
||||||
|
{
|
||||||
|
[AssemblyNeutral]
|
||||||
|
public interface ISourceReference
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -12,17 +12,17 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
|
||||||
{
|
{
|
||||||
public class RoslynCompilationService : ICompilationService
|
public class RoslynCompilationService : ICompilationService
|
||||||
{
|
{
|
||||||
private readonly ILibraryExportProvider _exportProvider;
|
private readonly ILibraryManager _libraryManager;
|
||||||
private readonly IApplicationEnvironment _environment;
|
private readonly IApplicationEnvironment _environment;
|
||||||
private readonly IAssemblyLoaderEngine _loader;
|
private readonly IAssemblyLoaderEngine _loader;
|
||||||
|
|
||||||
public RoslynCompilationService(IApplicationEnvironment environment,
|
public RoslynCompilationService(IApplicationEnvironment environment,
|
||||||
IAssemblyLoaderEngine loaderEngine,
|
IAssemblyLoaderEngine loaderEngine,
|
||||||
ILibraryExportProvider exportProvider)
|
ILibraryManager libraryManager)
|
||||||
{
|
{
|
||||||
_environment = environment;
|
_environment = environment;
|
||||||
_loader = loaderEngine;
|
_loader = loaderEngine;
|
||||||
_exportProvider = exportProvider;
|
_libraryManager = libraryManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<CompilationResult> Compile(string content)
|
public Task<CompilationResult> Compile(string content)
|
||||||
|
|
@ -67,7 +67,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
|
||||||
{
|
{
|
||||||
var references = new List<MetadataReference>();
|
var references = new List<MetadataReference>();
|
||||||
|
|
||||||
var export = _exportProvider.GetLibraryExport(_environment.ApplicationName, _environment.TargetFramework);
|
var export = _libraryManager.GetLibraryExport(_environment.ApplicationName);
|
||||||
|
|
||||||
foreach (var metadataReference in export.MetadataReferences)
|
foreach (var metadataReference in export.MetadataReferences)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
using System.Runtime.Versioning;
|
|
||||||
|
|
||||||
namespace Microsoft.Net.Runtime
|
|
||||||
{
|
|
||||||
[AssemblyNeutral]
|
|
||||||
public interface ILibraryExportProvider
|
|
||||||
{
|
|
||||||
ILibraryExport GetLibraryExport(string name, FrameworkName targetFramework);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Microsoft.Net.Runtime
|
||||||
|
{
|
||||||
|
[AssemblyNeutral]
|
||||||
|
public interface ILibraryInformation
|
||||||
|
{
|
||||||
|
string Name { get; }
|
||||||
|
|
||||||
|
IEnumerable<string> Dependencies { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Microsoft.Net.Runtime
|
||||||
|
{
|
||||||
|
[AssemblyNeutral]
|
||||||
|
public interface ILibraryManager
|
||||||
|
{
|
||||||
|
ILibraryExport GetLibraryExport(string name);
|
||||||
|
|
||||||
|
IEnumerable<ILibraryInformation> GetReferencingLibraries(string name);
|
||||||
|
|
||||||
|
ILibraryInformation GetLibraryInformation(string name);
|
||||||
|
|
||||||
|
IEnumerable<ILibraryInformation> GetLibraries();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -28,7 +28,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
yield return describe.Transient<IActionResultHelper, ActionResultHelper>();
|
yield return describe.Transient<IActionResultHelper, ActionResultHelper>();
|
||||||
yield return describe.Transient<IActionResultFactory, ActionResultFactory>();
|
yield return describe.Transient<IActionResultFactory, ActionResultFactory>();
|
||||||
yield return describe.Transient<IParameterDescriptorFactory, DefaultParameterDescriptorFactory>();
|
yield return describe.Transient<IParameterDescriptorFactory, DefaultParameterDescriptorFactory>();
|
||||||
yield return describe.Transient<IControllerAssemblyProvider, AppDomainControllerAssemblyProvider>();
|
yield return describe.Transient<IControllerAssemblyProvider, DefaultControllerAssemblyProvider>();
|
||||||
yield return describe.Transient<IActionDiscoveryConventions, DefaultActionDiscoveryConventions>();
|
yield return describe.Transient<IActionDiscoveryConventions, DefaultActionDiscoveryConventions>();
|
||||||
|
|
||||||
yield return describe.Instance<IMvcRazorHost>(new MvcRazorHost(typeof(RazorView).FullName));
|
yield return describe.Instance<IMvcRazorHost>(new MvcRazorHost(typeof(RazorView).FullName));
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using Microsoft.Net.Runtime;
|
||||||
|
using Moq;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.Core
|
||||||
|
{
|
||||||
|
public class DefaultControllerAssemblyProviderTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void CandidateAssemblies_IgnoresMvcAssemblies()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var manager = new Mock<ILibraryManager>();
|
||||||
|
manager.Setup(f => f.GetReferencingLibraries(It.IsAny<string>()))
|
||||||
|
.Returns(new[]
|
||||||
|
{
|
||||||
|
CreateLibraryInfo("Microsoft.AspNet.Mvc.Core"),
|
||||||
|
CreateLibraryInfo("Microsoft.AspNet.Mvc"),
|
||||||
|
CreateLibraryInfo("Microsoft.AspNet.Mvc.ModelBinding"),
|
||||||
|
CreateLibraryInfo("SomeRandomAssembly"),
|
||||||
|
})
|
||||||
|
.Verifiable();
|
||||||
|
var provider = new DefaultControllerAssemblyProvider(manager.Object);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var candidates = provider.GetCandiateLibraries();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(new[] { "SomeRandomAssembly" }, candidates.Select(a => a.Name));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CandidateAssemblies_ReturnsLibrariesReferencingAnyMvcAssembly()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var manager = new Mock<ILibraryManager>();
|
||||||
|
manager.Setup(f => f.GetReferencingLibraries(It.IsAny<string>()))
|
||||||
|
.Returns(Enumerable.Empty<ILibraryInformation>());
|
||||||
|
manager.Setup(f => f.GetReferencingLibraries("Microsoft.AspNet.Mvc.Core"))
|
||||||
|
.Returns(new[] { CreateLibraryInfo("Foo") });
|
||||||
|
manager.Setup(f => f.GetReferencingLibraries("Microsoft.AspNet.Mvc.ModelBinding"))
|
||||||
|
.Returns(new[] { CreateLibraryInfo("Bar") });
|
||||||
|
manager.Setup(f => f.GetReferencingLibraries("Microsoft.AspNet.Mvc"))
|
||||||
|
.Returns(new[] { CreateLibraryInfo("Baz") });
|
||||||
|
var provider = new DefaultControllerAssemblyProvider(manager.Object);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var candidates = provider.GetCandiateLibraries();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(new[] { "Baz", "Foo", "Bar" }, candidates.Select(a => a.Name));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ILibraryInformation CreateLibraryInfo(string name)
|
||||||
|
{
|
||||||
|
var info = new Mock<ILibraryInformation>();
|
||||||
|
info.SetupGet(b => b.Name).Returns(name);
|
||||||
|
return info.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue