Having fun with code
  • Blog
  • Favorites
    • Favorite Books
    • Favorite Libraries
    • Favorite Tools
  • Utilities
    • SP 2010 Colors
  • Contact
  • Home /
  • .NET /
  • Using Autofac in SharePoint 2010

Using Autofac in SharePoint 2010

February 1, 2012 / Matt C. / .NET, SharePoint

Up till now in my SharePoint 2010 projects, I’ve been using the very nice SharePoint Service Locator implementation, from the patterns & practices group. This has been really useful, and works great. If you’re not familiar with the service locator pattern, you can read up on it here. Using this pattern, it’s easy to build a lightweight common library that you pass out to your team (or as is often the case “teams”) of developers without them having to mess around with the implementation of every interface. After all, the implementation of the interfaces are registered and deployed on the SharePoint server using a feature, and that’s all developers need to know. In many instances, developers might even develop for SharePoint without even having SharePoint installed. The service locator allows you to build an API that often looks like this in my projects:

  • AppContext.Repositories.ContactsRepository.GetContact( … ), UpdateContact( … )
  • AppContext.Services.RegisterUser( … ), PurchaseProduct( … )  –> complex step that might work with multiple repositories and talk to AD, and the user profile manager
  • AppContext.Data.Call<storedprocedure>( … ) –> allow a direct call to a database, which happens sometimes in a custom service application

Why Autofac?

While Autofac provides service locator functionality with it’s ILifetimeScope and IContainer implementations, it also provides dependency injection of constructor parameters, and properties, and a fluent interface that allows late-bound resolution of injected parameters, and much more.  Other containers you could look at are: StructureMap (another favorite of mine), Unity, Ninject, Spring.NET, Castle Windsor. Based on benchmarks though – see here and here – it seems that Autofac is one of the better performing containers. Another thing that is useful about using Autofac is the “InstancePerLifetimeScope()” registration extension that will automatically instantiate the registered type for every ASP.NET request, and properly dispose of the object at the end of the ASP.NET request, which makes it an ideal candidate to minimize round-trip connections to a database for example, or other persistent storage.

Autofac vs. SharePoint Service Locator

Whereas the SharePoint Service Locator stores it’s mapping of interfaces to their implementations as persisted objects in the database, Autofac wires things up in ASP.NET during the Application_Start event. Autofac also requires some additional configuration in the web.config file, so already, Autofac is going to demand a little more of a setup process.

The other core need is to allow developers to wire up additional mappings in any new features they develop, and it would be nice for there not to be a need to always modify the web.config file everytime a new feature with new mappings is developed. So storing mappings in SharePoint might be a good idea.

Wiring Autofac up

The following code is a Farm-scoped Feature EventReceiver that wires up Autofac on all the web front-ends within the farm. The code takes care of registering Autofac and unregistering Autofac. It primarily does 2 things:

  • Makes all configuration changes to the web.config file necessary to support Autofac
  • Alters the global.asax file on all web front-ends

IISRESET is required after installing the feature

