Skip to content

Commit

Permalink
Fixes #414, patch for Simple Injector container initializer so it wil…
Browse files Browse the repository at this point in the history
…l be compatible with both Simple Injector 2.x and 3.x. Also fixed lifestyles so they don't have conflicts.
  • Loading branch information
NightOwl888 committed Oct 12, 2015
1 parent 3b7638a commit 328d30f
Showing 1 changed file with 137 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
using System.Web.Hosting;
using System.Web.Mvc;
using SimpleInjector;
using SimpleInjector.Extensions;
using MvcSiteMapProvider;
using MvcSiteMapProvider.Builder;
using MvcSiteMapProvider.Caching;
Expand Down Expand Up @@ -39,7 +38,7 @@ public static void SetUp(Container container)

// Extension to allow resolution of arrays by GetAllInstances (natively based on IEnumerable).
// source from: https://simpleinjector.codeplex.com/wikipage?title=CollectionRegistrationExtensions
AllowToResolveArraysAndLists(container);
container.AllowToResolveArraysAndLists();

var currentAssembly = typeof(MvcSiteMapProviderContainerInitializer).Assembly;
var siteMapProviderAssembly = typeof(SiteMaps).Assembly;
Expand All @@ -59,6 +58,7 @@ public static void SetUp(Container container)
// Example:
// typeof(SiteMap),
// typeof(SiteMapNodeVisibilityProviderStrategy)
typeof(IMvcContextFactory)
};
var multipleImplementationTypes = new Type[]
{
Expand All @@ -70,71 +70,79 @@ public static void SetUp(Container container)
// Matching type name (I[TypeName] = [TypeName]) or matching type name + suffix Adapter (I[TypeName] = [TypeName]Adapter)
// and not decorated with the [ExcludeFromAutoRegistrationAttribute].
CommonConventions.RegisterDefaultConventions(
(interfaceType, implementationType) => container.RegisterSingle(interfaceType, implementationType),
(interfaceType, implementationType) => container.Register(interfaceType, implementationType),
new Assembly[] { siteMapProviderAssembly },
allAssemblies,
excludeTypes,
string.Empty);

// Multiple implementations of strategy based extension points (and not decorated with [ExcludeFromAutoRegistrationAttribute]).
CommonConventions.RegisterAllImplementationsOfInterfaceSingle(
(interfaceType, implementationTypes) => container.RegisterAll(interfaceType, implementationTypes),
(interfaceType, implementationTypes) => container.RegisterCollection(interfaceType, implementationTypes),
multipleImplementationTypes,
allAssemblies,
excludeTypes,
string.Empty);

container.Register<XmlSiteMapController>();
container.RegisterMvcController<XmlSiteMapController>();

container.Register<IMvcContextFactory, MvcContextFactory>(Lifestyle.Singleton);

// Visibility Providers
container.RegisterSingle<ISiteMapNodeVisibilityProviderStrategy>(() =>
container.Register<ISiteMapNodeVisibilityProviderStrategy>(() =>
new SiteMapNodeVisibilityProviderStrategy(
container.GetAllInstances<ISiteMapNodeVisibilityProvider>().ToArray(), string.Empty));
container.GetAllInstances<ISiteMapNodeVisibilityProvider>().ToArray(), string.Empty),
Lifestyle.Singleton);

// Pass in the global controllerBuilder reference
container.RegisterSingle<ControllerBuilder>(() => ControllerBuilder.Current);
container.Register<ControllerBuilder>(() => ControllerBuilder.Current, Lifestyle.Singleton);

container.RegisterSingle<IControllerTypeResolverFactory>(() =>
container.Register<IControllerTypeResolverFactory>(() =>
new ControllerTypeResolverFactory(
new string[0],
container.GetInstance<IControllerBuilder>(),
container.GetInstance<IBuildManager>()));
container.GetInstance<IBuildManager>()),
Lifestyle.Singleton);

// Configure Security
container.RegisterAll<IAclModule>(typeof(AuthorizeAttributeAclModule), typeof(XmlRolesAclModule));
container.RegisterSingle<IAclModule>(() => new CompositeAclModule(container.GetAllInstances<IAclModule>().ToArray()));
container.RegisterCollection(typeof(IAclModule), new Type[] { typeof(AuthorizeAttributeAclModule), typeof(XmlRolesAclModule) });
container.Register<IAclModule>(() => new CompositeAclModule(container.GetAllInstances<IAclModule>().ToArray()), Lifestyle.Singleton);

