Skip to content

Commit 9d15bcb

Browse files
authored
Fix loading additional Handlebars.Net.Helpers dll's when running application from commandline using 'dotnet run' (#97)
* Fix loading additional Handlebars.Net.Helpers dll's when running application from commandline using 'dotnet run' * . * var paths = options.CustomHelperPaths ?? new List<string> * ... * fix
1 parent 40368e1 commit 9d15bcb

File tree

4 files changed

+90
-41
lines changed

4 files changed

+90
-41
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System;
2+
using System.IO;
3+
4+
namespace HandlebarsDotNet.Helpers.Compatibility;
5+
6+
internal static class AppContextHelper
7+
{
8+
public static string GetBaseDirectory()
9+
{
10+
#if NETSTANDARD1_3_OR_GREATER || NET6_0_OR_GREATER
11+
return AppContext.BaseDirectory.TrimEnd(Path.DirectorySeparatorChar);
12+
#else
13+
return AppDomain.CurrentDomain.BaseDirectory.TrimEnd(Path.DirectorySeparatorChar);
14+
#endif
15+
}
16+
}

src/Handlebars.Net.Helpers/HandlebarsHelpers.cs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
using HandlebarsDotNet.Helpers.Utils;
1414
using Stef.Validation;
1515
using HandlebarsDotNet.Helpers.Models;
16+
using System.Diagnostics;
17+
using HandlebarsDotNet.Helpers.Compatibility;
18+
19+
1620
#if NETSTANDARD1_3_OR_GREATER || NET46_OR_GREATER || NET6_0_OR_GREATER
1721
using System.Threading;
1822
#else
@@ -78,7 +82,36 @@ public static void Register(IHandlebars handlebarsContext, Action<HandlebarsHelp
7882
{ Category.Xslt, "XsltHelpers" }
7983
};
8084

81-
var paths = options.CustomHelperPaths ?? new List<string> { Directory.GetCurrentDirectory() };
85+
86+
87+
List<string> paths;
88+
if (options.CustomHelperPaths != null)
89+
{
90+
paths = options.CustomHelperPaths.ToList();
91+
}
92+
else
93+
{
94+
paths = new List<string>
95+
{
96+
Directory.GetCurrentDirectory(),
97+
AppContextHelper.GetBaseDirectory(),
98+
};
99+
100+
#if !NETSTANDARD1_3_OR_GREATER
101+
void Add(string? path, ICollection<string> customHelperPaths)
102+
{
103+
if (!string.IsNullOrEmpty(path))
104+
{
105+
customHelperPaths.Add(path!);
106+
}
107+
}
108+
Add(Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location), paths);
109+
Add(Path.GetDirectoryName(Assembly.GetCallingAssembly().Location), paths);
110+
Add(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), paths);
111+
Add(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule?.FileName), paths);
112+
#endif
113+
}
114+
82115
var extraHelpers = PluginLoader.Load(paths, extra, handlebarsContext);
83116

84117
foreach (var item in extraHelpers)

src/Handlebars.Net.Helpers/Options/HandlebarsHelpersOptions.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using System.Collections.Generic;
2-
using System.IO;
32
using HandlebarsDotNet.Helpers.Enums;
43
using HandlebarsDotNet.Helpers.Helpers;
54
using HandlebarsDotNet.Helpers.Utils;
@@ -36,20 +35,20 @@ public class HandlebarsHelpersOptions
3635
/// <summary>
3736
/// The categories to register. By default all categories are registered. See the WIKI for details.
3837
/// </summary>
39-
public Category[]? Categories { get; set; } = null;
38+
public Category[]? Categories { get; set; }
4039

4140
/// <summary>
4241
/// Used for unit-testing DateTime related functionality.
4342
/// </summary>
44-
public IDateTimeService? DateTimeService { get; set; } = null;
43+
public IDateTimeService? DateTimeService { get; set; }
4544

4645
/// <summary>
4746
/// A Dictionary with additional Custom Helpers (Key = CategoryPrefix, Value = IHelpers)
4847
/// </summary>
49-
public IDictionary<string, IHelpers>? CustomHelpers { get; set; } = null;
48+
public IDictionary<string, IHelpers>? CustomHelpers { get; set; }
5049