Autofac integration feature
  1. [Guid("9578f389-4e0b-40ef-9e8e-5358003e64d4")]
  2. public class AutofacIntegrationEventReceiver : SPFeatureReceiver
  3. {
  4.     public override void FeatureActivated(SPFeatureReceiverProperties properties)
  5.     {
  6.         // generally equivalent to: SPFarm.Local.Services.GetValue<SPWebService>()
  7.         var webService = properties.Feature.Parent as SPWebService;
  8.         if (webService == null)
  9.         {
  10.             throw new ArgumentNullException("properties.Feature.Parent");
  11.         }
  12.  
  13.         // let's register an autofac module (saves the config in the farm properties)
  14.         SPContainerBuilder.RegisterModule(typeof(Playground.PlaygroundModule2).AssemblyQualifiedName, null, null, true);
  15.  
  16.         // let's make the necessary changes to register autofac in web.config and global.asax
  17.         var globalAsaxFiles = new List<string>();
  18.         var zones = Enum.GetValues(typeof (SPUrlZone)).Cast<SPUrlZone>().ToArray();
  19.         foreach (var webApp in webService.WebApplications)
  20.         {
  21.             if (webApp.IsAdministrationWebApplication)
  22.                 continue; // don't mess with central admin 🙂
  23.  
  24.             // assuming every other web application "wants" to use Autofac
  25.             // (this may not be the case, change logic here, or scope the feature differently)
  26.  
  27.             foreach (var entry in _autofacConfigEntries)
  28.             {
  29.                 webApp.WebConfigModifications.Add(entry.Prepare());
  30.             }
  31.  
  32.             webApp.WebService.Update();
  33.             webApp.WebService.ApplyWebConfigModifications();
  34.  
  35.             var paths =
  36.                 zones.Select(z => Path.Combine(webApp.GetIisSettingsWithFallback(z).Path.ToString(), "global.asax"))
  37.                     .Distinct().Where(File.Exists).ToArray();
  38.             globalAsaxFiles.AddRange(paths);
  39.         }
  40.  
  41.         // Now replace the global.asax file(s) - I dare you!!
  42.         try
  43.         {
  44.             var asaxFileContents =
  45.                 string.Format(
  46.                     @"<%@ Assembly Name=""Microsoft.SharePoint""%><%@ Assembly Name=""{0}""%><%@ Application Language=""C#"" Inherits=""{1}"" %>",
  47.                     typeof(IContainerProviderAccessor).Assembly.FullName,
  48.                     typeof(Autofac.Integration.SharePoint.GlobalApplication).AssemblyQualifiedName);
  49.             foreach (var asax in globalAsaxFiles)
  50.             {
  51.                 File.WriteAllText(asax, asaxFileContents, Encoding.UTF8);
  52.             }
  53.         }
  54.         catch
  55.         {
  56.             // Modify the global.asax files manually (this shouldn't happen)
  57.         }
  58.     }
  59.  
  60.     public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
  61.     {
  62.         var webService = properties.Feature.Parent as SPWebService;
  63.         if (webService == null)
  64.         {
  65.             // allow de-activation here
  66.             return;
  67.         }
  68.  
  69.         var globalAsaxFiles = new List<string>();
  70.         var zones = Enum.GetValues(typeof (SPUrlZone)).Cast<SPUrlZone>().ToArray();
  71.         foreach (var webApplication in webService.WebApplications)
  72.         {
  73.             var modsCollection = webApplication.WebConfigModifications;
  74.  
  75.             for (var i = modsCollection.Count - 1; i > -1; i--)
  76.             {
  77.                 if (modsCollection[i].Owner == ConfigModsOwnerName)
  78.                 {
  79.                     // Remove it and save the change to the configuration database  
  80.                     modsCollection.Remove(modsCollection[i]);
  81.                 }
  82.             }
  83.             webApplication.Update();
  84.  
  85.             // Reapply all the configuration modifications
  86.             webApplication.WebService.Update();
  87.             webApplication.WebService.ApplyWebConfigModifications();
  88.  
  89.             var paths =
  90.                 zones.Select(z => Path.Combine(webApplication.GetIisSettingsWithFallback(z).Path.ToString(), "global.asax"))
  91.                     .Distinct().Where(File.Exists).ToArray();
  92.             globalAsaxFiles.AddRange(paths);
  93.         }
  94.  
  95.         // Now replace the global.asax file(s)
  96.         try
  97.         {
  98.             var asaxFileContents =
  99.                 @"<%@ Assembly Name=""Microsoft.SharePoint""%><%@ Application Language=""C#"" Inherits=""Microsoft.SharePoint.ApplicationRuntime.SPHttpApplication"" %>";
  100.             foreach (var asax in globalAsaxFiles)
  101.             {
  102.                 File.WriteAllText(asax, asaxFileContents, Encoding.UTF8);
  103.             }
  104.         }
  105.         catch
  106.         {
  107.             // Modify the global.asax files manually (this shouldn't happen)
  108.         }
  109.     }
  110.  
  111.     #region Web.Config Modification Entries
  112.     private const string ConfigModsOwnerName = "Autofac Integration For SharePoint";
  113.     private readonly WebConfigEntry[] _autofacConfigEntries =
  114.         {
  115.             // configSections entry
  116.             new WebConfigEntry(
  117.                 "section[@name='autofac']"
  118.                 ,"configuration/configSections"
  119.                 ,"<section name=\"autofac\" type=\"" + typeof(Autofac.Configuration.SectionHandler).AssemblyQualifiedName + "\"/>"
  120.                 ,SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode
  121.                 ,false)  
  122.  
  123.             // autofac entry
  124.             ,new WebConfigEntry(
  125.                 "autofac"
  126.                 ,"configuration"
  127.                 ,"<autofac/>"
  128.                 ,SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode
  129.                 ,false)   
  130.  
  131.             // autofac modules entry
  132.             ,new WebConfigEntry(
  133.                 "modules"
  134.                 ,"configuration/autofac"
  135.                 ,"<modules/>"
  136.                 ,SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode
  137.                 ,false)
  138.             // This is just a sample module
  139.             ,new WebConfigEntry(
  140.                 "module[@type='" + typeof(Playground.PlaygroundModule).AssemblyQualifiedName + "']"
  141.                 ,"configuration/autofac/modules"
  142.                 ,"<module type=\"" + typeof(Playground.PlaygroundModule).AssemblyQualifiedName + "\"/>"
  143.                 ,SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode
  144.                 , false)
  145.  
  146.             // autofac httpModules entries
  147.             ,new WebConfigEntry(
  148.                 "add[@name='ContainerDisposal']"
  149.                 ,"configuration/system.web/httpModules"
  150.                 ,"<add name=\"ContainerDisposal\" type=\"" + typeof(ContainerDisposalModule).AssemblyQualifiedName + "\" />"
  151.                 ,SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode
  152.                 ,false)
  153.             ,new WebConfigEntry(
  154.                 "add[@name='PropertyInjection']"
  155.                 ,"configuration/system.web/httpModules"
  156.                 ,"<add name=\"PropertyInjection\" type=\"" + typeof(PropertyInjectionModule).AssemblyQualifiedName + "\" />"
  157.                 ,SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode
  158.                 ,false)
  159.             ,new WebConfigEntry(
  160.                 "add[@name='AttributeInjection']"
  161.                 ,"configuration/system.web/httpModules"
  162.                 ,"<add name=\"AttributeInjection\" type=\"" + typeof(AttributedInjectionModule).AssemblyQualifiedName + "\" />"
  163.                 ,SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode
  164.                 ,false)
  165.                 
  166.             // autofac iis7 modules entries
  167.             ,new WebConfigEntry(
  168.                 "add[@name='ContainerDisposal']"
  169.                 ,"configuration/system.webServer/modules"
  170.                 ,"<add name=\"ContainerDisposal\" type=\"" + typeof(ContainerDisposalModule).AssemblyQualifiedName + "\" preCondition=\"managedHandler\" />"
  171.                 ,SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode
  172.                 ,false)
  173.             ,new WebConfigEntry(
  174.                 "add[@name='PropertyInjection']"
  175.                 ,"configuration/system.webServer/modules"
  176.                 ,"<add name=\"PropertyInjection\" type=\"" + typeof(PropertyInjectionModule).AssemblyQualifiedName + "\" preCondition=\"managedHandler\" />"
  177.                 ,SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode
  178.                 ,false)
  179.             ,new WebConfigEntry(
  180.                 "add[@name='AttributeInjection']"
  181.                 ,"configuration/system.webServer/modules"
  182.                 ,"<add name=\"AttributeInjection\" type=\"" + typeof(AttributedInjectionModule).AssemblyQualifiedName + "\" preCondition=\"managedHandler\" />"
  183.                 ,SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode
  184.                 ,false)
  185.  
  186.             // autofac assemblies entries
  187.             ,new WebConfigEntry(
  188.                 "add[@assembly='" + typeof(Autofac.IContainer).Assembly.FullName + "']"
  189.                 ,"configuration/system.web/compilation/assemblies"
  190.                 ,"<add assembly=\"" + typeof(Autofac.IContainer).Assembly.FullName + "\" />"
  191.                 ,SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode
  192.                 ,false)
  193.             ,new WebConfigEntry(
  194.                 "add[@assembly='" + typeof(Autofac.Configuration.ComponentElement).Assembly.FullName + "']"
  195.                 ,"configuration/system.web/compilation/assemblies"
  196.                 ,"<add assembly=\"" + typeof(Autofac.Configuration.ComponentElement).Assembly.FullName + "\" />"
  197.                 ,SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode
  198.                 ,false)
  199.             ,new WebConfigEntry(
  200.                 "add[@assembly='" + typeof(IContainerProviderAccessor).Assembly.FullName + "']"
  201.                 ,"configuration/system.web/compilation/assemblies"
  202.                 ,"<add assembly=\"" + typeof(IContainerProviderAccessor).Assembly.FullName + "\" />"
  203.                 ,SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode
  204.                 ,false)
  205.                 
  206.             // add some safe control entries as well (assuming you'll be building some controls in Autofac.Integration.SharePoint)
  207.             ,new WebConfigEntry(
  208.                 "SafeControl[@Assembly='" + typeof(Autofac.Integration.SharePoint.GlobalApplication).Assembly.FullName + "']"
  209.                 ,"configuration/SharePoint/SafeControls"
  210.                 ,"<SafeControl Assembly=\"" + typeof(Autofac.Integration.SharePoint.GlobalApplication).Assembly.FullName + "\" Namespace=\"Autofac.Integration.SharePoint\" TypeName=\"*\" Safe=\"True\" SafeAgainstScript=\"False\" />"
  211.                 ,SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode
  212.                 ,false)
  213.  
  214.         };
  215.  
  216.     /// <summary>
  217.     /// Container to hold info about our modifications to the web.config.
  218.     /// </summary>
  219.     public class WebConfigEntry
  220.     {
  221.         public string Name;
  222.         public string XPath;
  223.         public string Value;
  224.         public SPWebConfigModification.SPWebConfigModificationType ModificationType;
  225.         public bool KeepOnDeactivate;
  226.  
  227.         public WebConfigEntry(string name, string xPath, string value,
  228.             SPWebConfigModification.SPWebConfigModificationType modificationType, bool keepOnDeactivate)
  229.         {
  230.             Name = name;
  231.             XPath = xPath;
  232.             Value = value;
  233.             ModificationType = modificationType;
  234.             KeepOnDeactivate = keepOnDeactivate;
  235.         }
  236.  
  237.         public SPWebConfigModification Prepare()
  238.         {
  239.             var modification = new SPWebConfigModification(Name, XPath)
  240.             {
  241.                 Owner = ConfigModsOwnerName,
  242.                 Sequence = 0,
  243.                 Type = ModificationType,
  244.                 Value = Value
  245.             };
  246.             return modification;
  247.         }
  248.     }
  249.     #endregion
  250. }

