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
|
||||
{
|
||||
IEnumerable<Assembly> Assemblies { get; }
|
||||
IEnumerable<Assembly> CandidateAssemblies { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,3 +34,4 @@ using System.Runtime.InteropServices;
|
|||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("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()
|
||||
{
|
||||
var assemblies = _controllerAssemblyProvider.Assemblies;
|
||||
var assemblies = _controllerAssemblyProvider.CandidateAssemblies;
|
||||
var types = assemblies.SelectMany(a => a.DefinedTypes);
|
||||
var controllers = types.Where(_conventions.IsController);
|
||||
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
|
||||
{
|
||||
private readonly ILibraryExportProvider _exportProvider;
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly IApplicationEnvironment _environment;
|
||||
private readonly IAssemblyLoaderEngine _loader;
|
||||
|
||||
public RoslynCompilationService(IApplicationEnvironment environment,
|
||||
IAssemblyLoaderEngine loaderEngine,
|
||||
ILibraryExportProvider exportProvider)
|
||||
ILibraryManager libraryManager)
|
||||
{
|
||||
_environment = environment;
|
||||
_loader = loaderEngine;
|
||||
_exportProvider = exportProvider;
|
||||
_libraryManager = libraryManager;
|
||||
}
|
||||
|
||||
public Task<CompilationResult> Compile(string content)
|
||||
|
|
@ -67,7 +67,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
|
|||
{
|
||||
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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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<IActionResultFactory, ActionResultFactory>();
|
||||
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.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