在kephas应用程序中加载应用程序组件的默认实现是包括在应用程序文件夹中找到的所有组件。如果我需要提供其他文件夹,或者我想支持插件怎么办?如何指定其他文件夹或要在搜索中包含的文件夹列表?
kephas中的几乎所有内容都是可配置的,IAppRuntime
服务也不例外。但是,与公共应用程序不同,这不是通过[AppServiceContract]
属性注册的,而是在Bootstrap过程中设置和配置。这种行为背后的主要原因是在初始化组成/IOC容器之前需要使用IAppRuntime
服务。
您可以在下面找到可能的实现:
/// <summary>
/// An application runtime supporting plugins.
/// Each plugin is found in its own folder in the Plugins sub directory of the application root folder.
/// </summary>
public class PluginsAppRuntime : DefaultAppRuntime
{
/// <summary>
/// Initializes a new instance of the <see cref="PluginsAppRuntime"/> class.
/// </summary>
/// <param name="assemblyLoader">Optional. The assembly loader.</param>
/// <param name="logManager">Optional. The log manager.</param>
/// <param name="assemblyFilter">Optional. A filter for loaded assemblies.</param>
/// <param name="appLocation">Optional. The application location. If not specified, the current
/// application location is considered.</param>
public PluginsAppRuntime(
IAssemblyLoader assemblyLoader = null,
ILogManager logManager = null,
Func<AssemblyName, bool> assemblyFilter = null,
string appLocation = null)
: base(assemblyLoader, logManager, assemblyFilter, appLocation)
{
pluginsFolder = Path.Combine(this.GetAppLocation(), "Plugins");
this.PluginsFolder = Path.GetFullPath(pluginsFolder);
}
/// <summary>
/// Gets the pathname of the plugins folder.
/// </summary>
public string PluginsFolder { get; }
/// <summary>
/// Enumerates the application directories containing assemblies to be loaded.
/// </summary>
protected override IEnumerable<string> GetAppAssemblyDirectories()
{
var rootDirectory = this.GetAppLocation();
var appDirectories = new List<string> { rootDirectory };
appDirectories.AddRange(this.EnumeratePluginFolders());
var logger = this.GetLogger();
logger.Info($"Loading application from directories: {string.Join(", ", appDirectories)}");
return appDirectories;
}
/// <summary>
/// Enumerates the root bin folders for the plugins.
/// </summary>
public IEnumerable<string> EnumeratePluginFolders()
{
var binPluginsFolder = this.PluginsFolder;
if (Directory.Exists(binPluginsFolder))
{
var pluginsDirectories = Directory.EnumerateDirectories(binPluginsFolder);
return pluginsDirectories;
}
return new string[0];
}
}
/// <summary>
/// For the sake of simplicity, add an extension method to the ambient services builder to make use of this new service.
/// </summary>
public static class PluginsAmbientServicesBuilderExtensions
{
/// <summary>
/// Sets the plugins-enabled application runtime to the ambient services.
/// </summary>
/// <param name="ambientServicesBuilder">The ambient services builder.</param>
/// <param name="assemblyFilter">Optional. A filter specifying the assembly (optional).</param>
/// <param name="appLocation">Optional. The application location (optional). If not specified, the
/// assembly location is used.</param>
/// <returns>
/// The provided ambient services builder.
/// </returns>
public static AmbientServicesBuilder WithPluginsAppRuntime(
this AmbientServicesBuilder ambientServicesBuilder,
Func<AssemblyName, bool> assemblyFilter = null,
string appLocation = null)
{
Requires.NotNull(ambientServicesBuilder, nameof(ambientServicesBuilder));
var ambientServices = ambientServicesBuilder.AmbientServices;
var assemblyLoader = new DefaultAssemblyLoader();
ambientServices.RegisterService<IAssemblyLoader>(assemblyLoader);
return ambientServicesBuilder.WithAppRuntime(
new PluginsAppRuntime(
assemblyLoader,
ambientServices.LogManager,
assemblyFilter: assemblyFilter,
appLocation: appLocation));
}
}
/// <summary>
/// Last, but not least, define the application root object.
/// </summary>
public class App : AppBase
{
/// <summary>Configures the ambient services asynchronously.</summary>
/// <param name="appArgs">The application arguments.</param>
/// <param name="ambientServicesBuilder">The ambient services builder.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The asynchronous result.</returns>
protected override async Task ConfigureAmbientServicesAsync(
string[] appArgs,
AmbientServicesBuilder ambientServicesBuilder,
CancellationToken cancellationToken)
{
ambientServicesBuilder
.WithAppConfiguration(new DefaultAppConfiguration())
.WithPluginsAppRuntime()
.WithMefCompositionContainer();
}
}
/// <summary>
/// Now everything is ready to go!
/// </summary>
public static class Program
{
private static async Task<int> Main(string[] args)
{
try
{
var result = await new App().BootstrapAsync(args).PreserveThreadContext();
return 0;
}
catch (Exception ex)
{
return 100;
}
}
}