After the event receiver installs Autofac … you’ll see the following summarized list of changes to the root web.config files on all front-end web applications:

web.config change summary
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <configuration>
  3.   <configSections>
  4.     <section name="autofac" type="Autofac.Configuration.SectionHandler, Autofac.Configuration, Version=2.5.2.830, Culture=neutral, PublicKeyToken=17863af14b0044da" />
  5.   </configSections>
  6.   <SharePoint>
  7.     <SafeControls>
  8.       <SafeControl Assembly="Autofac.Integration.SharePoint, Version=1.0.0.0, Culture=neutral, PublicKeyToken=3a3b1e988e6ba16f" Namespace="Autofac.Integration.SharePoint" TypeName="*" Safe="True" SafeAgainstScript="False" />
  9.     </SafeControls>
  10.   </SharePoint>
  11.   <system.web>
  12.     <httpModules>
  13.       <add name="AttributeInjection" type="Autofac.Integration.Web.Forms.AttributedInjectionModule, Autofac.Integration.Web, Version=2.5.2.830, Culture=neutral, PublicKeyToken=17863af14b0044da" />
  14.       <add name="ContainerDisposal" type="Autofac.Integration.Web.ContainerDisposalModule, Autofac.Integration.Web, Version=2.5.2.830, Culture=neutral, PublicKeyToken=17863af14b0044da" />
  15.       <add name="PropertyInjection" type="Autofac.Integration.Web.Forms.PropertyInjectionModule, Autofac.Integration.Web, Version=2.5.2.830, Culture=neutral, PublicKeyToken=17863af14b0044da" />
  16.     </httpModules>
  17.     <compilation batch="true" debug="true" optimizeCompilations="true">
  18.       <assemblies>
  19.         <add assembly="Autofac, Version=2.5.2.830, Culture=neutral, PublicKeyToken=17863af14b0044da" />
  20.         <add assembly="Autofac.Configuration, Version=2.5.2.830, Culture=neutral, PublicKeyToken=17863af14b0044da" />
  21.         <add assembly="Autofac.Integration.Web, Version=2.5.2.830, Culture=neutral, PublicKeyToken=17863af14b0044da" />
  22.       </assemblies>
  23.     </compilation>
  24. </system.web>
  25.   <system.webServer>
  26.     <modules runAllManagedModulesForAllRequests="true">
  27.       <add name="AttributeInjection" type="Autofac.Integration.Web.Forms.AttributedInjectionModule, Autofac.Integration.Web, Version=2.5.2.830, Culture=neutral, PublicKeyToken=17863af14b0044da" preCondition="managedHandler" />
  28.       <add name="ContainerDisposal" type="Autofac.Integration.Web.ContainerDisposalModule, Autofac.Integration.Web, Version=2.5.2.830, Culture=neutral, PublicKeyToken=17863af14b0044da" preCondition="managedHandler" />
  29.       <add name="PropertyInjection" type="Autofac.Integration.Web.Forms.PropertyInjectionModule, Autofac.Integration.Web, Version=2.5.2.830, Culture=neutral, PublicKeyToken=17863af14b0044da" preCondition="managedHandler" />
  30.     </modules>
  31.   </system.webServer>
  32.   <autofac>
  33.     <modules>
  34.       <module type="Autofac.Integration.SharePoint.Playground.PlaygroundModule, Autofac.Integration.SharePoint, Version=1.0.0.0, Culture=neutral, PublicKeyToken=3a3b1e988e6ba16f" />
  35.     </modules>
  36.   </autofac>
  37. </configuration>

