Skip to content

Commit 6600d4d

Browse files
committed
Added autofac support for library
1 parent f08fad2 commit 6600d4d

File tree

9 files changed

+1010
-0
lines changed

9 files changed

+1010
-0
lines changed
Lines changed: 327 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,327 @@
1+
using System;
2+
using System.Globalization;
3+
using Autofac;
4+
using Autofac.Features.ResolveAnything;
5+
using AutofacCore = Autofac.Core;
6+
using CommonServiceLocator;
7+
using Prism.Autofac.Avalonia.Properties;
8+
using Prism.Events;
9+
using Prism.Logging;
10+
using Prism.Modularity;
11+
using Prism.Mvvm;
12+
using Prism.Regions;
13+
using Prism.Unity.Regions;
14+
15+
namespace Prism.Autofac
16+
{
17+
/// <summary>
18+
/// Base class that provides a basic bootstrapping sequence that
19+
/// registers most of the Prism Library assets
20+
/// in an Autofac <see cref="IContainer"/>.
21+
/// </summary>
22+
/// <remarks>
23+
/// This class must be overridden to provide application specific configuration.
24+
/// </remarks>
25+
public abstract class AutofacBootstrapper : Bootstrapper
26+
{
27+
private bool _useDefaultConfiguration = true;
28+
29+
/// <summary>
30+
/// Gets the default Autofac <see cref="IContainer"/> for the application.
31+
/// </summary>
32+
/// <value>The default <see cref="IContainer"/> instance.</value>
33+
public IContainer Container { get; protected set; }
34+
35+
/// <summary>
36+
/// Run the bootstrapper process.
37+
/// </summary>
38+
/// <param name="runWithDefaultConfiguration">If <see langword="true"/>, registers default Prism Library services in the container. This is the default behavior.</param>
39+
public override void Run(bool runWithDefaultConfiguration)
40+
{
41+
_useDefaultConfiguration = runWithDefaultConfiguration;
42+
43+
Logger = CreateLogger();
44+
if (Logger == null)
45+
{
46+
throw new InvalidOperationException(Resources.NullLoggerFacadeException);
47+
}
48+
49+
Logger.Log(Resources.LoggerCreatedSuccessfully, Category.Debug, Priority.Low);
50+
51+
Logger.Log(Resources.CreatingModuleCatalog, Category.Debug, Priority.Low);
52+
ModuleCatalog = CreateModuleCatalog();
53+
if (ModuleCatalog == null)
54+
{
55+
throw new InvalidOperationException(Resources.NullModuleCatalogException);
56+
}
57+
58+
Logger.Log(Resources.ConfiguringModuleCatalog, Category.Debug, Priority.Low);
59+
ConfigureModuleCatalog();
60+
61+
Logger.Log(Resources.CreatingAutofacContainerBuilder, Category.Debug, Priority.Low);
62+
ContainerBuilder builder = CreateContainerBuilder();
63+
if (builder == null)
64+
{
65+
throw new InvalidOperationException(Resources.NullAutofacContainerBuilderException);
66+
}
67+
68+
Logger.Log(Resources.ConfiguringAutofacContainerBuilder, Category.Debug, Priority.Low);
69+
// Make sure any not specifically registered concrete type can resolve.
70+
builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource());
71+
ConfigureContainerBuilder(builder);
72+
73+
Logger.Log(Resources.CreatingAutofacContainer, Category.Debug, Priority.Low);
74+
Container = CreateContainer(builder);
75+
if (Container == null)
76+
{
77+
throw new InvalidOperationException(Resources.NullAutofacContainerException);
78+
}
79+
80+
Logger.Log(Resources.ConfiguringServiceLocatorSingleton, Category.Debug, Priority.Low);
81+
ConfigureServiceLocator();
82+
83+
Logger.Log(Resources.ConfiguringViewModelLocator, Category.Debug, Priority.Low);
84+
ConfigureViewModelLocator();
85+
86+
Logger.Log(Resources.ConfiguringRegionAdapters, Category.Debug, Priority.Low);
87+
ConfigureRegionAdapterMappings();
88+
89+
Logger.Log(Resources.ConfiguringDefaultRegionBehaviors, Category.Debug, Priority.Low);
90+
ConfigureDefaultRegionBehaviors();
91+
92+
Logger.Log(Resources.RegisteringFrameworkExceptionTypes, Category.Debug, Priority.Low);
93+
RegisterFrameworkExceptionTypes();
94+
95+
Logger.Log(Resources.CreatingShell, Category.Debug, Priority.Low);
96+
Shell = CreateShell();
97+
if (Shell != null)
98+
{
99+
Logger.Log(Resources.SettingTheRegionManager, Category.Debug, Priority.Low);
100+
RegionManager.SetRegionManager(Shell, Container.Resolve<IRegionManager>());
101+
102+
Logger.Log(Resources.UpdatingRegions, Category.Debug, Priority.Low);
103+
RegionManager.UpdateRegions();
104+
105+
Logger.Log(Resources.InitializingShell, Category.Debug, Priority.Low);
106+
InitializeShell();
107+
}
108+
109+
if (Container.IsRegistered<IModuleManager>())
110+
{
111+
Logger.Log(Resources.InitializingModules, Category.Debug, Priority.Low);
112+
InitializeModules();
113+
}
114+
115+
Logger.Log(Resources.BootstrapperSequenceCompleted, Category.Debug, Priority.Low);
116+
}
117+
118+
/// <summary>
119+
/// Configures the LocatorProvider for the <see cref="ServiceLocator" />.
120+
/// </summary>
121+
protected override void ConfigureServiceLocator()
122+
{
123+
var serviceLocator = new AutofacServiceLocatorAdapter(Container);
124+
ServiceLocator.SetLocatorProvider(() => serviceLocator);
125+
126+
// register the locator in Autofac as well
127+
RegisterInstance(serviceLocator, typeof(IServiceLocator), registerAsSingleton: true);
128+
}
129+
130+
/// <summary>
131+
/// Configures the <see cref="ViewModelLocator"/> used by Prism.
132+
/// </summary>
133+
protected override void ConfigureViewModelLocator()
134+
{
135+
ViewModelLocationProvider.SetDefaultViewModelFactory((type) => Container.Resolve(type));
136+
}
137+
138+
/// <summary>
139+
/// Registers in the Autofac <see cref="IContainer"/> the <see cref="Type"/> of the Exceptions
140+
/// that are not considered root exceptions by the <see cref="ExceptionExtensions"/>.
141+
/// </summary>
142+
protected override void RegisterFrameworkExceptionTypes()
143+
{
144+
base.RegisterFrameworkExceptionTypes();
145+
146+
ExceptionExtensions.RegisterFrameworkExceptionType(typeof(AutofacCore.DependencyResolutionException));
147+
ExceptionExtensions.RegisterFrameworkExceptionType(typeof(AutofacCore.Registration.ComponentNotRegisteredException));
148+
}
149+
150+
/// <summary>
151+
/// Creates the <see cref="ContainerBuilder"/> that will be used to create the default container.
152+
/// </summary>
153+
/// <returns>A new instance of <see cref="ContainerBuilder"/>.</returns>
154+
protected virtual ContainerBuilder CreateContainerBuilder()
155+
{
156+
return new ContainerBuilder();
157+
}
158+
159+
/// <summary>
160+
/// Configures the <see cref="ContainerBuilder"/>.
161+
/// May be overwritten in a derived class to add specific type mappings required by the application.
162+
/// </summary>
163+
protected virtual void ConfigureContainerBuilder(ContainerBuilder builder)
164+
{
165+
builder.RegisterInstance(Logger).As<ILoggerFacade>();
166+
builder.RegisterInstance(ModuleCatalog);
167+
168+
if (_useDefaultConfiguration)
169+
{
170+
RegisterTypeIfMissing<IModuleInitializer, ModuleInitializer>(builder, true);
171+
RegisterTypeIfMissing<IModuleManager, ModuleManager>(builder, true);
172+
RegisterTypeIfMissing<RegionAdapterMappings, RegionAdapterMappings>(builder, true);
173+
RegisterTypeIfMissing<IRegionManager, RegionManager>(builder, true);
174+
RegisterTypeIfMissing<IEventAggregator, EventAggregator>(builder, true);
175+
RegisterTypeIfMissing<IRegionViewRegistry, RegionViewRegistry>(builder, true);
176+
RegisterTypeIfMissing<IRegionBehaviorFactory, RegionBehaviorFactory>(builder, true);
177+
RegisterTypeIfMissing<IRegionNavigationJournalEntry, RegionNavigationJournalEntry>(builder, false);
178+
RegisterTypeIfMissing<IRegionNavigationJournal, RegionNavigationJournal>(builder, false);
179+
RegisterTypeIfMissing<IRegionNavigationService, RegionNavigationService>(builder, false);
180+
RegisterTypeIfMissing<IRegionNavigationContentLoader, AutofacRegionNavigationContentLoader>(builder, true);
181+
}
182+
}
183+
184+
/// <summary>
185+
/// Creates the Autofac <see cref="IContainer"/> that will be used as the default container.
186+
/// </summary>
187+
/// <returns>A new instance of <see cref="IContainer"/>.</returns>
188+
protected virtual IContainer CreateContainer(ContainerBuilder containerBuilder)
189+
{
190+
IContainer container = containerBuilder.Build();
191+
192+
// Register container instance
193+
var updater = new ContainerBuilder();
194+
updater.RegisterInstance(container);
195+
updater.Update(container);
196+
197+
return container;
198+
}
199+
200+
/// <summary>
201+
/// Initializes the modules. May be overwritten in a derived class to use a custom Modules Catalog
202+
/// </summary>
203+
protected override void InitializeModules()
204+
{
205+
IModuleManager manager;
206+
207+
try
208+
{
209+
manager = Container.Resolve<IModuleManager>();
210+
}
211+
catch (AutofacCore.DependencyResolutionException ex)
212+
{
213+
if (ex.Message.Contains("IModuleCatalog"))
214+
{
215+
throw new InvalidOperationException(Resources.NullModuleCatalogException);
216+
}
217+
218+
throw;
219+
}
220+
221+
manager.Run();
222+
}
223+
224+
/// <summary>
225+
/// Registers a type in the container only if that type was not already registered.
226+
/// </summary>
227+
/// <typeparam name="TFrom">The interface type to register.</typeparam>
228+
/// <typeparam name="TTarget">The type implementing the interface.</typeparam>
229+
/// <param name="builder">The <see cref="ContainerBuilder"/> instance.</param>
230+
/// <param name="registerAsSingleton">Registers the type as a singleton.</param>
231+
protected void RegisterTypeIfMissing<TFrom, TTarget>(ContainerBuilder builder, bool registerAsSingleton = false)
232+
{
233+
if(Container!=null && Container.IsRegistered<TFrom>())
234+
{
235+
Logger.Log(String.Format(CultureInfo.CurrentCulture, Resources.TypeMappingAlreadyRegistered, typeof(TFrom).Name),
236+
Category.Debug, Priority.Low);
237+
}
238+
else
239+
{
240+
if (registerAsSingleton)
241+
{
242+
builder.RegisterType<TTarget>().As<TFrom>().SingleInstance();
243+
}
244+
else
245+
{
246+
builder.RegisterType<TTarget>().As<TFrom>();
247+
}
248+
}
249+
}
250+
251+
/// <summary>
252+
/// Registers a type in the container only if that type was not already registered.
253+
/// </summary>
254+
/// <param name="fromType">The interface type to register.</param>
255+
/// <param name="toType">The type implementing the interface.</param>
256+
/// <param name="registerAsSingleton">Registers the type as a singleton.</param>
257+
protected void RegisterTypeIfMissing(Type fromType, Type toType, bool registerAsSingleton)
258+
{
259+
if (fromType == null)
260+
{
261+
throw new ArgumentNullException(nameof(fromType));
262+
}
263+
if (toType == null)
264+
{
265+
throw new ArgumentNullException(nameof(toType));
266+
}
267+
if (Container.IsRegistered(fromType))
268+
{
269+
Logger.Log(String.Format(CultureInfo.CurrentCulture, Resources.TypeMappingAlreadyRegistered, fromType.Name),
270+
Category.Debug, Priority.Low);
271+
}
272+
else
273+
{
274+
ContainerBuilder builder = CreateContainerBuilder();
275+
if (registerAsSingleton)
276+
{
277+
builder.RegisterType(toType).As(fromType).SingleInstance();
278+
}
279+
else
280+
{
281+
builder.RegisterType(toType).As(fromType);
282+
}
283+
builder.Update(Container);
284+
}
285+
}
286+
287+
/// <summary>
288+
/// Registers an object instance in the container.
289+
/// </summary>
290+
/// <param name="instance">Object instance.</param>
291+
/// <param name="fromType">The interface type to register.</param>
292+
/// <param name="key">Optional key for registration.</param>
293+
/// <param name="registerAsSingleton">Registers the type as a singleton.</param>
294+
protected void RegisterInstance<T>(T instance, Type fromType, string key = "", bool registerAsSingleton = false)
295+
where T : class
296+
{
297+
if (instance == null)
298+
{
299+
throw new ArgumentNullException(nameof(instance));
300+
}
301+
if (fromType == null)
302+
{
303+
throw new ArgumentNullException(nameof(fromType));
304+
}
305+
306+
ContainerBuilder containerUpdater = CreateContainerBuilder();
307+
308+
var registration = containerUpdater.RegisterInstance(instance);
309+
// named instance
310+
if (!string.IsNullOrEmpty(key))
311+
{
312+
registration = registration.Named(key, fromType);
313+
}
314+
else
315+
{
316+
registration = registration.As(fromType);
317+
}
318+
// singleton
319+
if (registerAsSingleton)
320+
{
321+
registration.SingleInstance();
322+
}
323+
324+
containerUpdater.Update(Container);
325+
}
326+
}
327+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
using Autofac;
2+
using Prism.Mvvm;
3+
using System;
4+
5+
namespace Prism.Autofac
6+
{
7+
public static class AutofacExtensions
8+
{
9+
/// <summary>
10+
/// Registers an object for navigation.
11+
/// </summary>
12+
/// <typeparam name="T">The Type of the object to register</typeparam>
13+
/// <param name="builder"><see cref="ContainerBuilder"/> used to build <see cref="IContainer"/></param>
14+
/// <param name="name">The unique name to register with the object</param>
15+
public static void RegisterTypeForNavigation<T>(this ContainerBuilder builder, string name = null)
16+
{
17+
Type type = typeof(T);
18+
string viewName = string.IsNullOrWhiteSpace(name) ? type.Name : name;
19+
builder.RegisterTypeForNavigation(type, viewName);
20+
}
21+
22+
/// <summary>
23+
/// Registers an object for navigation
24+
/// </summary>
25+
/// <param name="container"></param>
26+
/// <param name="type">The type of object to register</param>
27+
/// <param name="name">The unique name to register with the obect.</param>
28+
public static void RegisterTypeForNavigation(this ContainerBuilder builder, Type type, string name)
29+
{
30+
builder.RegisterType(type).Named<object>(name);
31+
}
32+
33+
/// <summary>
34+
/// Registers an object for navigation.
35+
/// </summary>
36+
/// <typeparam name="TView">The Type of object to register as the view</typeparam>
37+
/// <typeparam name="TViewModel">The ViewModel to use as the DataContext for the view</typeparam>
38+
/// <param name="name">The unique name to register with the view</param>
39+
public static void RegisterTypeForNavigation<TView, TViewModel>(this ContainerBuilder builder, string name = null)
40+
{
41+
builder.RegisterTypeForNavigationWithViewModel<TViewModel>(typeof(TView), name);
42+
}
43+
44+
private static void RegisterTypeForNavigationWithViewModel<TViewModel>(this ContainerBuilder builder, Type viewType, string name)
45+
{
46+
if (string.IsNullOrWhiteSpace(name))
47+
name = viewType.Name;
48+
49+
ViewModelLocationProvider.Register(viewType.ToString(), typeof(TViewModel));
50+
51+
builder.RegisterTypeForNavigation(viewType, name);
52+
}
53+
}
54+
}

0 commit comments

Comments
 (0)