/// <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 (this.locatorAccessor == null) { lock (this.lockObject) { if (this.locatorAccessor == null) { try { // 1) Scan the GAC for any DLL matching the *.ServiceLocator.DLL pattern var matchingAssemblies = GacAssemblyLocator.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 = 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 discriminator 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."); } } if (serviceLocatorAssembly != null) { // Only one matching assembly, find its accessor class accessorType = FindServiceLocatorAccessorType(serviceLocatorAssembly); } 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 = 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(); } } } } }
/// <summary> /// Adds the locator accessor to the available accessors. /// If all parameters are null or an accessor already exists with that context, an exception is thrown. /// </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> /// <param name="locatorAccessor">The SharePoint locator accessor we want to add.</param> private void AddLocatorAccessor(SPWeb web, SPSite site, SPWebApplication webApplication, SPFarm farm, ISharePointServiceLocatorAccessor locatorAccessor) { // Get the identifier that represents the most specific context. Guid? mostSpecificIdentifier = GetMostSpecificIdentifier(web, site, webApplication, farm); if (!mostSpecificIdentifier.HasValue) { throw new NotSupportedException("Unable to get the most specific identifier for the context. Make sure at lest one parameter is not null."); } if (this.GetLocatorAccessor(web, site, webApplication, farm) != null) { throw new NotSupportedException("Trying to add a SharePoint Locator Accessor for a context that is already added."); } // Add the accessor to the dictionary. this.locatorAccessors.Add(mostSpecificIdentifier.Value, locatorAccessor); }
/// <summary> /// Adds the locator accessor to the available accessors. /// If all parameters are null or an accessor already exists with that context, an exception is thrown. /// </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> /// <param name="locatorAccessor">The SharePoint locator accessor we want to add.</param> private void AddLocatorAccessor(SPWeb web, SPSite site, SPWebApplication webApplication, SPFarm farm, ISharePointServiceLocatorAccessor locatorAccessor) { // Get the identifier that represents the most specific context. Guid?mostSpecificIdentifier = GetMostSpecificIdentifier(web, site, webApplication, farm); if (!mostSpecificIdentifier.HasValue) { throw new NotSupportedException("Unable to get the most specific identifier for the context. Make sure at lest one parameter is not null."); } if (this.GetLocatorAccessor(web, site, webApplication, farm) != null) { throw new NotSupportedException("Trying to add a SharePoint Locator Accessor for a context that is already added."); } // Add the accessor to the dictionary. this.locatorAccessors.Add(mostSpecificIdentifier.Value, locatorAccessor); }
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(); } } } } }