You’ll notice that this implementation has the “modules” functionality already wired-up at the very end of the web.config file to add new modules (see here for more details). But this isn’t the only way you can add new modules. In the “Autofac Integration Code” above, I’ve added the ability to store module configuration in SharePoint (using a Farm property) that also gets added to the modules wired up during Application_Start.

The functions that developers can use in their feature event receivers to register (and unregister) Autofac modules into SharePoint are in the SPContainerBuilder class in the download, and have the following signatures:

public static void RegisterModule(string moduleType, IDictionary<string, string> properties, IDictionary<string, string> parameters, bool replaceIfExists){ … }
public static void RemoveModule(string moduleType){ … }
Developers integrating new features into SharePoint can leverage these two functions in their feature event receivers to add new Autofac mappings without modifying the web.config files going-forward. 
By modifying the global.asax file, Autofac fires during Application startup and calls an initialize method on a static service locator class. The initialization of the Autofac container looks like the following.
Initializing the container
  1. /// <summary>
  2. /// This method is available for testing, or to use the ServiceLocator capability outside of
  3. /// the SharePoint HttpContext (i.e.: console app, linqpad, powershell, etc...)
  4. /// </summary>
  5. /// <param name="configFile">Autofac configuration file</param>
  6. /// <param name="additionalBuild">Any additional build information desired (will override the web.config and farm properties)</param>
  7. public static void InitializeContainer(string configFile, Action<ContainerBuilder> additionalBuild)
  8. {
  9.     if (_initialized)
  10.         return;
  11.  
  12.     if (!string.IsNullOrEmpty(configFile) && !File.Exists(configFile))
  13.         throw new FileNotFoundException("The autofac configuration file could not be found.", configFile);
  14.  
  15.     var builder = new SPContainerBuilder();
  16.  
  17.     // register modules from config file
  18.     builder.RegisterModule(string.IsNullOrEmpty(configFile)
  19.                                ? new ConfigurationSettingsReader("autofac")
  20.                                : new ConfigurationSettingsReader("autofac", configFile));
  21.  
  22.     // register modules from SPFarm.Properties
  23.     var modules = SPContainerBuilder.GetFarmPropertyConfiguredModules();
  24.     foreach (var module in modules)
  25.         builder.RegisterModule(module);
  26.  
  27.     if (additionalBuild != null)
  28.         additionalBuild.Invoke(builder);
  29.  
  30.     _containerProvider = new SPContainerProvider(builder.Build());
  31.     _initialized = true;
  32. }

