@joebigelow / wix-1 / commits / b6bf1604

Introduce IExtensionFactory as mechanism to create extensions

Rob Mensching committed Nov 11, 2017 at 12:41 UTC b6bf1604c32259757f75b4c35444cfe4ecc21a86
8 files changed +75 -44
src/WixToolset.BuildTasks/DoIt.cs
+1 -1
@@ -181,7 +181,7 @@ namespace WixToolset.BuildTasks
181 {
182 var extensionManager = serviceProvider.GetService<IExtensionManager>();
183
184 - foreach (var type in new[] { typeof(WixToolset.Core.Burn.StandardBackend), typeof(WixToolset.Core.WindowsInstaller.StandardBackend) })
184 + foreach (var type in new[] { typeof(WixToolset.Core.Burn.WixToolsetStandardBackend), typeof(WixToolset.Core.WindowsInstaller.WixToolsetStandardBackend) })
185 {
186 extensionManager.Add(type.Assembly);
187 }
src/WixToolset.Core.Burn/BurnBackendFactory.cs renamed
+1 -1
@@ -7,7 +7,7 @@ namespace WixToolset.Core.Burn
7 using WixToolset.Extensibility;
8 using WixToolset.Extensibility.Services;
9
10 - internal class BackendFactory : IBackendFactory
10 + internal class BurnBackendFactory : IBackendFactory
11 {
12 public bool TryCreateBackend(string outputType, string outputFile, IBindContext context, out IBackend backend)
13 {
src/WixToolset.Core.Burn/BurnExtensionFactory.cs new
+22
@@ -0,0 +1,22 @@
1 +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2 +
3 +namespace WixToolset.Core.Burn
4 +{
5 + using System;
6 + using WixToolset.Extensibility;
7 +
8 + internal class BurnExtensionFactory : IExtensionFactory
9 + {
10 + public bool TryCreateExtension(Type extensionType, out object extension)
11 + {
12 + extension = null;
13 +
14 + if (extensionType == typeof(IBackendFactory))
15 + {
16 + extension = new BurnBackendFactory();
17 + }
18 +
19 + return extension != null;
20 + }
21 + }
22 +}
src/WixToolset.Core.Burn/WixToolsetStandardBackend.cs renamed
+1 -1
@@ -6,7 +6,7 @@ namespace WixToolset.Core.Burn
6 /// Denotes this assembly contains a backend that is considered
7 /// a standard part of the WiX Toolset.
8 /// </summary>
9 - public static class StandardBackend
9 + public static class WixToolsetStandardBackend
10 {
11 }
12 }
src/WixToolset.Core.WindowsInstaller/WindowsInstallerExtensionFactory.cs new
+22
@@ -0,0 +1,22 @@
1 +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2 +
3 +namespace WixToolset.Core.WindowsInstaller
4 +{
5 + using System;
6 + using WixToolset.Extensibility;
7 +
8 + internal class WindowsInstallerExtensionFactory : IExtensionFactory
9 + {
10 + public bool TryCreateExtension(Type extensionType, out object extension)
11 + {
12 + extension = null;
13 +
14 + if (extensionType == typeof(IBackendFactory))
15 + {
16 + extension = new WindowsInstallerBackendFactory();
17 + }
18 +
19 + return extension != null;
20 + }
21 + }
22 +}
src/WixToolset.Core.WindowsInstaller/WixToolsetStandardBackend.cs renamed
+1 -1
@@ -6,7 +6,7 @@ namespace WixToolset.Core.WindowsInstaller
6 /// Denotes this assembly contains a backend that is considered
7 /// a standard part of the WiX Toolset.
8 /// </summary>
9 - public static class StandardBackend
9 + public static class WixToolsetStandardBackend
10 {
11 }
12 }
src/WixToolset.Core/ExtensionManager.cs
+26 -39
@@ -8,53 +8,36 @@ namespace WixToolset.Core
8 using System.Linq;
9 using System.Reflection;
10 using WixToolset.Data;
11 + using WixToolset.Extensibility;
12 using WixToolset.Extensibility.Services;
13
13 - public class ExtensionManager : IExtensionManager
14 + internal class ExtensionManager : IExtensionManager
15 {
15 - private List<Assembly> extensionAssemblies = new List<Assembly>();
16 + private List<IExtensionFactory> extensionFactories = new List<IExtensionFactory>();
17
17 - /// <summary>
18 - /// Adds an assembly.
19 - /// </summary>
20 - /// <param name="assembly">Assembly to add to the extension manager.</param>
21 - /// <returns>The assembly added.</returns>
22 - public Assembly Add(Assembly assembly)
18 + public void Add(Assembly extensionAssembly)
19 {
24 - this.extensionAssemblies.Add(assembly);
25 - return assembly;
20 + var types = extensionAssembly.GetTypes().Where(t => !t.IsAbstract && !t.IsInterface && typeof(IExtensionFactory).IsAssignableFrom(t));
21 + var factories = types.Select(t => (IExtensionFactory)Activator.CreateInstance(t)).ToList();
22 +
23 + this.extensionFactories.AddRange(factories);
24 }
25
28 - /// <summary>
29 - /// Loads an assembly from a type description string.
30 - /// </summary>
31 - /// <param name="extension">The assembly type description string.</param>
32 - /// <returns>The loaded assembly. This assembly can be ignored since the extension manager maintains the list of loaded assemblies internally.</returns>
33 - /// <remarks>
34 - /// <paramref name="extension"/> can be in several different forms:
35 - /// <list type="number">
36 - /// <item><term>AssemblyName (MyAssembly, Version=1.3.0.0, Culture=neutral, PublicKeyToken=b17a5c561934e089)</term></item>
37 - /// <item><term>Absolute path to an assembly (C:\MyExtensions\ExtensionAssembly.dll)</term></item>
38 - /// <item><term>Filename of an assembly in the application directory (ExtensionAssembly.dll)</term></item>
39 - /// <item><term>Relative path to an assembly (..\..\MyExtensions\ExtensionAssembly.dll)</term></item>
40 - /// </list>
41 - /// </remarks>
42 - public Assembly Load(string extension)
26 + public void Load(string extensionPath)
27 {
44 - string assemblyName = extension;
28 Assembly assembly;
29
30 // Absolute path to an assembly which means only "load from" will work even though we'd prefer to
31 // use Assembly.Load (see the documentation for Assembly.LoadFrom why).
49 - if (Path.IsPathRooted(assemblyName))
32 + if (Path.IsPathRooted(extensionPath))
33 {
51 - assembly = ExtensionManager.ExtensionLoadFrom(assemblyName);
34 + assembly = ExtensionManager.ExtensionLoadFrom(extensionPath);
35 }
53 - else if (ExtensionManager.TryExtensionLoad(assemblyName, out assembly))
36 + else if (ExtensionManager.TryExtensionLoad(extensionPath, out assembly))
37 {
38 // Loaded the assembly by name from the probing path.
39 }
57 - else if (ExtensionManager.TryExtensionLoad(Path.GetFileNameWithoutExtension(assemblyName), out assembly))
40 + else if (ExtensionManager.TryExtensionLoad(Path.GetFileNameWithoutExtension(extensionPath), out assembly))
41 {
42 // Loaded the assembly by filename alone along the probing path.
43 }
@@ -65,21 +48,25 @@ namespace WixToolset.Core
48 // path, so we should try Assembly.LoadFrom one last time. We could have detected a directory
49 // separator character and used Assembly.LoadFrom directly, but dealing with path canonicalization
50 // issues is something we don't want to deal with if we don't have to.
68 - assembly = ExtensionManager.ExtensionLoadFrom(assemblyName);
51 + assembly = ExtensionManager.ExtensionLoadFrom(extensionPath);
52 }
53
71 - return this.Add(assembly);
54 + this.Add(assembly);
55 }
56
74 - /// <summary>
75 - /// Creates extension of specified type from assemblies loaded into the extension manager.
76 - /// </summary>
77 - /// <typeparam name="T">Type of extension to create.</typeparam>
78 - /// <returns>Extensions created of the specified type.</returns>
57 public IEnumerable<T> Create<T>() where T : class
58 {
81 - var types = this.extensionAssemblies.SelectMany(a => a.GetTypes().Where(t => !t.IsAbstract && !t.IsInterface && typeof(T).IsAssignableFrom(t)));
82 - return types.Select(t => (T)Activator.CreateInstance(t)).ToList();
59 + var extensions = new List<T>();
60 +
61 + foreach (var factory in this.extensionFactories)
62 + {
63 + if (factory.TryCreateExtension(typeof(T), out var obj) && obj is T extension)
64 + {
65 + extensions.Add(extension);
66 + }
67 + }
68 +
69 + return extensions;
70 }
71
72 private static Assembly ExtensionLoadFrom(string assemblyName)
src/wix/Program.cs
+1 -1
@@ -49,7 +49,7 @@ namespace WixToolset.Core
49 {
50 var extensionManager = serviceProvider.GetService<IExtensionManager>();
51
52 - foreach (var type in new[] { typeof(WixToolset.Core.Burn.StandardBackend), typeof(WixToolset.Core.WindowsInstaller.StandardBackend) })
52 + foreach (var type in new[] { typeof(WixToolset.Core.Burn.WixToolsetStandardBackend), typeof(WixToolset.Core.WindowsInstaller.WixToolsetStandardBackend) })
53 {
54 extensionManager.Add(type.Assembly);
55 }