|
| 1 | +using System; |
| 2 | +using Autofac; |
| 3 | +using Microsoft.Practices.EnterpriseLibrary.Common.Configuration; |
| 4 | +using Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ContainerModel; |
| 5 | + |
| 6 | +namespace Autofac.Extras.EnterpriseLibraryConfigurator |
| 7 | +{ |
| 8 | + /// <summary> |
| 9 | + /// <see cref="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ContainerModel.IContainerConfigurator"/> |
| 10 | + /// implementation for registering Enterprise Library dependencies into |
| 11 | + /// an Autofac container. |
| 12 | + /// </summary> |
| 13 | + /// <remarks> |
| 14 | + /// <para> |
| 15 | + /// Enterprise Library uses |
| 16 | + /// <see cref="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ContainerModel.IContainerConfigurator"/> |
| 17 | + /// implementations as a bridge between configuration sources |
| 18 | + /// (<see cref="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.IConfigurationSource"/>), |
| 19 | + /// type registration providers |
| 20 | + /// (<see cref="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ContainerModel.ITypeRegistrationsProvider"/>), |
| 21 | + /// and inversion of control containers. This implementation allows you to |
| 22 | + /// use Autofac as the container from which Enterprise Library services |
| 23 | + /// get resolved. |
| 24 | + /// </para> |
| 25 | + /// <para> |
| 26 | + /// Setup of a container via a configurator is done using the |
| 27 | + /// <see cref="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.EnterpriseLibraryContainer.ConfigureContainer(IContainerConfigurator,IConfigurationSource)"/> |
| 28 | + /// method. Using this configurator, registering Enterprise Library with |
| 29 | + /// Autofac looks like this: |
| 30 | + /// </para> |
| 31 | + /// <code lang="C#"> |
| 32 | + /// // Create the ContainerBuilder and register EntLib. |
| 33 | + /// var builder = new ContainerBuilder(); |
| 34 | + /// using (var configSource = ConfigurationSourceFactory.Create()) |
| 35 | + /// { |
| 36 | + /// var configurator = new AutofacContainerConfigurator(builder); |
| 37 | + /// EnterpriseLibraryContainer.ConfigureContainer(configurator, configSource); |
| 38 | + /// } |
| 39 | + /// |
| 40 | + /// // Register other services/dependencies, then set the |
| 41 | + /// // service locator. |
| 42 | + /// var container = builder.Build(); |
| 43 | + /// var autofacLocator = new AutofacServiceLocator(container); |
| 44 | + /// EnterpriseLibraryContainer.Current = autofacLocator; |
| 45 | + /// </code> |
| 46 | + /// <para> |
| 47 | + /// Note the use of <see cref="T:Autofac.Extras.CommonServiceLocator.AutofacServiceLocator"/> |
| 48 | + /// to set the Enterprise Library service locator. You need to do that so |
| 49 | + /// Enterprise Library can do any internal resolutions it requires. |
| 50 | + /// </para> |
| 51 | + /// <para> |
| 52 | + /// Even though you can use this configurator directly, the simplest way |
| 53 | + /// to get Enterprise Library configured with Autofac is to use the |
| 54 | + /// <see cref="M:Autofac.Extras.EnterpriseLibraryConfigurator.EnterpriseLibraryRegistrationExtensions.RegisterEnterpriseLibrary"/> |
| 55 | + /// extensions. The above sample code becomes much simpler and more |
| 56 | + /// Autofac-styled with the extensions. |
| 57 | + /// </para> |
| 58 | + /// <code lang="C#"> |
| 59 | + /// // Create the ContainerBuilder and register EntLib. |
| 60 | + /// var builder = new ContainerBuilder(); |
| 61 | + /// builder.RegisterEnterpriseLibrary(); |
| 62 | + /// |
| 63 | + /// // Register other services/dependencies, then set the |
| 64 | + /// // service locator. |
| 65 | + /// var container = builder.Build(); |
| 66 | + /// var autofacLocator = new AutofacServiceLocator(container); |
| 67 | + /// EnterpriseLibraryContainer.Current = autofacLocator; |
| 68 | + /// </code> |
| 69 | + /// <para> |
| 70 | + /// Note that using Autofac as the backing store for service resolution |
| 71 | + /// in Enterprise Library, changes in the dependency configuration source |
| 72 | + /// are not directly supported. That is, if the set of configured services |
| 73 | + /// changes, the container is not automatically rebuilt. This is a different |
| 74 | + /// behavior from Unity, which supports configuration change and container |
| 75 | + /// update during application execution. |
| 76 | + /// </para> |
| 77 | + /// <para> |
| 78 | + /// The reason this is important is that some internal Enterprise Library |
| 79 | + /// components make the assumption that the container has a configuration |
| 80 | + /// change manager (<see cref="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ContainerModel.ConfigurationChangeEventSource"/>) |
| 81 | + /// registered regardless of support. This configurator will add a placeholder |
| 82 | + /// implementation to the container to enable these components to function, |
| 83 | + /// but developers should be aware that no action will take place if configuration |
| 84 | + /// changes even though the component appears to be present in the container. |
| 85 | + /// </para> |
| 86 | + /// </remarks> |
| 87 | + /// <seealso cref="M:Autofac.Extras.EnterpriseLibraryConfigurator.EnterpriseLibraryRegistrationExtensions.RegisterEnterpriseLibrary"/> |
| 88 | + public class AutofacContainerConfigurator : IContainerConfigurator |
| 89 | + { |
| 90 | + /// <summary> |
| 91 | + /// The <see cref="Autofac.ContainerBuilder"/> to which Enterprise Library |
| 92 | + /// registrations should be added. |
| 93 | + /// </summary> |
| 94 | + private ContainerBuilder _builder = null; |
| 95 | + |
| 96 | + /// <summary> |
| 97 | + /// Initializes a new instance of the <see cref="AutofacContainerConfigurator"/> class. |
| 98 | + /// </summary> |
| 99 | + /// <param name="builder"> |
| 100 | + /// The <see cref="Autofac.ContainerBuilder"/> to which Enterprise Library |
| 101 | + /// registrations should be added. |
| 102 | + /// </param> |
| 103 | + /// <exception cref="System.ArgumentNullException"> |
| 104 | + /// Thrown if <paramref name="builder" /> is <see langword="null" />. |
| 105 | + /// </exception> |
| 106 | + public AutofacContainerConfigurator(ContainerBuilder builder) |
| 107 | + { |
| 108 | + if (builder == null) |
| 109 | + { |
| 110 | + throw new ArgumentNullException("builder"); |
| 111 | + } |
| 112 | + this._builder = builder; |
| 113 | + } |
| 114 | + |
| 115 | + /// <summary> |
| 116 | + /// Consume the set of |
| 117 | + /// <see cref="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ContainerModel.TypeRegistration"/> |
| 118 | + /// objects and configure the associated container. |
| 119 | + /// </summary> |
| 120 | + /// <param name="configurationSource"> |
| 121 | + /// Configuration source to read registrations from. |
| 122 | + /// </param> |
| 123 | + /// <param name="rootProvider"> |
| 124 | + /// <see cref="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ContainerModel.ITypeRegistrationsProvider"/> |
| 125 | + /// that knows how to read the <paramref name="configurationSource"/> |
| 126 | + /// and return all relevant type registrations. |
| 127 | + /// </param> |
| 128 | + /// <remarks> |
| 129 | + /// <para> |
| 130 | + /// This method is used by <see cref="M:Microsoft.Practices.EnterpriseLibrary.Common.Configuration.EnterpriseLibraryContainer.ConfigureContainer"/> |
| 131 | + /// to add registrations from a provided <paramref name="configurationSource" /> |
| 132 | + /// to the Autofac container. |
| 133 | + /// </para> |
| 134 | + /// <para> |
| 135 | + /// At the end of the registration process, a placeholder configuration |
| 136 | + /// change manager (<see cref="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ContainerModel.ConfigurationChangeEventSource"/>) |
| 137 | + /// will be added to the container if one hasn't already been added. |
| 138 | + /// This is required because some internal Enterprise Library |
| 139 | + /// components make the assumption that the container has a configuration |
| 140 | + /// change manager registered regardless of support. Developers should |
| 141 | + /// be aware that no action will take place if configuration |
| 142 | + /// changes even though the component appears to be present in the container. |
| 143 | + /// </para> |
| 144 | + /// </remarks> |
| 145 | + public void RegisterAll(IConfigurationSource configurationSource, ITypeRegistrationsProvider rootProvider) |
| 146 | + { |
| 147 | + if (configurationSource == null) |
| 148 | + { |
| 149 | + throw new ArgumentNullException("configurationSource"); |
| 150 | + } |
| 151 | + if (rootProvider == null) |
| 152 | + { |
| 153 | + throw new ArgumentNullException("rootProvider"); |
| 154 | + } |
| 155 | + foreach (TypeRegistration registration in rootProvider.GetRegistrations(configurationSource)) |
| 156 | + { |
| 157 | + this._builder.RegisterTypeRegistration(registration); |
| 158 | + } |
| 159 | + |
| 160 | + // For some reason you have to manually register an event source |
| 161 | + // with the container. Unity must somehow do this automatically in |
| 162 | + // the UnityContainerConfigurator but I can't find it. You need to |
| 163 | + // do this if you use the Logging application block since the |
| 164 | + // LoggingUpdateCoordinator requires this type. I'm not sure which |
| 165 | + // other components might require it. |
| 166 | + // |
| 167 | + // Autofac doesn't support changing the container after it's already |
| 168 | + // built, so rather than implement a ChangeTrackingContainerConfigurator, |
| 169 | + // we'll just stick a throwaway event source in here. |
| 170 | + this._builder.RegisterInstance(new ConfigurationChangeEventSourceImpl()).As<ConfigurationChangeEventSource>().PreserveExistingDefaults(); |
| 171 | + } |
| 172 | + } |
| 173 | +} |
0 commit comments