Using Autofac within Application Pages, Web Parts, User Controls, Event Receivers

Application pages and user controls can use the standard injection techniques that come with Autofac with ASP.NET (in the Autofac.Integration.Web assembly).
Property Injection Example
  1. [InjectProperties]
  2. public partial class Play : LayoutsPageBase, IPlaygroundView
  3. {
  4.     private PlaygroundPresenter _presenter;
  5.     public PlaygroundPresenterFactory PresenterFactory { get; set; }
  6.  
  7.     // these are here just to test property injection
  8.     public ILogger Logger { get; set; }
  9.     public IPlayInterface PlayInterface { get; set; }
  10.  
  11.     protected void Page_Load(object sender, EventArgs e)
  12.     {
  13.         _presenter = PresenterFactory(this);
  14.     }
In SharePoint, there are various scenarios that need to be supported. The following is a non-comprehensive list, along with various usages that support each.
Presenter/Service Registration
  1. protected override void Load(ContainerBuilder builder)
  2. {
  3.     // presenters and views
  4.     //builder.RegisterType<UlsLogger>().AsImplementedInterfaces().SingleInstance(); // logger singleton
  5.     builder.RegisterType<UlsLogger>().As<ILogger>().WithParameter("categoryName", "Autofac Logger").SingleInstance(); // logger singleton
  6.     builder.RegisterType<PlaygroundPresenter>().AsSelf().InstancePerDependency();
  7.     builder.RegisterGeneratedFactory<PlaygroundPresenterFactory>();
  8. }
 
InstancePerLifetimeScopes
  1. protected override void Load(ContainerBuilder builder)
  2. {
  3.     // InstancePerLifetimeScope implementation
  4.     builder.RegisterType<PlayInterface>().As<IPlayInterface>().InstancePerLifetimeScope();
  5. }
 
Service Locator example
  1. // old-school detection:
  2. var cpa = (IContainerProviderAccessor) HttpContext.Current.ApplicationInstance;
  3. IContainerProvider cp = cpa.ContainerProvider;
  4. _logger = cp.RequestLifetime.Resolve<ILogger>();
  5.  
  6. // or, an easier way:
  7. this._logger = SPServiceLocator.GetRequestLifetime().Resolve<ILogger>();
 
Manual property injection
  1. SPServiceLocator.GetRequestLifetime().InjectProperties(this);
 
Elevated Privileges
  1. SPSecurity.RunWithElevatedPrivileges(delegate {
  2.     AnotherLogger = SPServiceLocator.GetRequestLifetime().Resolve<ILogger>();
  3.     if (AnotherLogger == null)
  4.     {
  5.         _view.ErrorMessage = "Elevated privileges was NOT successful";
  6.     } else {
  7.         _view.SuccessMessage = "Elevated privileges was successful";
  8.         AnotherLogger.Log(typeof (PlaygroundPresenter), _view.SuccessMessage);
  9.     }
  10. });
 
when HttpContext is null
  1. HttpContext context = HttpContext.Current;
  2. HttpContext.Current = null;
  3. try
  4. {
  5.     using (ILifetimeScope container = SPServiceLocator.NewDisposableLifetime())
  6.     {
  7.         var logger = container.Resolve<ILogger>();
  8.         ...
  9.     }
  10. }
  11. catch (Exception ex)
  12. {
  13.     _view.ErrorMessage = ex.Message;
  14. }
  15. HttpContext.Current = context;
 
In a background thread
  1.  
  2. public void TestInBackgroundThread()
  3. {
  4.     // page must be async for the following (which still hangs the page)
  5.     var bw = new BackgroundWorker {WorkerSupportsCancellation = false, WorkerReportsProgress = true};
  6.     bw.DoWork += BwDoWork;
  7.     bw.ProgressChanged += BwProgressChanged;
  8.     bw.RunWorkerCompleted += BwRunWorkerCompleted;
  9.     bw.RunWorkerAsync();
  10. }
  11.  
  12. private static void BwDoWork(object sender, DoWorkEventArgs e)
  13. {
  14.     ILifetimeScope container = null;
  15.     try
  16.     {
  17.         container = SPServiceLocator.NewDisposableLifetime("worker");
  18.         var bwLogger = container.Resolve<ILogger>();
  19.  
  20.         var worker = sender as BackgroundWorker;
  21.  
  22.         for (int i = 1; (i <= 10); i++)
  23.         {
  24.             // Perform a time consuming operation and report progress.
  25.             Thread.Sleep(500);
  26.             if (worker != null)
  27.                 worker.ReportProgress((i * 10));
  28.             bwLogger.Log(typeof(PlaygroundPresenter), string.Format("bw worker progress: {0}%", (i * 10)));
  29.             // watch this in ULS
  30.         }
  31.  
  32.         e.Result = "Super, background worker has completed";
  33.     }
  34.     finally
  35.     {
  36.         if (container != null)
  37.             container.Dispose();
  38.     }
  39. }

Using Autofac on the Server

You can reference and override the registrations from a console app, powershell, and/or Linqpad, and as long as you are on the server, access service implementations.

image

General Comments

If you’re interested in this code, go ahead and download the sample attached to this post. I’ve included the feature and feature event receiver project, and a library project which has SPContainerBuilder, SPServiceLocator, SPContainerProvider classes and more that help with managing Autofac capabilities.

BTW: I coded all this in 1 day, as a prototype, so I can’t promise it’s 100% full-proof, but it does work in my use-cases. Do download the code and play with it, and if you decide to improve this, let me know. Or take it into a new direction all-together, that’s fine too Smile.

Download Code and Files

Thanks for reading as always.

 

.net, autofac, di, ioc, sharepoint

5 comments on “Using Autofac in SharePoint 2010”

  1. Use Autofac with SharePoint | jmecwel says:
    October 7, 2013 at 7:41 am

    […] ways, you could explore to use Autofac with SharePoint: • Deployment with a farm feature, see this site for more details. • Add a global.asax file to your SP solution. This is the asp.net approach, not […]

  2. Autofac SharePoint 2010 integration | thoughts on technology says:
    June 20, 2013 at 2:27 pm

    […] that integrated Autofac into his SharePoint 2010 environment. I really want to encourage you to read his post, as he gives you a good insight in the pains that led him to using autofac, and also contains links […]

  3. denis says:
    June 20, 2012 at 5:29 am

    does autofac injects in OWSTIMER ?

    • Matt C. says:
      June 20, 2012 at 9:43 am

      Autofac wouldn’t inject in code executed within the OWSTIMER. You would need to initialize an ILifetimeScope, and use the service locator technique ( .Resolve(…) ) for that.

  4. Dew Drop – February 2, 2012 (#1,257) | Alvin Ashcraft's Morning Dew says:
    February 2, 2012 at 8:56 am

    […] Using Autofac in SharePoint 2010 (Matt Cowan) […]

Categories

  • .NET (20)
  • ASP.NET MVC (4)
  • JAMstack (2)
    • Headless CMS (2)
  • Miscellaneous (2)
  • Python (1)
  • REST (3)
  • SharePoint (8)
  • WordPress (1)

Tags

.net ado.net autofac binding C# chrome code generation command line console application csv dapper di entity framework integration ioc job scheduling engine json jsv learning llblgen load balancing micro-orm mycorp odata orm people editor people picker picker controls picker dialog plugins pmp python Quartz.NET rest saf service application servicestack sharepoint smo soap sql sqlalchemy tornado web server validation web api

Archives

  • May 2020 (2)
  • November 2013 (1)
  • June 2013 (1)
  • May 2013 (1)
  • March 2013 (1)
  • December 2012 (1)
  • November 2012 (1)
  • October 2012 (3)
  • September 2012 (2)
  • June 2012 (2)
  • May 2012 (1)
  • April 2012 (1)
  • February 2012 (2)
  • January 2012 (1)
  • December 2011 (2)
  • September 2011 (2)
(c) 2013 Having fun with code - "FunCoding" theme designed by mattjcowan using the Theme Blvd framework