create IPluginLocator
create PluginLocator implementation. simplify NotificationManager to use PluginLocator to find plugins change plugin location code to use reflection to support multiple extension points in the application
This commit is contained in:
parent
54907cb57d
commit
c985aae677
1
.gitignore
vendored
1
.gitignore
vendored
@ -5,3 +5,4 @@
|
||||
**/.vs/**
|
||||
**dotsettings
|
||||
**.DotSettings.user
|
||||
**/.localhistory/**
|
||||
|
||||
13
RaceLapTimer/Interfaces/IPluginLocator.cs
Normal file
13
RaceLapTimer/Interfaces/IPluginLocator.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Interfaces
|
||||
{
|
||||
public interface IPluginLocator
|
||||
{
|
||||
List<T> Locate<T>();
|
||||
}
|
||||
}
|
||||
@ -43,6 +43,7 @@
|
||||
<Compile Include="IConfigFilePathProvider.cs" />
|
||||
<Compile Include="IContainerHelper.cs" />
|
||||
<Compile Include="ILoggerService.cs" />
|
||||
<Compile Include="IPluginLocator.cs" />
|
||||
<Compile Include="IPluginPathProvider.cs" />
|
||||
<Compile Include="ConfigurationSetting.cs" />
|
||||
<Compile Include="CompetitionRace.cs" />
|
||||
|
||||
@ -10,6 +10,7 @@ using Nancy.Diagnostics;
|
||||
using Nancy.TinyIoc;
|
||||
using Ninject;
|
||||
using RaceLapTimer.ApiControllers;
|
||||
using RaceLapTimer.Extensions;
|
||||
using RaceLapTimer.Extensions.Notifications;
|
||||
|
||||
namespace RaceLapTimer
|
||||
@ -30,14 +31,16 @@ namespace RaceLapTimer
|
||||
container.Bind<IPluginPathProvider>().To<PluginPathProvider>();
|
||||
container.Bind<IConfigFilePathProvider>().To<ConfigFilePathProvider>();
|
||||
container.Bind<IContainerHelper>().To<ContainerHelper>();
|
||||
container.Bind<INotifierManager>().To<NotificationManager>().InSingletonScope();
|
||||
container.Bind<IDbProvider>().To<TestProvider>().InSingletonScope();
|
||||
|
||||
container.Bind<IPluginLocator>().To<PluginLocator>();
|
||||
//load dynamic plugins..:
|
||||
var cfgFilePath = Path.Combine(container.Get<IConfigFilePathProvider>().GetPath, "NinjectConfig.xml");
|
||||
|
||||
container.Load(cfgFilePath);
|
||||
|
||||
container.Bind<INotifierManager>().To<NotificationManager>().InSingletonScope();
|
||||
|
||||
|
||||
var nM = container.Get<INotifierManager>();
|
||||
nM.NotifyRaceStarted(new NotificationEventArgs());
|
||||
}
|
||||
|
||||
@ -4,8 +4,6 @@ using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Interfaces;
|
||||
|
||||
@ -14,27 +12,11 @@ namespace RaceLapTimer.Extensions.Notifications
|
||||
class NotificationManager : INotifierManager
|
||||
{
|
||||
private readonly List<INotifierProvider> _providers;
|
||||
public NotificationManager(IPluginPathProvider pluginPath, IContainerHelper helper)
|
||||
public NotificationManager(IPluginPathProvider pluginPath, IContainerHelper helper, IPluginLocator locator)
|
||||
{
|
||||
if (!Directory.Exists(pluginPath.GetPluginPath)) return;
|
||||
var files = Directory.GetFiles(pluginPath.GetPluginPath);
|
||||
var providerFactories = locator.Locate<INotifierProviderFactory>();
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
var ext = Path.GetExtension(file);
|
||||
if (!IsAssembly(ext)) continue;
|
||||
|
||||
var assembly = Assembly.LoadFrom(file); //need to use ReflectionOnlyLoadFrom rather than LoadFrom here, this will cause exception if another extension point is implemented
|
||||
var pluginTypes = (from t in assembly.GetExportedTypes()
|
||||
where t.GetInterfaces().Any(x=>x.Name==nameof(INotifierProviderFactory))
|
||||
select t).ToList();
|
||||
if (pluginTypes.Any())
|
||||
{
|
||||
helper.RegisterType(typeof(INotifierProviderFactory), pluginTypes.First(), Path.GetFileNameWithoutExtension(file));
|
||||
}
|
||||
}
|
||||
|
||||
var providerFactories = helper.GetAll<INotifierProviderFactory>().ToList();
|
||||
//var providerFactories = helper.GetAll<INotifierProviderFactory>().ToList();
|
||||
_providers = new List<INotifierProvider>();
|
||||
foreach (var factory in providerFactories)
|
||||
{
|
||||
@ -108,5 +90,13 @@ namespace RaceLapTimer.Extensions.Notifications
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private class DiscoveredPlugin
|
||||
{
|
||||
public string FilePath { get; set; }
|
||||
public Type PluginType { get; set; }
|
||||
public Type TypeToBindTo { get; set; }
|
||||
public string UniqueName { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
96
RaceLapTimer/RaceLapTimer/Extensions/PluginLocator.cs
Normal file
96
RaceLapTimer/RaceLapTimer/Extensions/PluginLocator.cs
Normal file
@ -0,0 +1,96 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Interfaces;
|
||||
|
||||
namespace RaceLapTimer.Extensions
|
||||
{
|
||||
public class PluginLocator:IPluginLocator
|
||||
{
|
||||
private readonly IContainerHelper _helper;
|
||||
private readonly IPluginPathProvider _pluginPath;
|
||||
|
||||
public PluginLocator(IContainerHelper helper, IPluginPathProvider pluginPath)
|
||||
{
|
||||
_helper = helper;
|
||||
_pluginPath = pluginPath;
|
||||
}
|
||||
|
||||
public async Task<List<T>> LocateAsync<T>()
|
||||
{
|
||||
return await Task.Run(()=> Locate<T>());
|
||||
}
|
||||
|
||||
private List<T> Locate<T>()
|
||||
{
|
||||
if (!Directory.Exists(_pluginPath.GetPluginPath)) return new List<T>();
|
||||
var files = Directory.GetFiles(_pluginPath.GetPluginPath);
|
||||
var discoveryList = new List<DiscoveredPlugin>();
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
var ext = Path.GetExtension(file);
|
||||
if (!IsAssembly(ext)) continue;
|
||||
|
||||
var assembly = Assembly.ReflectionOnlyLoadFrom(file);
|
||||
var pluginTypes = (from t in assembly.GetExportedTypes()
|
||||
where t.GetInterfaces().Any(x => x.Name == nameof(INotifierProviderFactory))
|
||||
select t).ToList();
|
||||
if (pluginTypes.Any())
|
||||
{
|
||||
discoveryList.Add(new DiscoveredPlugin
|
||||
{
|
||||
FilePath = file,
|
||||
PluginType = pluginTypes.First(),
|
||||
TypeToBindTo = typeof(INotifierProviderFactory),
|
||||
UniqueName = Path.GetFileNameWithoutExtension(file)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var plugin in discoveryList)
|
||||
{
|
||||
//load into the appDomain..
|
||||
var assy = Assembly.LoadFrom(plugin.FilePath);
|
||||
//register our type
|
||||
var pluginTypes =
|
||||
(from t in assy.GetExportedTypes()
|
||||
where t.GetInterfaces().Any(x => x.Name == plugin.TypeToBindTo.Name)
|
||||
select t).ToList();
|
||||
|
||||
if (!pluginTypes.Any()) continue;
|
||||
|
||||
var pg = pluginTypes.First();
|
||||
_helper.RegisterType(plugin.TypeToBindTo, pg, plugin.UniqueName);
|
||||
}
|
||||
|
||||
return _helper.GetAll<T>().ToList();
|
||||
}
|
||||
|
||||
private bool IsAssembly(string extension)
|
||||
{
|
||||
var validAssemblyExts = new List<string>
|
||||
{
|
||||
"dll", "exe"
|
||||
};
|
||||
var ext = extension.Remove(0, 1);
|
||||
if (validAssemblyExts.Contains(ext))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private class DiscoveredPlugin
|
||||
{
|
||||
public string FilePath { get; set; }
|
||||
public Type PluginType { get; set; }
|
||||
public Type TypeToBindTo { get; set; }
|
||||
public string UniqueName { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -114,6 +114,7 @@
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Extensions\PluginLocator.cs" />
|
||||
<Compile Include="IDbProvider.cs" />
|
||||
<Compile Include="ApiControllers\LapTrackApiModule.cs" />
|
||||
<Compile Include="ApiControllers\MonitorApiModule.cs" />
|
||||
|
||||
@ -72,10 +72,6 @@
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\IrDaemonNotifier\IrDaemonNotifier.csproj">
|
||||
<Project>{916994f6-1711-4aeb-8de6-4ab6fcb3f080}</Project>
|
||||
<Name>IrDaemonNotifier</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\NLogLogger\NLogLogger.csproj">
|
||||
<Project>{9a93a12f-7591-406a-a4f3-41aa8299c4b4}</Project>
|
||||
<Name>NLogLogger</Name>
|
||||
@ -84,10 +80,6 @@
|
||||
<Project>{85A3CC28-096C-40A6-8C67-3AADE40EDF32}</Project>
|
||||
<Name>RaceLapTimer</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\UdpNotifier\UdpNotifier.csproj">
|
||||
<Project>{734097b0-a764-40ad-957a-43fe4f085b65}</Project>
|
||||
<Name>UdpNotifier</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="..\packages\Nancy.Viewengines.Razor.1.4.3\build\Nancy.ViewEngines.Razor.targets" Condition="Exists('..\packages\Nancy.Viewengines.Razor.1.4.3\build\Nancy.ViewEngines.Razor.targets')" />
|
||||
|
||||
Loading…
Reference in New Issue
Block a user