private static IContainer ScanGacForAutofacModulesAndCreateContainer(string appRootNamespace, Func<string, bool> assemblyFileNameMatchingPredicate) { using (new SPMonitoredScope("Dynamite - Bootstrapping dependency injection container " + appRootNamespace + " and scanning GAC for Modules.")) { var containerBuilderForDynamiteComponents = new ContainerBuilder(); var assemblyLocator = new GacAssemblyLocator(); // Don't just scan the GAC modules, also prepare the Dynamite core utils (by passing the params in ourselves). // I.E. each container gets its own DynamiteRegistrationModule components. var dynamiteModule = new AutofacDynamiteRegistrationModule(appRootNamespace); containerBuilderForDynamiteComponents.RegisterModule(dynamiteModule); var matchingAssemblies = assemblyLocator.GetAssemblies(new List<string> { AssemblyFolder }, assemblyFileNameMatchingPredicate); // Make sure we exclude all other GSoft.Dynamite DLLs (i.e. ignore other versions deployed to same GAC) // so that other AutofacDynamiteRegistrationModule instances don't get registered. var filteredMatchingAssemblies = matchingAssemblies.Where(x => !x.FullName.Contains("GSoft.Dynamite,")); // Now make sure all Dynamite component modules (i.e. all DLLs that start with GSoft.Dynamite.*) are registered BEFORE // any other modules. // This ensures that "client" modules will be able to override the Container registrations of GSoft.Dynamite.Components modules. var dynamiteComponentModuleAssemblies = filteredMatchingAssemblies.Where(assembly => assembly.FullName.StartsWith("GSoft.Dynamite.")); var allTheRest = filteredMatchingAssemblies.Where(assembly => !assembly.FullName.StartsWith("GSoft.Dynamite.")); // 1) Build the base container with only Dynamite-related components AutofacBackportScanningUtils.RegisterAssemblyModules(containerBuilderForDynamiteComponents, dynamiteComponentModuleAssemblies.ToArray()); var container = containerBuilderForDynamiteComponents.Build(); var logger = container.Resolve<ILogger>(); string dynamiteAssemblyNameEnumeration = string.Empty; dynamiteComponentModuleAssemblies.Cast<Assembly>().ToList().ForEach(a => dynamiteAssemblyNameEnumeration += a.FullName + ", "); logger.Info("Dependency injection module registration for container " + appRootNamespace + ". The following Dynamite component assemblies were scanned and any Autofac Module within was registered. The order of registrations was: " + dynamiteAssemblyNameEnumeration); // 2) Extend the original registrations with any remaining AddOns' registrations var containerBuilderForAddOns = new ContainerBuilder(); AutofacBackportScanningUtils.RegisterAssemblyModules(containerBuilderForAddOns, allTheRest.ToArray()); containerBuilderForAddOns.Update(container); string addOnAssemblyNameEnumeration = string.Empty; allTheRest.Cast<Assembly>().ToList().ForEach(a => addOnAssemblyNameEnumeration += a.FullName + ", "); logger.Info("Dependency injection module registration for container " + appRootNamespace + ". The following Add-On component assemblies (i.e. extensions to the core Dynamite components) were scanned and any Autofac Module within was registered. The order of registrations was: " + addOnAssemblyNameEnumeration); // Log the full component registry for easy debugging through ULS string componentRegistryAsString = string.Empty; var regAndServices = container.ComponentRegistry.Registrations.SelectMany(r => r.Services.OfType<IServiceWithType>(), (r, s) => new { r, s }); regAndServices.ToList().ForEach(regAndService => componentRegistryAsString += "[" + regAndService.s.ServiceType.FullName + "->" + regAndService.r.Activator.LimitType.FullName + "], "); logger.Info("Autofac component registry details for container " + appRootNamespace + ": " + componentRegistryAsString); return container; } }
private static IContainer ScanGacForAutofacModulesAndCreateContainer(string appRootNamespace, Func<string, bool> assemblyFileNameMatchingPredicate) { using (new SPMonitoredScope("Dynamite - Bootstrapping dependency injection container " + appRootNamespace + " and scanning GAC for Modules.")) { var containerBuilder = new ContainerBuilder(); var assemblyLocator = new GacAssemblyLocator(); // Don't just scan the GAC modules, also prepare the Dynamite core utils (by passing the params in ourselves). // I.E. each container gets its own DynamiteRegistrationModule components. var dynamiteModule = new AutofacDynamiteRegistrationModule(appRootNamespace); containerBuilder.RegisterModule(dynamiteModule); var matchingAssemblies = assemblyLocator.GetAssemblies(new List<string> { AssemblyFolder }, assemblyFileNameMatchingPredicate); // Make sure we exclude all other GSoft.Dynamite DLLs (i.e. ignore other versions deployed to same GAC) // so that other AutofacDynamiteRegistrationModule instances don't get registered. var filteredMatchingAssemblies = matchingAssemblies.Where(x => !x.FullName.Contains("GSoft.Dynamite,")); AutofacBackportScanningUtils.RegisterAssemblyModules(containerBuilder, filteredMatchingAssemblies.ToArray()); return containerBuilder.Build(); } }
private void EnsureServiceLocatorAccessorForCurrentSiteContext(SPSite site) { if (locatorAccessor == null) { lock (lockObject) { if (this.locatorAccessor == null) { // 1) Scan the GAC for any DLL matching the *.ServiceLocator.DLL pattern var assemblyScanner = new GacAssemblyLocator(); var matchingAssemblies = assemblyScanner.GetAssemblies(new List<string>() { "GAC_MSIL" }, assemblyFileName => assemblyFileName.Contains(".ServiceLocator")); Type accessorType = null; if (matchingAssemblies.Any()) { var serviceLocatorAssembly = matchingAssemblies[0]; if (matchingAssemblies.Count > 1) { // 2) If more than one service locator is found, gotta use the contextual SPSite object // and extract the preferred service locator setting from its property bag. if (site != null) { using (var rootWeb = site.OpenWeb()) { string serviceLocatorAssemlyName = rootWeb.Properties[KeyServiceLocatorAssemblyName]; serviceLocatorAssembly = matchingAssemblies.FirstOrDefault(assembly => assembly.FullName.Contains(serviceLocatorAssemlyName)); } } else { throw new ArgumentNullException("site"); } } if (serviceLocatorAssembly != null) { // Only one matching assembly, find its accessor class accessorType = this.FindServiceLocatorAccessorType(serviceLocatorAssembly); } else { throw new InvalidOperationException("Failed to find an assembly matching the *.ServiceLocator.DLL pattern to provide a service locator."); } } if (accessorType != null) { // 3) Create the accessor instance this.locatorAccessor = (ISharePointServiceLocatorAccessor)Activator.CreateInstance(accessorType); } else { throw new InvalidOperationException("Failed to find implementation of ISharePointServiceLocatorAccessor for AddOnProvidedServiceLocator. Your *.ServiceLocator.DLL assembly should expose its static container through that interface."); } } } } }
/// <summary> /// Triggers ServiceLocator bootstrapping (scans the GAC for assemblies with a name /// that matches *.ServiceLocator.DLL, by convention). /// </summary> /// <param name="web">The context's SPWeb. Keep null if none available.</param> /// <param name="site">The context's SPSite. Keep null if none available.</param> /// <param name="webApplication">The context's SPWebApplication. Keep null if none available.</param> /// <param name="farm">The context's SPFarm. Keep null if none available.</param> private void EnsureServiceLocatorAccessor(SPWeb web, SPSite site, SPWebApplication webApplication, SPFarm farm) { if (locatorAccessor == null) { lock (lockObject) { if (this.locatorAccessor == null) { try { // 1) Scan the GAC for any DLL matching the *.ServiceLocator.DLL pattern var assemblyScanner = new GacAssemblyLocator(); var matchingAssemblies = assemblyScanner.GetAssemblies(new List<string>() { "GAC_MSIL" }, assemblyFileName => assemblyFileName.Contains(".ServiceLocator")); Assembly serviceLocatorAssembly = null; Type accessorType = null; if (matchingAssemblies.Any()) { if (matchingAssemblies.Count > 1) { // 2) If more than one service locator is found, we must disambiguate. We have to use the // contextual SPWeb, SPSite, SPWebApp or SPFarm objects and extract the preferred service // locator assembly name setting from their property bag. // The SPWeb's property bag is inspected first, if available, then the SPSite's RootWeb property // bag, then the SPWebApp's, then the SPFarm's property bag as a last resort. string contextObjectWhereDiscriminatorWasFound; string serviceLocatorAssemblyNameDiscriminator = this.FindServiceLocatorAccessorTypeNameFromMostSpecificPropertyBag(web, site, webApplication, farm, out contextObjectWhereDiscriminatorWasFound); string allServiceLocatorAssemblyNames = string.Join(";", matchingAssemblies.Select(locatorAssembly => locatorAssembly.FullName).ToArray()); string basicDisambiguationErrorMessage = string.Format( CultureInfo.InvariantCulture, "Failed to disambiguate between all DLLs in the GAC that match the *.ServiceLocator.DLL filename pattern. All matching assemblies in GAC: {0}.", allServiceLocatorAssemblyNames); if (!string.IsNullOrEmpty(serviceLocatorAssemblyNameDiscriminator)) { // We found a ServiceLocator assembly name in one of the context's Property Bags. serviceLocatorAssembly = matchingAssemblies.FirstOrDefault(assembly => assembly.FullName.Contains(serviceLocatorAssemblyNameDiscriminator)); if (serviceLocatorAssembly == null) { throw new InvalidOperationException(basicDisambiguationErrorMessage + " The discriminator found in one of the context's Property Bags (value=" + serviceLocatorAssemblyNameDiscriminator + ", property bag location=" + contextObjectWhereDiscriminatorWasFound + ") did not match either of the " + matchingAssemblies.Count + " ServiceLocator DLLs available in GAC. The discriminator value should match one of the DLLs so that we can determine which to use."); } } else { // We failed to find a disambiguator setting in all of the context's Property Bags throw new InvalidOperationException(basicDisambiguationErrorMessage + " You cannot begin injection from the root application container if more that one ServiceLocator assembly exists in the GAC." + " You must begin injection with one of the following methods on your ISharePointServiceLocator: BeginLifetimeScope(SPFeature) or" + " BeginLifetimeScope(SPWeb) or BeginLifetimeScope(SPSite) or BeginLifetimeScope(SPWebApplication) or BeginLifetimeScope(SPFarm)," + " depending on your context. IMPORTANT: The property bags on the context' SPWeb, SPSite, SPWebApplication and SPFarm will be inspected" + " (in that order) to find a value for the key '" + KeyServiceLocatorAssemblyName + "'. This discriminator value will indicate to Dynamite's" + " AddOnProvidedServiceLocator which concrete add-on's ServiceLocator DLL to use in the current context."); } } else { // Only one ServiceLocator DLL found in GAC. There is no ambiguity: use this locator. serviceLocatorAssembly = matchingAssemblies[0]; } if (serviceLocatorAssembly != null) { // At this point we figured out the right matching assembly: find its accessor class within its types accessorType = this.FindServiceLocatorAccessorType(serviceLocatorAssembly); } } else { // Not even one DLL in GAC matches the *.ServiceLocator.DLL pattern throw new InvalidOperationException("Failed to find any assembly in the GAC that matches the *.ServiceLocator.DLL pattern."); } if (accessorType != null) { // 3) Create the accessor instance this.locatorAccessor = (ISharePointServiceLocatorAccessor)Activator.CreateInstance(accessorType); } else { throw new InvalidOperationException("Failed to find implementation of ISharePointServiceLocatorAccessor for AddOnProvidedServiceLocator. Your ServiceLocator assembly (" + serviceLocatorAssembly.FullName + ") should expose its static container through that interface."); } } catch (InvalidOperationException exception) { var logger = new TraceLogger("GSoft.Dynamite", "GSoft.Dynamite", false); logger.Error( "AddOnProvidedServiceLocator Initialization Error - An error occured while trying to find a DLL matching the pattern *ServiceLocator.dll in the GAC. The FallbackServiceLocator will be used instead as a last resort (no AddOn registration module will be registered). Exception: {0}", exception.ToString()); // Either no assembly in the GAC matches the pattern *.ServiceLocator.DLL pattern, // or in the matching assembly that was found, no class implements ISharePointServiceLocatorAccessor. // In this case, use our default all-available-Dynamite-modules-only service locator this.locatorAccessor = new FallbackServiceLocator(); } } } } }