diff --git a/src/MvcSiteMapProvider/CodeAsConfiguration/Shared/DI/CommonConventions.cs b/src/MvcSiteMapProvider/CodeAsConfiguration/Shared/DI/CommonConventions.cs
index 7958b863..83e68e66 100644
--- a/src/MvcSiteMapProvider/CodeAsConfiguration/Shared/DI/CommonConventions.cs
+++ b/src/MvcSiteMapProvider/CodeAsConfiguration/Shared/DI/CommonConventions.cs
@@ -8,7 +8,27 @@ namespace DI
{
internal class CommonConventions
{
- // Single implementations of interface with matching name (minus the "I").
+ ///
+ /// Registers all single types in a set of assemblies that meet the following criteria:
+ /// 1) The name of the type matches the interface name (I[TypeName] = [TypeName]) or
+ /// 2) The name of the type matches the interface name + the suffix "Adapter" (I[TypeName] = [TypeName]Adapter)
+ /// 3) The class does not have a string parameter in the constructor
+ /// 4) The class is not decorated with the [ExcludeFromAutoRegistrationAttribute]
+ ///
+ /// The method on the DI container used to register a type to an abstraction.
+ /// Should be in the format (interfaceType, implementationType) => SomeMethod(interfaceType, implementationType)
+ /// or similar.
+ /// An array of assemblies to scan for the interface types. These assemblies
+ /// must be referenced within this project. Typically, you will just want to use the MvcSiteMapProvider
+ /// assembly unless you decide to use throughout your project.
+ /// An array of assemblies to scan for the implementation types.
+ /// This array should contain all of the assemblies where you have defined types that will be injected
+ /// into MvcSiteMapProvider.
+ /// An array of used to manually exclude types if
+ /// you intend to register them manually. Use this parameter if you want to inject your own implementation
+ /// and therefore don't want the default type automatically registered.
+ /// A regular expression that can be used to exclude types based on the type
+ /// name (excluding the namespace name). All types that match the regular expression will be excluded.
public static void RegisterDefaultConventions(
Action registerMethod,
Assembly[] interfaceAssemblies,
@@ -23,27 +43,52 @@ public static void RegisterDefaultConventions(
foreach (var interfaceType in interfaces)
{
- if (!IsMatch(interfaceType, excludeTypes, excludeRegEx))
+ if (!IsExcludedType(interfaceType, excludeTypes, excludeRegEx))
{
List implementations = new List();
foreach (var assembly in implementationAssemblies)
- implementations.AddRange(GetImplementationsOfInterface(assembly, interfaceType));
+ implementations.AddRange(GetImplementationsOfInterface(assembly, interfaceType).Where(implementation => !IsExcludedType(implementation, excludeTypes, excludeRegEx)).ToArray());
- if (implementations.Count == 1)
+ // Prefer the default name ITypeName = TypeName
+ Type implementationType = implementations.Where(implementation => IsDefaultType(interfaceType, implementation)).FirstOrDefault();
+
+ if (implementationType == null)
+ {
+ // Fall back on ITypeName = ITypeNameAdapter
+ implementationType = implementations.Where(implementation => IsAdapterType(interfaceType, implementation)).FirstOrDefault();
+ }
+
+ if (implementationType != null)
{
- var implementationType = implementations[0];
- if (!IsMatch(implementationType, excludeTypes, excludeRegEx) && interfaceType.Name.Equals("I" + implementationType.Name))
- {
- System.Diagnostics.Debug.WriteLine("Auto registration of {1} : {0}", interfaceType.Name, implementationType.Name);
- registerMethod(interfaceType, implementationType);
- }
+ System.Diagnostics.Debug.WriteLine("Auto registration of {1} : {0}", interfaceType.Name, implementationType.Name);
+ registerMethod(interfaceType, implementationType);
}
}
}
}
// For DI containers that allow the use of a multiple registration method calls for individual implementations of a given interface
+
+ ///
+ /// Registers all of the types that implement the passed in interfaceTypes with the DI container so they can be
+ /// resolved as an of values (where T is the interface type).
+ ///
+ /// This overload is for DI containers that allow the use of multiple registration method calls, one for
+ /// each implementation of the interface.
+ ///
+ /// The method of the DI container used to register a single implementation, which will be
+ /// called one time per implementation found to register each implementation of the type. Should be in the format
+ /// (interfaceType, implementationType) => SomeMethod(interfaceType, implementationType) or similar.
+ /// The interfaces to limit the registration to. If empty, no types will be registered.
+ /// An array of assemblies to scan for the implementation types.
+ /// This array should contain all of the assemblies where you have defined types that will be injected
+ /// into MvcSiteMapProvider.
+ /// An array of used to manually exclude types if
+ /// you intend to register them manually. Use this parameter if you want to inject your own implementation
+ /// and therefore don't want the default type automatically registered.
+ /// A regular expression that can be used to exclude types based on the type
+ /// name (excluding the namespace name). All types that match the regular expression will be excluded.
public static void RegisterAllImplementationsOfInterface(
Action registerMethod,
Type[] interfaceTypes,
@@ -60,7 +105,7 @@ public static void RegisterAllImplementationsOfInterface(
foreach (var implementationType in implementations)
{
- if (!IsMatch(implementationType, excludeTypes, excludeRegEx))
+ if (!IsExcludedType(implementationType, excludeTypes, excludeRegEx))
{
System.Diagnostics.Debug.WriteLine("Auto registration of {1} : {0}", interfaceType.Name, implementationType.Name);
registerMethod(interfaceType, implementationType);
@@ -69,7 +114,26 @@ public static void RegisterAllImplementationsOfInterface(
}
}
- // For DI containers that require the use of a single registration method call for all implementations of a given interface
+ ///
+ /// Registers all of the types that implement the passed in interfaceTypes with the DI container so they can be
+ /// resolved as an of values (where T is the interface type).
+ ///
+ /// This overload is for DI containers that require the use of a multiple registration method call for
+ /// all implementations a given interface.
+ ///
+ /// The method of the DI container used to register an array of implementations, which will be
+ /// called only one time to register all of the implementations of the type. Should be in the format
+ /// (interfaceType, implementationTypes) => SomeMethod(interfaceType, implementationTypes) or similar, where
+ /// implementationTypes is a .
+ /// The interfaces to limit the registration to. If empty, no types will be registered.
+ /// An array of assemblies to scan for the implementation types.
+ /// This array should contain all of the assemblies where you have defined types that will be injected
+ /// into MvcSiteMapProvider.
+ /// An array of used to manually exclude types if
+ /// you intend to register them manually. Use this parameter if you want to inject your own implementation
+ /// and therefore don't want the default type automatically registered.
+ /// A regular expression that can be used to exclude types based on the type
+ /// name (excluding the namespace name). All types that match the regular expression will be excluded.
public static void RegisterAllImplementationsOfInterfaceSingle(
Action> registerMethod,
Type[] interfaceTypes,
@@ -87,7 +151,7 @@ public static void RegisterAllImplementationsOfInterfaceSingle(
foreach (var implementationType in implementations)
{
- if (!IsMatch(implementationType, excludeTypes, excludeRegEx))
+ if (!IsExcludedType(implementationType, excludeTypes, excludeRegEx))
{
matchingImplementations.Add(implementationType);
}
@@ -99,22 +163,38 @@ public static void RegisterAllImplementationsOfInterfaceSingle(
}
- private static bool IsMatch(Type type, Type[] excludeTypes, string excludeRegEx)
+ private static bool IsExcludedType(Type type, Type[] excludeTypes, string excludeRegEx)
{
- return IsMatch(type, excludeTypes) || IsMatch(type, excludeRegEx);
+ return IsExcludedType(type, excludeTypes) || IsExcludedType(type, excludeRegEx) || IsExcludedType(type);
}
- private static bool IsMatch(Type type, Type[] excludeTypes)
+ private static bool IsExcludedType(Type type, Type[] excludeTypes)
{
return excludeTypes.Contains(type);
}
- private static bool IsMatch(Type type, string excludeRegEx)
+ private static bool IsExcludedType(Type type, string excludeRegEx)
{
if (string.IsNullOrEmpty(excludeRegEx)) return false;
return Regex.Match(type.Name, excludeRegEx, RegexOptions.Compiled).Success;
}
+ private static bool IsExcludedType(Type type)
+ {
+ return type.GetCustomAttributes(typeof(MvcSiteMapProvider.DI.ExcludeFromAutoRegistrationAttribute), false).Length > 0;
+ }
+
+ private static bool IsDefaultType(Type interfaceType, Type implementationType)
+ {
+ return interfaceType.Name.Equals("I" + implementationType.Name);
+ }
+
+ private static bool IsAdapterType(Type interfaceType, Type implementationType)
+ {
+ return implementationType.Name.EndsWith("Adapter") &&
+ interfaceType.Name.Equals("I" + implementationType.Name.Substring(0, implementationType.Name.Length - 7));
+ }
+
private static IEnumerable GetInterfaces(Assembly assembly)
{
return assembly.GetTypes().Where(t => t.IsInterface);