// Setup cache
#if NET35
container.RegisterSingleOpenGeneric(typeof(ICacheProvider<>), typeof(AspNetCacheProvider<>));
container.RegisterSingle<ICacheDependency>(() => new AspNetFileCacheDependency(absoluteFileName));
container.RegisterOpenGeneric(typeof(ICacheProvider<>), typeof(AspNetCacheProvider<>), Lifestyle.Singleton);
container.Register<ICacheDependency>(() => new AspNetFileCacheDependency(absoluteFileName), Lifestyle.Singleton);
#else
container.RegisterSingle<System.Runtime.Caching.ObjectCache>(() => System.Runtime.Caching.MemoryCache.Default);
container.RegisterSingleOpenGeneric(typeof(ICacheProvider<>), typeof(RuntimeCacheProvider<>));
container.RegisterSingle<ICacheDependency>(() => new RuntimeFileCacheDependency(absoluteFileName));
container.Register<System.Runtime.Caching.ObjectCache>(() => System.Runtime.Caching.MemoryCache.Default, Lifestyle.Singleton);
container.RegisterOpenGeneric(typeof(ICacheProvider<>), typeof(RuntimeCacheProvider<>), Lifestyle.Singleton);
container.Register<ICacheDependency>(() => new RuntimeFileCacheDependency(absoluteFileName), Lifestyle.Singleton);
#endif
container.RegisterSingle<ICacheDetails>(() => new CacheDetails(absoluteCacheExpiration, TimeSpan.MinValue, container.GetInstance<ICacheDependency>()));
container.Register<ICacheDetails>(() => new CacheDetails(absoluteCacheExpiration, TimeSpan.MinValue, container.GetInstance<ICacheDependency>()), Lifestyle.Singleton);

// Configure the visitors
container.RegisterSingle<ISiteMapNodeVisitor, UrlResolvingSiteMapNodeVisitor>();
container.Register<ISiteMapNodeVisitor, UrlResolvingSiteMapNodeVisitor>(Lifestyle.Singleton);

// Prepare for the sitemap node providers
container.RegisterSingle<IReservedAttributeNameProvider>(() => new ReservedAttributeNameProvider(new string[0]));
container.RegisterSingle<IXmlSource>(() => new FileXmlSource(absoluteFileName));
container.Register<IReservedAttributeNameProvider>(() => new ReservedAttributeNameProvider(new string[0]), Lifestyle.Singleton);
container.Register<IXmlSource>(() => new FileXmlSource(absoluteFileName), Lifestyle.Singleton);

// Register the sitemap node providers
container.RegisterSingle<XmlSiteMapNodeProvider>(() => container.GetInstance<XmlSiteMapNodeProviderFactory>()
.Create(container.GetInstance<IXmlSource>()));
container.RegisterSingle<ReflectionSiteMapNodeProvider>(() => container.GetInstance<ReflectionSiteMapNodeProviderFactory>()
.Create(includeAssembliesForScan));
container.Register<XmlSiteMapNodeProvider>(() => container.GetInstance<XmlSiteMapNodeProviderFactory>()
.Create(container.GetInstance<IXmlSource>()),
Lifestyle.Singleton);
container.Register<ReflectionSiteMapNodeProvider>(() => container.GetInstance<ReflectionSiteMapNodeProviderFactory>()
.Create(includeAssembliesForScan),
Lifestyle.Singleton);

// Register the sitemap builders
container.RegisterSingle<ISiteMapBuilder>(() => container.GetInstance<SiteMapBuilderFactory>()
.Create(new CompositeSiteMapNodeProvider(container.GetInstance<XmlSiteMapNodeProvider>(), container.GetInstance<ReflectionSiteMapNodeProvider>())));
container.Register<ISiteMapBuilder>(() => container.GetInstance<SiteMapBuilderFactory>()
.Create(new CompositeSiteMapNodeProvider(container.GetInstance<XmlSiteMapNodeProvider>(), container.GetInstance<ReflectionSiteMapNodeProvider>())),
Lifestyle.Singleton);

container.RegisterAll<ISiteMapBuilderSet>(
container.RegisterCollection<ISiteMapBuilderSet>(
ResolveISiteMapBuilderSets(container, securityTrimmingEnabled, enableLocalization, visibilityAffectsDescendants, useTitleIfDescriptionNotProvided));
container.RegisterSingle<ISiteMapBuilderSetStrategy>(() => new SiteMapBuilderSetStrategy(container.GetAllInstances<ISiteMapBuilderSet>().ToArray()));
container.Register<ISiteMapBuilderSetStrategy>(() => new SiteMapBuilderSetStrategy(container.GetAllInstances<ISiteMapBuilderSet>().ToArray()),
Lifestyle.Singleton);
}