5150
/// <summary>
52-
/// The paths to search for additional helpers. If null, the CurrentDirectory is used.
51+
/// The paths to search for additional helpers. If null, the CurrentDirectory and BaseDirectory are used.
5352
/// </summary>
54-
public IReadOnlyList<string>? CustomHelperPaths = new List<string> { Directory.GetCurrentDirectory() };
53+
public IReadOnlyList<string>? CustomHelperPaths;
5554
}

src/Handlebars.Net.Helpers/Plugin/PluginLoader.cs

Lines changed: 35 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,54 +6,55 @@
66
using HandlebarsDotNet.Helpers.Enums;
77
using HandlebarsDotNet.Helpers.Helpers;
88

9-
namespace HandlebarsDotNet.Helpers.Plugin
9+
namespace HandlebarsDotNet.Helpers.Plugin;
10+
11+
internal static class PluginLoader
1012
{
11-
internal static class PluginLoader
13+
public static IDictionary<Category, IHelpers> Load(IEnumerable<string> paths, IDictionary<Category, string> items, params object[] args)
1214
{
13-
public static IDictionary<Category, IHelpers> Load(IEnumerable<string> paths, IDictionary<Category, string> items, params object[] args)
15+
var helpers = new Dictionary<Category, IHelpers>();
16+
17+
var pluginTypes = new List<Type>();
18+
try
1419
{
15-
var pluginTypes = new List<Type>();
16-
try
20+
foreach (var file in paths.Distinct().SelectMany(path => Directory.GetFiles(path, "Handlebars*dll")).Distinct())
1721
{
18-
foreach (var file in paths.SelectMany(path => Directory.GetFiles(path, "*.dll")))
22+
try
1923
{
20-
try
21-
{
22-
var assembly = Assembly.Load(new AssemblyName
23-
{
24-
Name = Path.GetFileNameWithoutExtension(file)
25-
});
26-
27-
pluginTypes.AddRange(GetImplementationTypeByInterface(assembly));
28-
}
29-
catch
24+
var assembly = Assembly.Load(new AssemblyName
3025
{
31-
// no-op: just try next .dll
32-
}
33-
}
34-
}
35-
catch
36-
{
37-
// no-op: file system access possibly denied, don't search for files
38-
}
39-
26+
Name = Path.GetFileNameWithoutExtension(file)
27+
});
4028

41-
var helpers = new Dictionary<Category, IHelpers>();
42-
foreach (var item in items)
43-
{
44-
var matchingType = pluginTypes.FirstOrDefault(pt => pt.Name == item.Value);
45-
if (matchingType is { })
29+
pluginTypes.AddRange(GetImplementationTypeByInterface(assembly));
30+
}
31+
catch
4632
{
47-
helpers.Add(item.Key, (IHelpers)Activator.CreateInstance(matchingType, args)!);
33+
// Just try next .dll
4834
}
4935
}
50-
36+
}
37+
catch
38+
{
39+
// File system access possibly denied, don't search for any more files
5140
return helpers;
5241
}
5342

54-
private static IEnumerable<Type> GetImplementationTypeByInterface(Assembly assembly)
43+
44+
foreach (var item in items)
5545
{
56-
return assembly.GetTypes().Where(t => typeof(IHelpers).IsAssignableFrom(t) && !t.GetTypeInfo().IsInterface);
46+
var matchingType = pluginTypes.FirstOrDefault(pt => pt.Name == item.Value);
47+
if (matchingType is not null)
48+
{
49+
helpers.Add(item.Key, (IHelpers)Activator.CreateInstance(matchingType, args)!);
50+
}
5751
}
52+
53+
return helpers;
54+
}
55+
56+
private static IEnumerable<Type> GetImplementationTypeByInterface(Assembly assembly)
57+
{
58+
return assembly.GetTypes().Where(t => typeof(IHelpers).IsAssignableFrom(t) && !t.GetTypeInfo().IsInterface);
5859
}
5960
}

0 commit comments

Comments
 (0)