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/**
|
**/.vs/**
|
||||||
**dotsettings
|
**dotsettings
|
||||||
**.DotSettings.user
|
**.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="IConfigFilePathProvider.cs" />
|
||||||
<Compile Include="IContainerHelper.cs" />
|
<Compile Include="IContainerHelper.cs" />
|
||||||
<Compile Include="ILoggerService.cs" />
|
<Compile Include="ILoggerService.cs" />
|
||||||
|
<Compile Include="IPluginLocator.cs" />
|
||||||
<Compile Include="IPluginPathProvider.cs" />
|
<Compile Include="IPluginPathProvider.cs" />
|
||||||
<Compile Include="ConfigurationSetting.cs" />
|
<Compile Include="ConfigurationSetting.cs" />
|
||||||
<Compile Include="CompetitionRace.cs" />
|
<Compile Include="CompetitionRace.cs" />
|
||||||
|
|||||||
@ -10,6 +10,7 @@ using Nancy.Diagnostics;
|
|||||||
using Nancy.TinyIoc;
|
using Nancy.TinyIoc;
|
||||||
using Ninject;
|
using Ninject;
|
||||||
using RaceLapTimer.ApiControllers;
|
using RaceLapTimer.ApiControllers;
|
||||||
|
using RaceLapTimer.Extensions;
|
||||||
using RaceLapTimer.Extensions.Notifications;
|
using RaceLapTimer.Extensions.Notifications;
|
||||||
|
|
||||||
namespace RaceLapTimer
|
namespace RaceLapTimer
|
||||||
@ -30,14 +31,16 @@ namespace RaceLapTimer
|
|||||||
container.Bind<IPluginPathProvider>().To<PluginPathProvider>();
|
container.Bind<IPluginPathProvider>().To<PluginPathProvider>();
|
||||||
container.Bind<IConfigFilePathProvider>().To<ConfigFilePathProvider>();
|
container.Bind<IConfigFilePathProvider>().To<ConfigFilePathProvider>();
|
||||||
container.Bind<IContainerHelper>().To<ContainerHelper>();
|
container.Bind<IContainerHelper>().To<ContainerHelper>();
|
||||||
container.Bind<INotifierManager>().To<NotificationManager>().InSingletonScope();
|
|
||||||
container.Bind<IDbProvider>().To<TestProvider>().InSingletonScope();
|
container.Bind<IDbProvider>().To<TestProvider>().InSingletonScope();
|
||||||
|
container.Bind<IPluginLocator>().To<PluginLocator>();
|
||||||
//load dynamic plugins..:
|
//load dynamic plugins..:
|
||||||
var cfgFilePath = Path.Combine(container.Get<IConfigFilePathProvider>().GetPath, "NinjectConfig.xml");
|
var cfgFilePath = Path.Combine(container.Get<IConfigFilePathProvider>().GetPath, "NinjectConfig.xml");
|
||||||
|
|
||||||
container.Load(cfgFilePath);
|
container.Load(cfgFilePath);
|
||||||
|
|
||||||
|
container.Bind<INotifierManager>().To<NotificationManager>().InSingletonScope();
|
||||||
|
|
||||||
|
|
||||||
var nM = container.Get<INotifierManager>();
|
var nM = container.Get<INotifierManager>();
|
||||||
nM.NotifyRaceStarted(new NotificationEventArgs());
|
nM.NotifyRaceStarted(new NotificationEventArgs());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,8 +4,6 @@ using System.Diagnostics;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Security.Cryptography.X509Certificates;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Interfaces;
|
using Interfaces;
|
||||||
|
|
||||||
@ -14,27 +12,11 @@ namespace RaceLapTimer.Extensions.Notifications
|
|||||||
class NotificationManager : INotifierManager
|
class NotificationManager : INotifierManager
|
||||||
{
|
{
|
||||||
private readonly List<INotifierProvider> _providers;
|
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 providerFactories = locator.Locate<INotifierProviderFactory>();
|
||||||
var files = Directory.GetFiles(pluginPath.GetPluginPath);
|
|
||||||
|
|
||||||
foreach (var file in files)
|
//var providerFactories = helper.GetAll<INotifierProviderFactory>().ToList();
|
||||||
{
|
|
||||||
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();
|
|
||||||
_providers = new List<INotifierProvider>();
|
_providers = new List<INotifierProvider>();
|
||||||
foreach (var factory in providerFactories)
|
foreach (var factory in providerFactories)
|
||||||
{
|
{
|
||||||
@ -108,5 +90,13 @@ namespace RaceLapTimer.Extensions.Notifications
|
|||||||
}
|
}
|
||||||
return false;
|
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" />
|
<Reference Include="System.Xml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="Extensions\PluginLocator.cs" />
|
||||||
<Compile Include="IDbProvider.cs" />
|
<Compile Include="IDbProvider.cs" />
|
||||||
<Compile Include="ApiControllers\LapTrackApiModule.cs" />
|
<Compile Include="ApiControllers\LapTrackApiModule.cs" />
|
||||||
<Compile Include="ApiControllers\MonitorApiModule.cs" />
|
<Compile Include="ApiControllers\MonitorApiModule.cs" />
|
||||||
|
|||||||
@ -72,10 +72,6 @@
|
|||||||
<None Include="packages.config" />
|
<None Include="packages.config" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\IrDaemonNotifier\IrDaemonNotifier.csproj">
|
|
||||||
<Project>{916994f6-1711-4aeb-8de6-4ab6fcb3f080}</Project>
|
|
||||||
<Name>IrDaemonNotifier</Name>
|
|
||||||
</ProjectReference>
|
|
||||||
<ProjectReference Include="..\NLogLogger\NLogLogger.csproj">
|
<ProjectReference Include="..\NLogLogger\NLogLogger.csproj">
|
||||||
<Project>{9a93a12f-7591-406a-a4f3-41aa8299c4b4}</Project>
|
<Project>{9a93a12f-7591-406a-a4f3-41aa8299c4b4}</Project>
|
||||||
<Name>NLogLogger</Name>
|
<Name>NLogLogger</Name>
|
||||||
@ -84,10 +80,6 @@
|
|||||||
<Project>{85A3CC28-096C-40A6-8C67-3AADE40EDF32}</Project>
|
<Project>{85A3CC28-096C-40A6-8C67-3AADE40EDF32}</Project>
|
||||||
<Name>RaceLapTimer</Name>
|
<Name>RaceLapTimer</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
<ProjectReference Include="..\UdpNotifier\UdpNotifier.csproj">
|
|
||||||
<Project>{734097b0-a764-40ad-957a-43fe4f085b65}</Project>
|
|
||||||
<Name>UdpNotifier</Name>
|
|
||||||
</ProjectReference>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<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')" />
|
<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