private static IEnumerable<ISiteMapBuilderSet> ResolveISiteMapBuilderSets(
Expand All @@ -149,8 +157,11 @@ private static IEnumerable<ISiteMapBuilderSet> ResolveISiteMapBuilderSets(
container.GetInstance<ISiteMapBuilder>(),
container.GetInstance<ICacheDetails>());
}
}

private static void AllowToResolveArraysAndLists(Container container)
public static class ContainerExtensions
{
public static void AllowToResolveArraysAndLists(this Container container)
{
container.ResolveUnregisteredType += (sender, e) =>
{
Expand Down Expand Up @@ -180,5 +191,101 @@ private static void RegisterArrayResolver(UnregisteredTypeEventArgs e, Container
var arrayExpression = Expression.Call(arrayMethod, enumerableExpression);
e.Register(arrayExpression);
}

// Extension methods for cross-version support of Simple Injector 2.x and 3.x.

// This will succeed on 2.x and will be bypassed on 3.x
public static void RegisterCollection(this Container container, Type serviceType, IEnumerable<Type> serviceTypes)
{
// container.RegisterAll(serviceType, serviceTypes);
var method = container.GetType().GetMethod(
"RegisterAll",
BindingFlags.Instance | BindingFlags.Public,
null,
new Type[] { typeof(Type), typeof(IEnumerable<Type>) },
null);

if (method != null)
{
method.Invoke(container, new object[] { serviceType, serviceTypes });
}
}

// This will succeed on 2.x and will be bypassed on 3.x
public static void RegisterCollection<TService>(this Container container, IEnumerable<TService> containerUncontrolledCollection) where TService : class
{
// container.RegisterAll(containerUncontrolledCollection);
var method = container.GetType().GetMethods()
.Where(mi => mi.Name == "RegisterAll")
.Select(mi => new { M = mi, P = mi.GetParameters(), A = mi.GetGenericArguments() })
.Where(x => x.A.Length == 1
&& x.P.Length == 1
&& x.P[0].Name == "collection")
.Select(x => x.M)
.FirstOrDefault();

if (method != null)
{
var genericMethod = method.MakeGenericMethod(new Type[] { typeof(TService) });
genericMethod.Invoke(container, new object[] { containerUncontrolledCollection });
}
}

// This will work on both 2.x and 3.x. On 2.x this will override the default implementation because it is in the same namespace as the caller.
public static void RegisterOpenGeneric(this Container container, Type openGenericServiceType, Type openGenericImplementation, Lifestyle lifestyle)
{
bool isSimpleInjector2 = false;
var openGenericExtensionType = container.GetType().Assembly.GetType("SimpleInjector.Extensions.OpenGenericRegistrationExtensions");
if (openGenericExtensionType != null)
{
// Attempt to find the method to invoke
// OpenGenericRegistrationExtensions.RegisterOpenGeneric(container, openGenericServiceType, openGenericImplementation, lifestyle);
var method = openGenericExtensionType.GetMethod(
"RegisterOpenGeneric",
BindingFlags.Static | BindingFlags.Public,
null,
new Type[] { typeof(Container), typeof(Type), typeof(Type), typeof(Lifestyle) },
null);

if (method != null && !Attribute.IsDefined(method, typeof(ObsoleteAttribute)))
{
// This is SimpleInjector 2 - Invoke the method
isSimpleInjector2 = true;
method.Invoke(null, new object[] { container, openGenericServiceType, openGenericImplementation, lifestyle });
}
}

if (!isSimpleInjector2)
{
container.Register(openGenericServiceType, openGenericImplementation, lifestyle);
}
}

public static void RegisterMvcController<TService>(this Container container) where TService: IController
{
var registration = Lifestyle.Transient.CreateRegistration(typeof(IController), typeof(TService), container);
container.AddRegistration(typeof(TService), registration);

// This will run if using SimpleInjector 3.x
Type diagnosticTypeType = container.GetType().Assembly.GetType("SimpleInjector.Diagnostics.DiagnosticType");
if (diagnosticTypeType != null)
{
var method = registration.GetType().GetMethod(
"SuppressDiagnosticWarning",
BindingFlags.Instance | BindingFlags.Public,
null,
new Type[] { diagnosticTypeType, typeof(string) },
null);

if (method != null)
{
object disposableTransientComponent = Enum.Parse(diagnosticTypeType, "DisposableTransientComponent", true);

method.Invoke(registration, new object[] {
disposableTransientComponent,
"MVC's DefaultControllerFactory disposes the controller when the web request ends." });
}
}
}
}
}

0 comments on commit 328d30f

Please sign in to comment.