aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Core/ExtensionManager.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/WixToolset.Core/ExtensionManager.cs')
-rw-r--r--src/WixToolset.Core/ExtensionManager.cs110
1 files changed, 110 insertions, 0 deletions
diff --git a/src/WixToolset.Core/ExtensionManager.cs b/src/WixToolset.Core/ExtensionManager.cs
new file mode 100644
index 00000000..45cb65ec
--- /dev/null
+++ b/src/WixToolset.Core/ExtensionManager.cs
@@ -0,0 +1,110 @@
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
3namespace WixToolset
4{
5 using System;
6 using System.Collections.Generic;
7 using System.IO;
8 using System.Linq;
9 using System.Reflection;
10 using WixToolset.Data;
11
12 public class ExtensionManager
13 {
14 private List<Assembly> extensionAssemblies = new List<Assembly>();
15
16 /// <summary>
17 /// Loads an assembly from a type description string.
18 /// </summary>
19 /// <param name="extension">The assembly type description string.</param>
20 /// <returns>The loaded assembly. This assembly can be ignored since the extension manager maintains the list of loaded assemblies internally.</returns>
21 /// <remarks>
22 /// <paramref name="extension"/> can be in several different forms:
23 /// <list type="number">
24 /// <item><term>AssemblyName (MyAssembly, Version=1.3.0.0, Culture=neutral, PublicKeyToken=b17a5c561934e089)</term></item>
25 /// <item><term>Absolute path to an assembly (C:\MyExtensions\ExtensionAssembly.dll)</term></item>
26 /// <item><term>Filename of an assembly in the application directory (ExtensionAssembly.dll)</term></item>
27 /// <item><term>Relative path to an assembly (..\..\MyExtensions\ExtensionAssembly.dll)</term></item>
28 /// </list>
29 /// </remarks>
30 public Assembly Load(string extension)
31 {
32 string assemblyName = extension;
33 Assembly assembly;
34
35 // Absolute path to an assembly which means only "load from" will work even though we'd prefer to
36 // use Assembly.Load (see the documentation for Assembly.LoadFrom why).
37 if (Path.IsPathRooted(assemblyName))
38 {
39 assembly = ExtensionManager.ExtensionLoadFrom(assemblyName);
40 }
41 else if (ExtensionManager.TryExtensionLoad(assemblyName, out assembly))
42 {
43 // Loaded the assembly by name from the probing path.
44 }
45 else if (ExtensionManager.TryExtensionLoad(Path.GetFileNameWithoutExtension(assemblyName), out assembly))
46 {
47 // Loaded the assembly by filename alone along the probing path.
48 }
49 else // relative path to an assembly
50 {
51 // We want to use Assembly.Load when we can because it has some benefits over Assembly.LoadFrom
52 // (see the documentation for Assembly.LoadFrom). However, it may fail when the path is a relative
53 // path, so we should try Assembly.LoadFrom one last time. We could have detected a directory
54 // separator character and used Assembly.LoadFrom directly, but dealing with path canonicalization
55 // issues is something we don't want to deal with if we don't have to.
56 assembly = ExtensionManager.ExtensionLoadFrom(assemblyName);
57 }
58
59 this.extensionAssemblies.Add(assembly);
60 return assembly;
61 }
62
63 /// <summary>
64 /// Creates extension of specified type from assemblies loaded into the extension manager.
65 /// </summary>
66 /// <typeparam name="T">Type of extension to create.</typeparam>
67 /// <returns>Extensions created of the specified type.</returns>
68 public IEnumerable<T> Create<T>() where T : class
69 {
70 var extensionType = typeof(T);
71 var types = this.extensionAssemblies.SelectMany(a => a.GetTypes().Where(t => !t.IsAbstract && !t.IsInterface && extensionType.IsAssignableFrom(t)));
72 return types.Select(t => (T)Activator.CreateInstance(t)).ToList();
73 }
74
75 private static Assembly ExtensionLoadFrom(string assemblyName)
76 {
77 try
78 {
79 return Assembly.LoadFrom(assemblyName);
80 }
81 catch (Exception e)
82 {
83 throw new WixException(WixErrors.InvalidExtension(assemblyName, e.Message), e);
84 }
85 }
86
87 private static bool TryExtensionLoad(string assemblyName, out Assembly assembly)
88 {
89 try
90 {
91 assembly = Assembly.Load(assemblyName);
92 return true;
93 }
94 catch (IOException innerE)
95 {
96 if (innerE is FileLoadException || innerE is FileNotFoundException)
97 {
98 assembly = null;
99 return false;
100 }
101
102 throw new WixException(WixErrors.InvalidExtension(assemblyName, innerE.Message), innerE);
103 }
104 catch (Exception e)
105 {
106 throw new WixException(WixErrors.InvalidExtension(assemblyName, e.Message), e);
107 }
108 }
109 }
110}