Automatically register controllers with Sitecore 8.2 IoC container
using System; | |
using System.Collections.Generic; | |
using System.Globalization; | |
using System.Linq; | |
using System.Reflection; | |
using System.Runtime.CompilerServices; | |
using System.Text.RegularExpressions; | |
using System.Web.Mvc; | |
using Microsoft.Extensions.DependencyInjection; | |
namespace Sitecore.Foundation.DependencyInjection | |
{ | |
public static class ServiceCollectionExtensions | |
{ | |
[MethodImplAttribute(MethodImplOptions.NoInlining)] | |
public static void AddMvcControllersInCurrentAssembly(this IServiceCollection serviceCollection) | |
{ | |
AddMvcControllers(serviceCollection, Assembly.GetCallingAssembly()); | |
} | |
public static void AddMvcControllers(this IServiceCollection serviceCollection, params string[] assemblyFilters) | |
{ | |
var assemblyNames = new HashSet<string>(assemblyFilters.Where(filter => !filter.Contains('*'))); | |
var wildcardNames = assemblyFilters.Where(filter => filter.Contains('*')).ToArray(); | |
var assemblies = AppDomain.CurrentDomain.GetAssemblies().Where(assembly => | |
{ | |
var nameToMatch = assembly.GetName().Name; | |
if (assemblyNames.Contains(nameToMatch)) return true; | |
return wildcardNames.Any(wildcard => IsWildcardMatch(nameToMatch, wildcard)); | |
}) | |
.ToArray(); | |
AddMvcControllers(serviceCollection, assemblies); | |
} | |
public static void AddMvcControllers(this IServiceCollection serviceCollection, params Assembly[] assemblies) | |
{ | |
var controllers = GetTypesImplementing<IController>(assemblies) | |
.Where(controller => controller.Name.EndsWith("Controller", StringComparison.Ordinal)); | |
foreach (var controller in controllers) | |
{ | |
serviceCollection.AddTransient(controller); | |
} | |
// h/t Sean Holmesby and Akshay Sura: this adds Web API controller support | |
var apiControllers = GetTypesImplementing<ApiController>(assemblies) | |
.Where(controller => controller.Name.EndsWith("Controller", StringComparison.Ordinal)); | |
foreach (var apiController in apiControllers) | |
{ | |
serviceCollection.AddTransient(apiController); | |
} | |
} | |
public static Type[] GetTypesImplementing<T>(params Assembly[] assemblies) | |
{ | |
if (assemblies == null || assemblies.Length == 0) | |
{ | |
return new Type[0]; | |
} | |
var targetType = typeof(T); | |
return assemblies | |
.Where(assembly => !assembly.IsDynamic) | |
.SelectMany(GetExportedTypes) | |
.Where(type => !type.IsAbstract && !type.IsGenericTypeDefinition && targetType.IsAssignableFrom(type)) | |
.ToArray(); | |
} | |
private static IEnumerable<Type> GetExportedTypes(Assembly assembly) | |
{ | |
try | |
{ | |
return assembly.GetExportedTypes(); | |
} | |
catch (NotSupportedException) | |
{ | |
// A type load exception would typically happen on an Anonymously Hosted DynamicMethods | |
// Assembly and it would be safe to skip this exception. | |
return Type.EmptyTypes; | |
} | |
catch (ReflectionTypeLoadException ex) | |
{ | |
// Return the types that could be loaded. Types can contain null values. | |
return ex.Types.Where(type => type != null); | |
} | |
catch (Exception ex) | |
{ | |
// Throw a more descriptive message containing the name of the assembly. | |
throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, | |
"Unable to load types from assembly {0}. {1}", assembly.FullName, ex.Message), ex); | |
} | |
} | |
/// <summary> | |
/// Checks if a string matches a wildcard argument (using regex) | |
/// </summary> | |
private static bool IsWildcardMatch(string input, string wildcards) | |
{ | |
return Regex.IsMatch(input, "^" + Regex.Escape(wildcards).Replace("\\*", ".*").Replace("\\?", ".") + "$", RegexOptions.IgnoreCase); | |
} | |
} | |
} |
This comment has been minimized.
This comment has been minimized.
I added the change to the gist with credit; thanks! |
This comment has been minimized.
This comment has been minimized.
To make it work for attribute routed ApiControllers, I changed it to add types implementing IHttpController instead of ApiController (without this change, the ApiControllers returned 404):
|
This comment has been minimized.
This comment has been minimized.
Great! I owe you a beer. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This comment has been minimized.
Thanks to Sean Holmesby I found why my ApiController weren't working with Microsoft DI and here is it: