This commit is contained in:
Thomas Peterson 2024-11-28 19:02:53 +01:00
parent d0352818f0
commit aa91e0049f
611 changed files with 813 additions and 17878 deletions

View File

@ -11,6 +11,7 @@
<entry key="PSCHelpdesk/PSCHelpdesk/LightTheme.axaml" value="PSCHelpdesk/PSCHelpdesk.Desktop/PSCHelpdesk.Desktop.csproj" />
<entry key="PSCHelpdesk/PSCHelpdesk/Toasts/Display/ToastHolder.axaml" value="PSCHelpdesk/PSCHelpdesk.Desktop/PSCHelpdesk.Desktop.csproj" />
<entry key="PSCHelpdesk/PSCHelpdesk/Toasts/Display/ToastNotification.axaml" value="PSCHelpdesk/PSCHelpdesk.Desktop/PSCHelpdesk.Desktop.csproj" />
<entry key="PSCHelpdesk/PSCHelpdesk/ViewModels/TestTemplateControl.axaml" value="PSCHelpdesk/PSCHelpdesk.Desktop/PSCHelpdesk.Desktop.csproj" />
<entry key="PSCHelpdesk/PSCHelpdesk/Views/ContentDisplay.axaml" value="PSCHelpdesk/PSCHelpdesk.Desktop/PSCHelpdesk.Desktop.csproj" />
<entry key="PSCHelpdesk/PSCHelpdesk/Views/ContentDisplayView.axaml" value="PSCHelpdesk/PSCHelpdesk.Browser/PSCHelpdesk.Browser.csproj" />
<entry key="PSCHelpdesk/PSCHelpdesk/Views/MainDockWindow.axaml" value="PSCHelpdesk/PSCHelpdesk.Desktop/PSCHelpdesk.Desktop.csproj" />

View File

@ -13,23 +13,610 @@
<list default="true" id="95257dc5-08bd-4c50-8726-85956b3c2c92" name="Changes" comment="">
<change beforePath="$PROJECT_DIR$/.idea/.idea.PSCHelpdesk/.idea/avalonia.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.PSCHelpdesk/.idea/avalonia.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/.idea.PSCHelpdesk/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.PSCHelpdesk/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/HetznerServer/HetznerServer.cs" beforeDir="false" afterPath="$PROJECT_DIR$/HetznerServer/HetznerServer.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/HetznerServer/ViewModels/ServerViewModel.cs" beforeDir="false" afterPath="$PROJECT_DIR$/HetznerServer/ViewModels/ServerViewModel.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/PSCHelpdesk.sln.DotSettings.user" beforeDir="false" afterPath="$PROJECT_DIR$/PSCHelpdesk.sln.DotSettings.user" afterDir="false" />
<change beforePath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/App.axaml.cs" beforeDir="false" afterPath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/App.axaml.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/Converter/AvaloniaPluginResultConverter.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/PSCHelpdesk.csproj" beforeDir="false" afterPath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/PSCHelpdesk.csproj" afterDir="false" />
<change beforePath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/Services/PluginService.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/Startup.cs" beforeDir="false" afterPath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/Startup.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/ViewModels/MainDockWindowViewModel.cs" beforeDir="false" afterPath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/ViewModels/MainDockWindowViewModel.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/ViewModels/MainWindowViewModel.cs" beforeDir="false" afterPath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/ViewModels/MainWindowViewModel.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/ViewModels/PluginListViewModel.cs" beforeDir="false" afterPath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/ViewModels/PluginListViewModel.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/Views/MainDockWindow.axaml" beforeDir="false" afterPath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/Views/MainDockWindow.axaml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/Views/MainDockWindow.axaml.cs" beforeDir="false" afterPath="$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/Views/MainDockWindow.axaml.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Shared/Setting/SettingsManager.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Shared/Setting/SettingsManager.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Shared/Shared.csproj" beforeDir="false" afterPath="$PROJECT_DIR$/Shared/Shared.csproj" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Shared/ViewModels/ViewModelBase.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Shared/ViewModels/ViewModelBase.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/_dist/hetzner/HetznerServer.deps.json" beforeDir="false" afterPath="$PROJECT_DIR$/_dist/hetzner/HetznerServer.deps.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Mvc/ApplicationBuilderExtensions.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Mvc/DefaultMvcPluginLoader.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Mvc/DefaultMvcRazorPluginLoader.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Mvc/DefaultPriseMvcActionDescriptorChangeProvider.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Mvc/DefaultPriseMvcControllerActivator.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Mvc/DefaultPrisePluginViewsAssemblyFileProvider.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Mvc/DefaultStaticPluginCacheAccessor.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Mvc/DefaultStaticPluginCacheAccessorBootstrapper.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Mvc/IMvcPluginLoader.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Mvc/IPluginCacheAccessorBootstrapper.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Mvc/IPriseMvcActionDescriptorChangeProvider.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Mvc/PluginAssemblyPart.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Mvc/Prise.Mvc.csproj" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Mvc/PriseMvcExtensions.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Plugin/BootstrapperServiceAttribute.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Plugin/IPluginBootstrapper.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Plugin/PluginActivatedAttribute.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Plugin/PluginAttribute.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Plugin/PluginBootstrapperAttribute.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Plugin/PluginFactoryAttribute.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Plugin/PluginServiceAttribute.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Plugin/Prise.Plugin.csproj" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Plugin/ProvidedBy.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Proxy/Infrastructure/IParameterConverter.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Proxy/Infrastructure/IResultConverter.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Proxy/Method.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Proxy/MethodFindingStrategy.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Proxy/Parameter.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Proxy/PassthroughParameterConverter.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Proxy/PassthroughResultConverter.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Proxy/Prise.Proxy.csproj" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Proxy/PriseProxy.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Proxy/PriseProxyException.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Proxy/ProxyCreator.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Proxy/ResultConverter.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Proxy/TaskCompletionSource.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Proxy/runtime/DispatchProxy.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Proxy/runtime/DispatchProxyGenerator.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Proxy/runtime/IngoreAccessChecksToAttributeBuilder.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.ReverseProxy/Prise.ReverseProxy.csproj" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.ReverseProxy/ReverseProxy.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.ReverseProxy/ReverseProxyException.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Testing/Prise.Testing.csproj" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Testing/Testing.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/.vscode/launch.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/.vscode/tasks.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/FileBulkDateChanger/FileBulkDateChanger.deps.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/FileBulkDateChanger/FileBulkDateChanger.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/FileBulkDateChanger/FileBulkDateChanger.exe" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/FileBulkDateChanger/FileBulkDateChanger.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/FileBulkDateChanger/FileBulkDateChanger.runtimeconfig.dev.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/FileBulkDateChanger/FileBulkDateChanger.runtimeconfig.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/IntegrationTestsPlugins/DomainForPluginC/DomainForPluginC.csproj" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/IntegrationTestsPlugins/DomainForPluginC/IDiscount.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/IntegrationTestsPlugins/DomainForPluginC/IDiscountService.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/IntegrationTestsPlugins/PluginA/AdditionCalculationPlugin.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/IntegrationTestsPlugins/PluginA/PluginA.csproj" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/IntegrationTestsPlugins/PluginA/PluginA.net2.csproj" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/IntegrationTestsPlugins/PluginA/ZAdditionPlusOneCalculationPlugin.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/IntegrationTestsPlugins/PluginA/prise.plugin.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/IntegrationTestsPlugins/PluginB/PluginB.csproj" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/IntegrationTestsPlugins/PluginB/PluginB.net2.csproj" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/IntegrationTestsPlugins/PluginB/SubtractionCalculationPlugin.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/IntegrationTestsPlugins/PluginB/prise.plugin.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/IntegrationTestsPlugins/PluginC/Calculations/ICanCalculate.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/IntegrationTestsPlugins/PluginC/DivideOrMultiplyCalculationBootstrapper.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/IntegrationTestsPlugins/PluginC/DivideOrMultiplyCalculationPlugin.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/IntegrationTestsPlugins/PluginC/PluginC.csproj" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/IntegrationTestsPlugins/PluginC/PluginC.net2.csproj" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/IntegrationTestsPlugins/PluginC/prise.plugin.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTests/AppHostCollection.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTests/AppHostWebApplicationFactory.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTests/AppHostWebApplicationFactory.netcore2.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTests/AppHostWebApplicationFactory.netcore3.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTests/BreakTheServerTests.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTests/CalculationPluginTestsBase.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTests/CalculationTests.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTests/DiscoTests.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTests/MultipleTests.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTests/PluginTestBase.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTests/Prise.IntegrationTests.csproj" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTests/Properties/launchSettings.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTests/SadPathTests.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsContract/CalculationContext.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsContract/CalculationResult.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsContract/ComplexCalculationContext.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsContract/ComplexCalculationResult.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsContract/IAuthenticatedDataService.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsContract/ICalculationPlugin.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsContract/INetworkCalculationPlugin.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsContract/IPluginWithSerializer.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsContract/ITokenService.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsContract/ITranslationPlugin.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsContract/Prise.IntegrationTestsContract.csproj" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsHost/Controllers/CalculationController.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsHost/Controllers/CalculationControllerBase.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsHost/Controllers/DiscoveryController.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsHost/Controllers/MultipleCalculationController.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsHost/Custom/AppHostFrameworkProvider.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsHost/ICommandLineArguments.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsHost/Models/CalculationRequestModel.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsHost/Models/CalculationRequestMultiModel.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsHost/Models/CalculationResponseModel.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsHost/PluginLoaders/CalculationPluginLoader.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsHost/Prise.IntegrationTestsHost.csproj" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsHost/Program.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsHost/Program.netcore2.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsHost/Program.netcore3.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsHost/Properties/launchSettings.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsHost/Services/ICalculationService.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsHost/Startup.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsHost/Startup.netcore2.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsHost/Startup.netcore3.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsHost/appsettings.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsHost/data.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsHost/dictionary-de-DE.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsHost/dictionary-fr-FR.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsHost/dictionary-nl-BE.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsHost/http/Calculations.http" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsHost/http/Disco.http" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/Prise.IntegrationTestsHost/tokens.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/build.cake" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginD/Dictionary.Domain.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginD/Dictionary.Domain.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginD/ExternalServiceForPluginD.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginD/ExternalServiceForPluginD.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginD/Microsoft.Extensions.Configuration.Abstractions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginD/Microsoft.Extensions.DependencyInjection.Abstractions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginD/Microsoft.Extensions.DependencyInjection.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginD/Microsoft.Extensions.Primitives.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginD/Newtonsoft.Json.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginD/PluginD.deps.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginD/PluginD.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginD/PluginD.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginD/Prise.IntegrationTestsContract.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginD/Prise.IntegrationTestsContract.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginD/Prise.Plugin.net2.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginD/Prise.Plugin.net2.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginD/Prise.PluginBridge.net2.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginD/Prise.PluginBridge.net2.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginD/System.Runtime.CompilerServices.Unsafe.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginE/Microsoft.Extensions.DependencyInjection.Abstractions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginE/Microsoft.Extensions.DependencyInjection.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginE/Newtonsoft.Json.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginE/PluginE.deps.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginE/PluginE.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginE/PluginE.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginE/Prise.IntegrationTestsContract.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginE/Prise.IntegrationTestsContract.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginE/Prise.Plugin.net2.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginE/Prise.Plugin.net2.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginF/Microsoft.Bcl.AsyncInterfaces.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginF/Microsoft.Extensions.DependencyInjection.Abstractions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginF/Microsoft.Extensions.DependencyInjection.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginF/PluginF.deps.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginF/PluginF.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginF/PluginF.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginF/Prise.IntegrationTestsContract.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginF/Prise.IntegrationTestsContract.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginF/Prise.Plugin.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginF/Prise.Plugin.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginF/System.Runtime.CompilerServices.Unsafe.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginF/System.Text.Encodings.Web.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginF/System.Text.Json.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginF/XmlSerializerLib.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginF/XmlSerializerLib.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginG.1.0.0.nupkg" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginG/Dictionary.Domain.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginG/Dictionary.Domain.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginG/ExternalServiceForPluginD.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginG/ExternalServiceForPluginD.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginG/Microsoft.Extensions.Configuration.Abstractions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginG/Microsoft.Extensions.DependencyInjection.Abstractions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginG/Microsoft.Extensions.DependencyInjection.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginG/Microsoft.Extensions.Primitives.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginG/Newtonsoft.Json.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginG/PluginG.deps.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginG/PluginG.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginG/PluginG.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginG/Prise.IntegrationTestsContract.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginG/Prise.IntegrationTestsContract.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginG/Prise.Plugin.net2.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginG/Prise.Plugin.net2.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginG/Prise.PluginBridge.net2.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginG/Prise.PluginBridge.net2.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp2.1/PluginG/System.Runtime.CompilerServices.Unsafe.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginD/Dictionary.Domain.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginD/Dictionary.Domain.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginD/ExternalServiceForPluginD.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginD/ExternalServiceForPluginD.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginD/Microsoft.Extensions.Configuration.Abstractions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginD/Microsoft.Extensions.DependencyInjection.Abstractions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginD/Microsoft.Extensions.DependencyInjection.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginD/Microsoft.Extensions.Primitives.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginD/Newtonsoft.Json.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginD/PluginD.deps.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginD/PluginD.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginD/PluginD.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginD/Prise.IntegrationTestsContract.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginD/Prise.IntegrationTestsContract.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginD/Prise.Plugin.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginD/Prise.Plugin.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginD/Prise.PluginBridge.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginD/Prise.PluginBridge.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginE/Microsoft.Extensions.DependencyInjection.Abstractions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginE/Microsoft.Extensions.DependencyInjection.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginE/Newtonsoft.Json.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginE/PluginE.deps.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginE/PluginE.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginE/PluginE.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginE/Prise.IntegrationTestsContract.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginE/Prise.IntegrationTestsContract.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginE/Prise.Plugin.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginE/Prise.Plugin.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginF/Microsoft.Extensions.DependencyInjection.Abstractions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginF/Microsoft.Extensions.DependencyInjection.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginF/PluginF.deps.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginF/PluginF.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginF/PluginF.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginF/Prise.IntegrationTestsContract.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginF/Prise.IntegrationTestsContract.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginF/Prise.Plugin.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginF/Prise.Plugin.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginF/XmlSerializerLib.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginF/XmlSerializerLib.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginG.1.0.0.nupkg" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginG/Dictionary.Domain.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginG/Dictionary.Domain.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginG/ExternalServiceForPluginD.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginG/ExternalServiceForPluginD.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginG/Microsoft.Extensions.Configuration.Abstractions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginG/Microsoft.Extensions.DependencyInjection.Abstractions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginG/Microsoft.Extensions.DependencyInjection.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginG/Microsoft.Extensions.Primitives.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginG/Newtonsoft.Json.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginG/PluginG.deps.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginG/PluginG.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginG/PluginG.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginG/Prise.IntegrationTestsContract.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginG/Prise.IntegrationTestsContract.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginG/Prise.Plugin.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginG/Prise.Plugin.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginG/Prise.PluginBridge.net3.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.0/PluginG/Prise.PluginBridge.net3.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginD/Dictionary.Domain.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginD/Dictionary.Domain.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginD/ExternalServiceForPluginD.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginD/ExternalServiceForPluginD.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginD/Microsoft.Extensions.Configuration.Abstractions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginD/Microsoft.Extensions.DependencyInjection.Abstractions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginD/Microsoft.Extensions.DependencyInjection.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginD/Microsoft.Extensions.Primitives.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginD/Newtonsoft.Json.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginD/PluginD.deps.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginD/PluginD.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginD/PluginD.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginD/Prise.IntegrationTestsContract.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginD/Prise.IntegrationTestsContract.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginD/Prise.Plugin.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginD/Prise.Plugin.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginD/Prise.PluginBridge.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginD/Prise.PluginBridge.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginE/Microsoft.Extensions.DependencyInjection.Abstractions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginE/Microsoft.Extensions.DependencyInjection.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginE/Newtonsoft.Json.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginE/PluginE.deps.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginE/PluginE.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginE/PluginE.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginE/Prise.IntegrationTestsContract.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginE/Prise.IntegrationTestsContract.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginE/Prise.Plugin.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginE/Prise.Plugin.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginF/Microsoft.Extensions.DependencyInjection.Abstractions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginF/Microsoft.Extensions.DependencyInjection.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginF/PluginF.deps.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginF/PluginF.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginF/PluginF.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginF/Prise.IntegrationTestsContract.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginF/Prise.IntegrationTestsContract.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginF/Prise.Plugin.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginF/Prise.Plugin.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginF/XmlSerializerLib.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginF/XmlSerializerLib.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginG.1.0.0.nupkg" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginG/Dictionary.Domain.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginG/Dictionary.Domain.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginG/ExternalServiceForPluginD.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginG/ExternalServiceForPluginD.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginG/Microsoft.Extensions.Configuration.Abstractions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginG/Microsoft.Extensions.DependencyInjection.Abstractions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginG/Microsoft.Extensions.DependencyInjection.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginG/Microsoft.Extensions.Primitives.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginG/Newtonsoft.Json.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginG/PluginG.deps.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginG/PluginG.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginG/PluginG.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginG/Prise.IntegrationTestsContract.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginG/Prise.IntegrationTestsContract.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginG/Prise.Plugin.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginG/Prise.Plugin.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginG/Prise.PluginBridge.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netcoreapp3.1/PluginG/Prise.PluginBridge.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.4/Legacy.Contract.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.4/Legacy.Domain.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.4/Legacy.Domain.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.4/LegacyPlugin.deps.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.4/LegacyPlugin.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.4/LegacyPlugin.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.4/Microsoft.CSharp.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.4/Microsoft.Extensions.Configuration.Abstractions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.4/Microsoft.Extensions.DependencyInjection.Abstractions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.4/Microsoft.Extensions.DependencyInjection.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.4/Microsoft.Extensions.Primitives.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.4/Newtonsoft.Json.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.4/Prise.Plugin.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.4/System.Buffers.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.4/System.Dynamic.Runtime.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.4/System.IO.FileSystem.Primitives.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.4/System.Linq.Expressions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.4/System.Linq.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.4/System.Memory.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.4/System.Numerics.Vectors.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.4/System.ObjectModel.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.4/System.Reflection.Emit.ILGeneration.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.4/System.Reflection.Emit.Lightweight.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.4/System.Reflection.Emit.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.4/System.Reflection.TypeExtensions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.4/System.Runtime.CompilerServices.Unsafe.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.4/System.Runtime.Serialization.Primitives.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.4/System.Text.RegularExpressions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.4/System.Threading.Tasks.Extensions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.4/System.Threading.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.4/System.Xml.ReaderWriter.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.4/System.Xml.XDocument.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.5/Legacy.Contract.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.5/Legacy.Domain.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.5/Legacy.Domain.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.5/LegacyPlugin.deps.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.5/LegacyPlugin.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.5/LegacyPlugin.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.5/Microsoft.CSharp.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.5/Microsoft.Extensions.Configuration.Abstractions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.5/Microsoft.Extensions.DependencyInjection.Abstractions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.5/Microsoft.Extensions.DependencyInjection.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.5/Microsoft.Extensions.Primitives.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.5/Newtonsoft.Json.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.5/Prise.Plugin.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.5/System.Buffers.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.5/System.Dynamic.Runtime.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.5/System.IO.FileSystem.Primitives.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.5/System.Linq.Expressions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.5/System.Linq.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.5/System.Memory.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.5/System.Numerics.Vectors.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.5/System.ObjectModel.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.5/System.Reflection.Emit.ILGeneration.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.5/System.Reflection.Emit.Lightweight.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.5/System.Reflection.Emit.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.5/System.Reflection.TypeExtensions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.5/System.Runtime.CompilerServices.Unsafe.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.5/System.Runtime.Serialization.Primitives.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.5/System.Text.RegularExpressions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.5/System.Threading.Tasks.Extensions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.5/System.Threading.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.5/System.Xml.ReaderWriter.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/LegacyPlugin1.5/System.Xml.XDocument.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/PluginA/Microsoft.Extensions.DependencyInjection.Abstractions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/PluginA/Microsoft.Extensions.DependencyInjection.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/PluginA/PluginA.deps.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/PluginA/PluginA.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/PluginA/PluginA.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/PluginA/Prise.IntegrationTestsContract.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/PluginA/Prise.IntegrationTestsContract.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/PluginA/Prise.Plugin.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/PluginA/Prise.Plugin.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/PluginB/Microsoft.Extensions.DependencyInjection.Abstractions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/PluginB/Microsoft.Extensions.DependencyInjection.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/PluginB/PluginB.deps.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/PluginB/PluginB.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/PluginB/PluginB.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/PluginB/Prise.IntegrationTestsContract.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/PluginB/Prise.IntegrationTestsContract.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/PluginB/Prise.Plugin.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/PluginB/Prise.Plugin.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/PluginC/DomainForPluginC.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/PluginC/DomainForPluginC.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/PluginC/Microsoft.Extensions.DependencyInjection.Abstractions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/PluginC/Microsoft.Extensions.DependencyInjection.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/PluginC/PluginC.deps.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/PluginC/PluginC.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/PluginC/PluginC.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/PluginC/Prise.IntegrationTestsContract.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/PluginC/Prise.IntegrationTestsContract.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/PluginC/Prise.Plugin.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.0/PluginC/Prise.Plugin.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginA/Microsoft.Extensions.DependencyInjection.Abstractions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginA/Microsoft.Extensions.DependencyInjection.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginA/PluginA.deps.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginA/PluginA.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginA/PluginA.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginA/Prise.IntegrationTestsContract.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginA/Prise.IntegrationTestsContract.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginA/Prise.Plugin.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginA/Prise.Plugin.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginB/Microsoft.Extensions.DependencyInjection.Abstractions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginB/Microsoft.Extensions.DependencyInjection.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginB/PluginB.deps.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginB/PluginB.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginB/PluginB.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginB/Prise.IntegrationTestsContract.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginB/Prise.IntegrationTestsContract.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginB/Prise.Plugin.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginB/Prise.Plugin.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginDWithFactory/Dictionary.Domain.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginDWithFactory/Dictionary.Domain.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginDWithFactory/ExternalServiceForPluginD.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginDWithFactory/ExternalServiceForPluginD.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginDWithFactory/Microsoft.Bcl.AsyncInterfaces.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginDWithFactory/Microsoft.Extensions.Configuration.Abstractions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginDWithFactory/Microsoft.Extensions.DependencyInjection.Abstractions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginDWithFactory/Microsoft.Extensions.DependencyInjection.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginDWithFactory/Microsoft.Extensions.Primitives.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginDWithFactory/Newtonsoft.Json.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginDWithFactory/PluginD.deps.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginDWithFactory/PluginD.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginDWithFactory/PluginD.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginDWithFactory/Prise.IntegrationTestsContract.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginDWithFactory/Prise.IntegrationTestsContract.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginDWithFactory/Prise.Plugin.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginDWithFactory/Prise.Plugin.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginDWithFactory/Prise.PluginBridge.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginDWithFactory/Prise.PluginBridge.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginDWithFactory/System.Buffers.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginDWithFactory/System.Memory.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginDWithFactory/System.Numerics.Vectors.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginDWithFactory/System.Reflection.DispatchProxy.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginDWithFactory/System.Runtime.CompilerServices.Unsafe.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginDWithFactory/System.Text.Encodings.Web.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginDWithFactory/System.Text.Json.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginDWithFactory/System.Threading.Tasks.Extensions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginE/Microsoft.Bcl.AsyncInterfaces.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginE/Microsoft.Extensions.DependencyInjection.Abstractions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginE/Microsoft.Extensions.DependencyInjection.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginE/PluginE.deps.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginE/PluginE.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginE/PluginE.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginE/Prise.IntegrationTestsContract.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginE/Prise.IntegrationTestsContract.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginE/Prise.Plugin.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginE/Prise.Plugin.pdb" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginE/System.Buffers.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginE/System.Memory.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginE/System.Numerics.Vectors.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginE/System.Runtime.CompilerServices.Unsafe.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginE/System.Text.Encodings.Web.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginE/System.Text.Json.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginE/System.Threading.Tasks.Extensions.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests.Integration/compatibility/netstandard2.1/PluginG.1.0.0.nupkg" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/.vscode/settings.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/Activation/DefaultPluginActivationContextProviderTests.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/Assemblies/Newtonsoft.Json.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/Assemblies/Prise.Tests.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/Assemblies/en-GB/Newtonsoft.Json.dll" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/Assemblies/libsos.so" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/AssemblyLoading/DefaultAssemblyLoadContextTests/Base.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/AssemblyLoading/DefaultAssemblyLoadContextTests/DefaultAssemblyLoadContextTests_Ctor.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/AssemblyLoading/DefaultAssemblyLoadContextTests/DefaultAssemblyLoadContextTests_Load.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/AssemblyLoading/DefaultAssemblyLoadContextTests/DefaultAssemblyLoadContextTests_LoadFromDefaultContext.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/AssemblyLoading/DefaultAssemblyLoadContextTests/DefaultAssemblyLoadContextTests_LoadFromDependencyContext.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/AssemblyLoading/DefaultAssemblyLoadContextTests/DefaultAssemblyLoadContextTests_LoadFromRemote.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/AssemblyLoading/DefaultAssemblyLoadContextTests/DefaultAssemblyLoadContextTests_LoadPluginAssembly.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/AssemblyLoading/DefaultAssemblyLoadContextTests/DefaultAssemblyLoadContextTests_LoadUnmanagedDll.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/AssemblyLoading/DefaultAssemblyLoadContextTests/DefaultAssemblyLoadContextTests_LoadUnmanagedFromDefault.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/AssemblyLoading/DefaultAssemblyLoadContextTests/DefaultAssemblyLoadContextTests_LoadUnmanagedFromDependencyContext.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/AssemblyLoading/DefaultAssemblyLoadContextTests/DefaultAssemblyLoadContextTests_LoadUnmanagedFromRemote.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/AssemblyLoading/DefaultAssemblyLoadStrategyTests.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/AssemblyLoading/DefaultAssemblyLoaderTests.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/AssemblyScanning/DefaultAssemblyScannerTests.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/AssemblyScanning/DefaultNugetPackageAssemblyScannerTests.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/Caching/DefaultScopedPluginCacheTests.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/Core/DefaultPluginTypeSelectorTests.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/IMyService.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/MyService.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/Platform/DefaultRuntimePlatformContextTests.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/Plugins/ITestPlugin.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/Plugins/TestPluginA.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/Plugins/TestPluginActivation.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/Plugins/TestType.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/Prise.Tests.csproj" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/Proxy/ProxyTests.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/ReverseProxy/MyServiceProxy.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/ReverseProxy/ReverseProxyTests.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/TestBase.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/TestContext.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/TestData.json" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise.Tests/TestFile.txt" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Activation/DefaultPluginActivationContext.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Activation/DefaultPluginActivationContextProvider.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Activation/DefaultPluginActivationOptions.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Activation/DefaultPluginActivator.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Activation/DefaultPluginProxyCreator.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Activation/DefaultPluginServiceProvider.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Activation/DefaultRemotePluginActivator.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Activation/IPluginActivationContext.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Activation/IPluginActivationContextProvider.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Activation/IPluginActivationOptions.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Activation/IPluginActivator.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Activation/IPluginProxyCreator.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Activation/IPluginServiceProvider.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Activation/IRemotePluginActivator.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Activation/PluginActivationException.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Activation/PluginService.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyLoading/AssemblyFromStrategy.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyLoading/AssemblyLoadException.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyLoading/DefaultAssemblyDependencyResolver.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyLoading/DefaultAssemblyLoadContext.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyLoading/DefaultAssemblyLoadStrategy.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyLoading/DefaultAssemblyLoader.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyLoading/DefaultNativeAssemblyUnloader.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyLoading/DefaultPluginDependencyContext.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyLoading/DefaultPluginDependencyResolver.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyLoading/HostDependency.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyLoading/IAssemblyDependencyResolver.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyLoading/IAssemblyLoadContext.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyLoading/IAssemblyLoadStrategy.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyLoading/IAssemblyLoader.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyLoading/INativeAssemblyUnloader.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyLoading/IPluginDependencyContext.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyLoading/IPluginDependencyResolver.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyLoading/IRuntimeDefaultAssemblyContext.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyLoading/InMemoryAssemblyLoadContext.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyLoading/NativeAssembly.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyLoading/PlatformDependency.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyLoading/PluginDependency.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyLoading/PluginResourceDependency.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyLoading/RemoteDependency.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyLoading/RuntimeAssemblyShim.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyLoading/RuntimeDefaultAssemblyContext.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyLoading/RuntimeLoadFlag.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyLoading/ValueOrProceed.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyScanning/AssemblyScannerOptions.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyScanning/AssemblyScanningException.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyScanning/DefaultAssemblyResolver.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyScanning/DefaultAssemblyScanner.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyScanning/DefaultMetadataLoadContext.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyScanning/DefaultNugetPackageAssemblyScanner.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyScanning/DefaultNugetPackageUtilities.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyScanning/IAssemblyScanner.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyScanning/IAssemblyScannerOptions.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyScanning/IMetadataLoadContext.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyScanning/INugetPackageUtilities.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/AssemblyScanning/PluginNugetPackage.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Caching/CachedPluginAssembly.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Caching/DefaultScopedPluginCache.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Caching/ICachedPluginAssembly.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Caching/IPluginCache.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Core/AssemblyScanResult.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Core/DefaultDirectoryTraverser.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Core/DefaultFileSystemUtilities.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Core/DefaultPluginTypeSelector.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Core/IAssemblyShim.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Core/IDirectoryTraverser.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Core/IFileSystemUtilities.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Core/IPluginLoadContext.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Core/IPluginTypeSelector.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Core/IRuntimePlatformContext.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Core/NativeDependencyLoadPreference.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Core/PluginLoadContext.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Core/PluginLoadContextExtensions.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Core/PluginPlatformVersion.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Core/PriseAssembly.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Core/Runtime.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Core/RuntimeInfo.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Core/RuntimeType.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/DefaultPluginLoader.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/DependencyInjection/DefaultFactories.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/DependencyInjection/PriseDependencyInjectionException.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/DependencyInjection/ServiceCollectionExtensions.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/IPluginLoader.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Infrastructure/JsonSerializerParameterConverter.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Infrastructure/JsonSerializerResultConverter.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Platform/DefaultRuntimePlatformContext.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Platform/IPlatformAbstraction.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Platform/PlatformException.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/PluginLoadException.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Prise.csproj" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Utils/HostFrameworkUtils.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Utils/LinqUtils.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Utils/ValidationUtils.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Vendor/Prise/Utils/ValueUtils.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/_dist/hetzner/HetznerServer.dll" beforeDir="false" afterPath="$PROJECT_DIR$/_dist/hetzner/HetznerServer.dll" afterDir="false" />
<change beforePath="$PROJECT_DIR$/_dist/hetzner/HetznerServer.pdb" beforeDir="false" afterPath="$PROJECT_DIR$/_dist/hetzner/HetznerServer.pdb" afterDir="false" />
<change beforePath="$PROJECT_DIR$/_dist/nextcloud/Nextcloud.deps.json" beforeDir="false" afterPath="$PROJECT_DIR$/_dist/nextcloud/Nextcloud.deps.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/_dist/nextcloud/Nextcloud.dll" beforeDir="false" afterPath="$PROJECT_DIR$/_dist/nextcloud/Nextcloud.dll" afterDir="false" />
<change beforePath="$PROJECT_DIR$/_dist/nextcloud/Nextcloud.pdb" beforeDir="false" afterPath="$PROJECT_DIR$/_dist/nextcloud/Nextcloud.pdb" afterDir="false" />
</list>
@ -45,9 +632,14 @@
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
<component name="HighlightingSettingsPerFile">
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/DecompilerCache/decompiler/8b4806d72c8e4cc3b55824ab34018d6a31600/03/4320f39c/IDockGroup.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/DecompilerCache/decompiler/8b4806d72c8e4cc3b55824ab34018d6a31600/06/4ff6aee3/RootDockGroup.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/DecompilerCache/decompiler/8b4806d72c8e4cc3b55824ab34018d6a31600/76/f4abce16/DockItem.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/DecompilerCache/decompiler/8b4806d72c8e4cc3b55824ab34018d6a31600/9a/c689be08/StackDockGroup.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/ca55e2cf16410d6583d46a0c9733075e7c0a9d8bff277747e638859b39c45/DockItemViewModel.cs" root0="SKIP_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/2854ce6d56c18d0d837d3a3ef9c4f2c7c77691fa3528c8394986ac7ce7719/StackFrameIterator.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/c2effb26f7ae7be40d323e1ace14b106724737392b02a71b51d42704a62f9/VMBase.cs" root0="SKIP_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/c47c13cca75e97617e947c6da5d1608f1132d40d0ac16d29274ae52f7d3527/IUniDockService.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/ca55e2cf16410d6583d46a0c9733075e7c0a9d8bff277747e638859b39c45/DockItemViewModel.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/fa3c59274a754721f822d1776be91c7ffdd37ff4219098396aa16ba1fc5447/Ioc.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/HetznerServer/ViewModels/ServerViewModel.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/HetznerServer/Views/ServerView.axaml" root0="FORCE_HIGHLIGHTING" />
@ -56,9 +648,6 @@
<setting file="file://$PROJECT_DIR$/Shared/IconPack/Icons/PackIconFontAwesomeDataFactory.cs" root0="SKIP_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Shared/IconPack/Icons/PackIconMaterialDataFactory.cs" root0="SKIP_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Shared/IconPack/Icons/PackIconMaterialKind.cs" root0="SKIP_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Vendor/Prise/AssemblyScanning/DefaultAssemblyResolver.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Vendor/Prise/DefaultPluginLoader.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Vendor/Prise/DependencyInjection/ServiceCollectionExtensions.cs" root0="FORCE_HIGHLIGHTING" />
</component>
<component name="InvalidFacetManager">
<ignored-facets>
@ -258,7 +847,9 @@
<workItem from="1732088722904" duration="10121000" />
<workItem from="1732263256084" duration="10035000" />
<workItem from="1732368344000" duration="2447000" />
<workItem from="1732522254277" duration="18965000" />
<workItem from="1732522254277" duration="19594000" />
<workItem from="1732700320617" duration="11387000" />
<workItem from="1732784667633" duration="9372000" />
</task>
<task id="LOCAL-00001" summary="Backup">
<option name="closed" value="true" />
@ -276,7 +867,15 @@
<option name="project" value="LOCAL" />
<updated>1732211861007</updated>
</task>
<option name="localTasksCounter" value="3" />
<task id="LOCAL-00003" summary="backup">
<option name="closed" value="true" />
<created>1732644534156</created>
<option name="number" value="00003" />
<option name="presentableId" value="LOCAL-00003" />
<option name="project" value="LOCAL" />
<updated>1732644534156</updated>
</task>
<option name="localTasksCounter" value="4" />
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
@ -298,7 +897,8 @@
<component name="VcsManagerConfiguration">
<option name="CLEAR_INITIAL_COMMIT_MESSAGE" value="true" />
<MESSAGE value="Backup" />
<option name="LAST_COMMIT_MESSAGE" value="Backup" />
<MESSAGE value="backup" />
<option name="LAST_COMMIT_MESSAGE" value="backup" />
</component>
<component name="XDebuggerManager">
<breakpoint-manager>
@ -401,17 +1001,95 @@
<option name="timeStamp" value="195" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DotNet Breakpoints">
<url>file://$PROJECT_DIR$/HetznerServer/ViewModels/ServerViewModel.cs</url>
<line>99</line>
<properties documentPath="C:\Users\boonkerz\RiderProjects\PSCHelpDesk\HetznerServer\ViewModels\ServerViewModel.cs" containingFunctionPresentation="Method 'saveServerSettings'">
<url>file://$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/Views/MainDockWindow.axaml.cs</url>
<line>43</line>
<properties documentPath="C:\Users\info\RiderProjects\pschelpdesk\PSCHelpdesk\PSCHelpdesk\Views\MainDockWindow.axaml.cs" containingFunctionPresentation="Lambda expression inside Constructor 'MainDockWindow'">
<startOffsets>
<option value="3585" />
<option value="1289" />
</startOffsets>
<endOffsets>
<option value="3628" />
<option value="1371" />
</endOffsets>
</properties>
<option name="timeStamp" value="204" />
<option name="timeStamp" value="207" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DotNet Breakpoints">
<url>file://$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/Views/MainDockWindow.axaml.cs</url>
<line>50</line>
<properties documentPath="C:\Users\info\RiderProjects\pschelpdesk\PSCHelpdesk\PSCHelpdesk\Views\MainDockWindow.axaml.cs" containingFunctionPresentation="Lambda expression inside Constructor 'MainDockWindow'">
<startOffsets>
<option value="1607" />
</startOffsets>
<endOffsets>
<option value="1608" />
</endOffsets>
</properties>
<option name="timeStamp" value="209" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DotNet Breakpoints">
<url>file://$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/Views/MainDockWindow.axaml.cs</url>
<line>60</line>
<properties documentPath="C:\Users\info\RiderProjects\pschelpdesk\PSCHelpdesk\PSCHelpdesk\Views\MainDockWindow.axaml.cs" containingFunctionPresentation="Lambda expression inside Constructor 'MainDockWindow'">
<startOffsets>
<option value="2029" />
</startOffsets>
<endOffsets>
<option value="2123" />
</endOffsets>
</properties>
<option name="timeStamp" value="210" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DotNet Breakpoints">
<url>file://$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/Views/MainDockWindow.axaml.cs</url>
<line>62</line>
<properties documentPath="C:\Users\info\RiderProjects\pschelpdesk\PSCHelpdesk\PSCHelpdesk\Views\MainDockWindow.axaml.cs" containingFunctionPresentation="Lambda expression inside Constructor 'MainDockWindow'">
<startOffsets>
<option value="2185" />
</startOffsets>
<endOffsets>
<option value="2278" />
</endOffsets>
</properties>
<option name="timeStamp" value="211" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DotNet Breakpoints">
<url>file://$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/Views/MainDockWindow.axaml.cs</url>
<line>64</line>
<properties documentPath="C:\Users\info\RiderProjects\pschelpdesk\PSCHelpdesk\PSCHelpdesk\Views\MainDockWindow.axaml.cs" containingFunctionPresentation="Lambda expression inside Constructor 'MainDockWindow'">
<startOffsets>
<option value="2309" />
</startOffsets>
<endOffsets>
<option value="2336" />
</endOffsets>
</properties>
<option name="timeStamp" value="212" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DotNet Breakpoints">
<url>file://$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/Views/MainDockWindow.axaml.cs</url>
<line>67</line>
<properties documentPath="C:\Users\info\RiderProjects\pschelpdesk\PSCHelpdesk\PSCHelpdesk\Views\MainDockWindow.axaml.cs" containingFunctionPresentation="Lambda expression inside Constructor 'MainDockWindow'">
<startOffsets>
<option value="2380" />
</startOffsets>
<endOffsets>
<option value="2643" />
</endOffsets>
</properties>
<option name="timeStamp" value="215" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DotNet Breakpoints">
<url>file://$PROJECT_DIR$/PSCHelpdesk/PSCHelpdesk/Views/MainDockWindow.axaml.cs</url>
<line>75</line>
<properties documentPath="C:\Users\info\RiderProjects\pschelpdesk\PSCHelpdesk\PSCHelpdesk\Views\MainDockWindow.axaml.cs" containingFunctionPresentation="Lambda expression inside Constructor 'MainDockWindow'">
<startOffsets>
<option value="2758" />
</startOffsets>
<endOffsets>
<option value="2759" />
</endOffsets>
</properties>
<option name="timeStamp" value="216" />
</line-breakpoint>
</breakpoints>
</breakpoint-manager>

View File

@ -7,7 +7,6 @@ using CommunityToolkit.Mvvm.DependencyInjection;
using CommunityToolkit.Mvvm.Input;
using DynamicData;
using DynamicData.Binding;
using HetznerCloudApi;
using PSCHelpdesk.Plugins.HetznerServer.Models;
using PSCHelpdesk.Plugins.HetznerServer.Service;
using PSCHelpdesk.Plugins.HetznerServer.Views;

View File

@ -21,6 +21,8 @@
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADefaultAssemblyScanner_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F667004c0a83e47158c9865f6d54f01d91ac00_003Fa5_003F00a41a89_003FDefaultAssemblyScanner_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADefaultDirectoryTraverser_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F667004c0a83e47158c9865f6d54f01d91ac00_003F5a_003Fbd6f74c9_003FDefaultDirectoryTraverser_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADefaultPluginLoader_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F667004c0a83e47158c9865f6d54f01d91ac00_003F34_003F243c7c7d_003FDefaultPluginLoader_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADockItemViewModel_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003Fca55e2cf16410d6583d46a0c9733075e7c0a9d8bff277747e638859b39c45_003FDockItemViewModel_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADockItem_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F8b4806d72c8e4cc3b55824ab34018d6a31600_003F76_003Ff4abce16_003FDockItem_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AExceptionDispatchInfo_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fbd1d5c50194fea68ff3559c160230b0ab50f5acf4ce3061bffd6d62958e2182_003FExceptionDispatchInfo_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AExceptionDispatchInfo_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fbf9021a960b74107a7e141aa06bc9d8a0a53c929178c2fb95b1597be8af8dc_003FExceptionDispatchInfo_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AFile_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fe6a62e457eaef3f1f68c2a3e51b1b1351d3f2a3cef1a7379c6248f38bb8d64e8_003FFile_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
@ -30,6 +32,7 @@
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AHeroIcon_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F8edaf97dcc544ce3960f853a8b6332e246a200_003Fb9_003F454418ca_003FHeroIcon_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AHyperlinkButton_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fdd582eafcc7da4dc5ece1e7e4de37b1f271b42b4cea54a2aecfe3bda3fd2e5a_003FHyperlinkButton_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIBrush_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fbe37f94ace60e93760f363e28be5136e9e82a6dce891cef5f298e2bcd812c256_003FIBrush_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIDockGroup_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F8b4806d72c8e4cc3b55824ab34018d6a31600_003F03_003F4320f39c_003FIDockGroup_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIoc_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F2e6883f773fb7c69a15db509adac9a0c068e4ca54fa119e835fd2324311c3b_003FIoc_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIoc_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Ffa3c59274a754721f822d1776be91c7ffdd37ff4219098396aa16ba1fc5447_003FIoc_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIoc_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003Ffa3c59274a754721f822d1776be91c7ffdd37ff4219098396aa16ba1fc5447_003FIoc_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
@ -37,6 +40,7 @@
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIpv6_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F95e899f2b13d4189874af98ec00443321e400_003Ff7_003F54c88032_003FIpv6_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIServerActionsService_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fa924c6fef45b419cbbc71e86813a9b3a35000_003Ff5_003Fd14c12da_003FIServerActionsService_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIStorageProvider_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fceb1c14a2cad4d38a6c5bf90e72339c81cc000_003F_005Fcb8e6_003FIStorageProvider_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIUniDockService_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003Fc47c13cca75e97617e947c6da5d1608f1132d40d0ac16d29274ae52f7d3527_003FIUniDockService_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AJObject_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F443ce614ff11fd4152a3c735dec9ef388c537ef8ea9c24e0f018f1bd619e85_003FJObject_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AJsonConvert_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Ff3981d658666ec9cc1e6958fe22f8614bfe02ccb6625b056c3ece3729c9262_003FJsonConvert_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AJsonSerializerInternalWriter_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fe2e3d26278e439d44964729238a685ad58d3189abf8fb84cdfe34b893a290a2_003FJsonSerializerInternalWriter_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
@ -70,6 +74,7 @@
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AServiceProvider_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F9d4f4ac7db6d2c5d183ab2d92602280ed4349fd6e6a1b6313546b3d01fdab5_003FServiceProvider_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AServiceProvider_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F9d4f4ac7db6d2c5d183ab2d92602280ed4349fd6e6a1b6313546b3d01fdab5_003FServiceProvider_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AStackDockGroup_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F8b4806d72c8e4cc3b55824ab34018d6a31600_003F9a_003Fc689be08_003FStackDockGroup_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AStackFrameIterator_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F2854ce6d56c18d0d837d3a3ef9c4f2c7c77691fa3528c8394986ac7ce7719_003FStackFrameIterator_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AString_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fdad3f0ebff0dd1f8e1d244c3c44c649be8228d5e25fb37ef1de7f3c0e261c_003FString_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AStyledElement_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fb06c2ce0981bf6e5989cda2e3e737e53c2d54ee6ae7e7ce318d378f52e5f66_003FStyledElement_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASyntaxOverride_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F3271b3ee9bab4ce68ae772afd9932ac39000_003Fe2_003F9f2554b7_003FSyntaxOverride_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>

View File

@ -1,14 +0,0 @@
using System;
using Prise.Proxy;
namespace PSCHelpdesk.Converter;
public class AvaloniaPluginResultConverter : ResultConverter
{
public override object Deserialize(Type localType, Type remoteType, object value)
{
// No conversion, no backwards compatibility
// When the host upgrades any Avalonia dependency, it will break
return value;
}
}

View File

@ -49,9 +49,17 @@
<DependentUpon>MenuItem.axaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Update="Views\TestTemplateView.axaml.cs">
<DependentUpon>TestTemplateControl.axaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<AdditionalFiles Include="Controls\ProgressRing.axaml" />
</ItemGroup>
<ItemGroup>
<Folder Include="Converter\" />
</ItemGroup>
</Project>

View File

@ -1,120 +0,0 @@
using System;
using System.Linq;
using Avalonia.Controls;
using CommunityToolkit.Mvvm.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using PSCHelpdesk.Shared.Menu;
using PSCHelpdesk.Shared.Plugin;
using PSCHelpdesk.Shared.Service;
using PSCHelpdesk.Shared.Tasks;
namespace PSCHelpdesk.Services;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using Avalonia;
using Prise;
public class PluginService
{
private List<string> toLoadPlugins = new List<string>();
private Dictionary<string, Contract> loadedPlugins = new Dictionary<string, Contract>();
private Dictionary<string, string> foundPlugins = new Dictionary<string, string>();
private Dictionary<string, Type> controls = new Dictionary<string, Type>();
public PluginService()
{
//this.scanPlugins();
//this.LoadPlugin("HetznerServer");
this.LoadPlugin("Nextcloud");
}
public Dictionary<string, string> GetPlugins()
{
return this.foundPlugins;
}
async private void scanPlugins()
{
var pluginLoader = Ioc.Default.GetService<IPluginLoader>();
var dist = getPluginPath();
var pluginScanResults = await pluginLoader.FindPlugins<Contract>(dist);
var menuService = Ioc.Default.GetService<MenuService>();
//components = new Dictionary<string, IAppComponent>();
foreach (var pluginScanResult in pluginScanResults)
{
this.foundPlugins.Add(Path.GetFileNameWithoutExtension(pluginScanResult.AssemblyName), pluginScanResult.AssemblyPath);
}
}
private string getPluginPath()
{
var pathToThisProgram = Assembly.GetExecutingAssembly() // this assembly location (/bin/Debug/netcoreapp3.1)
.Location;
var pathToExecutingDir = Path.GetDirectoryName(pathToThisProgram);
//return Path.GetFullPath(Path.Combine(pathToExecutingDir, "../../../../../_dist"));
return pathToExecutingDir;
}
async public void LoadPlugin(string pluginName)
{
if(this.loadedPlugins.ContainsKey(pluginName))
{
return;
}
this.toLoadPlugins.Add(pluginName);
var pluginLoader = Ioc.Default.GetService(typeof(IPluginLoader)) as IPluginLoader;
var menuService = Ioc.Default.GetRequiredService<IMenuService>();
var settingsService = Ioc.Default.GetRequiredService<ISettingsService>();
var settingsManager = Ioc.Default.GetRequiredService<ISettingsManager>();
var taskManager = Ioc.Default.GetRequiredService<ITaskManager>();
var testService = Ioc.Default.GetRequiredService<ITestService>();
var appService = Ioc.Default.GetService(typeof(AppService)) as AppService;
var pluginAssemblies = await pluginLoader.FindPlugins<Contract>(getPluginPath());
var pluginToEnable = pluginAssemblies.FirstOrDefault(p => Path.GetFileNameWithoutExtension(p.AssemblyName) == pluginName);
if (pluginToEnable != null)
{
var plugin = await pluginLoader.LoadPlugin<Contract>(pluginToEnable, configure: (context) =>
{
context
.AddHostTypes(new[] {typeof(Application), typeof(Item)})
.AddRemoteTypes(new []{typeof(Item)})
.AddHostService<IMenuService>(menuService)
.AddHostService<ISettingsService>(settingsService)
.AddHostService<ISettingsManager>(settingsManager)
.AddHostService<ITaskManager>(taskManager)
.AddHostService<ITestService>(testService)
//.AddHostService<SettingsManager>(settingsService)
;
});
if (!this.loadedPlugins.ContainsKey(pluginName))
{
loadedPlugins.Add(plugin.GetName(), plugin);
plugin.Configure();
var items = plugin.LoadViews();
foreach (var item in items)
{
this.controls.Add(item.FullName, item);
}
appService.AppIsStarted();
}
}
}
public UserControl GetView(string viewName)
{
return (UserControl)Activator.CreateInstance(this.controls[viewName]);
}
public bool ViewExists(string viewName)
{
return this.controls.ContainsKey(viewName);
}
}

View File

@ -3,9 +3,6 @@ using Microsoft.Extensions.DependencyInjection;
using NP.Ava.UniDock;
using NP.Ava.UniDock.Factories;
using NP.Ava.UniDockService;
using Prise.DependencyInjection;
using Prise.Proxy;
using PSCHelpdesk.Converter;
using PSCHelpdesk.Services;
using PSCHelpdesk.Shared.Service;
using PSCHelpdesk.Shared.Setting;
@ -32,7 +29,6 @@ class Startup
var te = new ServiceCollection()
.AddSingleton<IUserInterfaceDispatchService, AvaloniaDispatcherService>()
.AddFactory<IResultConverter>(()=> new AvaloniaPluginResultConverter())
.AddSingleton<AppService>()
.AddSingleton<ISettingsManager>(settingsManager)
.AddSingleton<ISettingsService>(settingsService)

View File

@ -33,13 +33,19 @@ public class MainDockWindowViewModel : ViewModelBase, IViewModelBase
public ReactiveCommand<string, Unit> ClickMenu { get; }
public ReactiveCommand<Unit,Unit> OpenPlugins { get; }
public ReactiveCommand<Unit,Unit> SaveLayout { get; }
public ReactiveCommand<Unit,Unit> LoadLayout { get; }
public EventHandler<OpenEventArg> openTab;
public EventHandler LoadHandler;
public EventHandler SaveHandler;
public MainDockWindowViewModel()
{
ClickMenu = ReactiveCommand.Create<string>(SelectMenu);
OpenPlugins = ReactiveCommand.Create(openPlugins);
SaveLayout = ReactiveCommand.Create(saveLayout);
LoadLayout = ReactiveCommand.Create(loadLayout);
this.MenuItems = new List<Item>();
MenuService = (MenuService)Ioc.Default.GetService(typeof(IMenuService));
@ -100,9 +106,19 @@ public class MainDockWindowViewModel : ViewModelBase, IViewModelBase
DockId = "plugins",
Header = "Plugins",
DefaultDockGroupId = "Tabs",
Content = new PluginListViewModel(Ioc.Default.GetService<PluginManager>())
}
Content = new PluginListViewModel()
}
});
}
void loadLayout()
{
this.LoadHandler?.Invoke(this, EventArgs.Empty);
}
void saveLayout()
{
this.SaveHandler?.Invoke(this, EventArgs.Empty);
}
}

View File

@ -124,7 +124,7 @@ public class MainWindowViewModel : ViewModelBase, IViewModelBase
{
if (TabItems.Count(x => x.Header == "Plugins") == 0)
TabItems.Add(new TabItemViewModel("Plugins",
new PluginListViewModel(Ioc.Default.GetService<PluginManager>())));
new PluginListViewModel()));
SelectedTabItem = TabItems.Last();
}

View File

@ -1,5 +1,6 @@
using Avalonia.Collections;
using Avalonia.Controls;
using CommunityToolkit.Mvvm.DependencyInjection;
using CommunityToolkit.Mvvm.Input;
using NP.Ava.UniDockService;
using PSCHelpdesk.Services;
@ -7,7 +8,7 @@ using PSCHelpdesk.Shared.ViewModels;
namespace PSCHelpdesk.ViewModels;
class PluginListViewModel : ViewModelBase, IViewModelBase
public class PluginListViewModel : ViewModelBase, IViewModelBase
{
public RelayCommand<object> LoadAllPluginsCommand { get; set; }
public RelayCommand<object> UnLoadAllPluginsCommand { get; set; }
@ -15,10 +16,9 @@ class PluginListViewModel : ViewModelBase, IViewModelBase
public AvaloniaList<string> Plugins { get; set; }
public UserControl CurrentControl { get; set; }
private PluginService _pluginService { get; }
public PluginListViewModel(PluginManager pluginService)
public PluginListViewModel()
{
var pluginService = Ioc.Default.GetService<PluginManager>();
this.Plugins = new AvaloniaList<string>();
LoadPluginCommand = new RelayCommand<object>(LoadPlugin);
@ -33,14 +33,14 @@ class PluginListViewModel : ViewModelBase, IViewModelBase
async void LoadPlugin(object parameter)
{
this._pluginService.LoadPlugin(parameter.ToString());
}
async void LoadAllPlugins(object parameter)
{
foreach (var plugin in Plugins)
{
this._pluginService.LoadPlugin(plugin);
}
}

View File

@ -0,0 +1,8 @@
using PSCHelpdesk.Shared.ViewModels;
namespace PSCHelpdesk.ViewModels;
public class TestTemplateViewModel: ViewModelBase, IViewModelBase
{
}

View File

@ -42,9 +42,9 @@
</Style>
</MenuItem.Styles>
</MenuItem>
<MenuItem Header="_Plugins" Command="{Binding OpenPlugins}">
</MenuItem>
<MenuItem Header="_Plugins" Command="{Binding OpenPlugins}"></MenuItem>
<MenuItem Header="_SaveLayout" Command="{Binding SaveLayout}"></MenuItem>
<MenuItem Header="_RestoreLayout" Command="{Binding LoadLayout}"></MenuItem>
</Menu>
<!-- top level group should reference the dock manager-->
<np:RootDockGroup TheDockManager="{StaticResource TheDockManager}"

View File

@ -1,12 +1,16 @@
using System.Collections.ObjectModel;
using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using CommunityToolkit.Mvvm.DependencyInjection;
using DynamicData;
using NP.Ava.UniDock;
using NP.Ava.UniDockService;
using NP.Utilities;
using PSCHelpdesk.Shared.Service;
using PSCHelpdesk.Shared.Setting;
using PSCHelpdesk.ViewModels;
@ -35,40 +39,50 @@ public partial class MainDockWindow : Window
);
};
//_uniDockService.DockItemsViewModels = null;
(this.DataContext as MainDockWindowViewModel).SaveHandler += (_, __) =>
{
var settingsManager = (SettingsManager)Ioc.Default.GetService<ISettingsManager>();
_uniDockService.SaveToFile(Path.Combine(settingsManager.DataRoot, "DockSerialization.xml"));
var settingsManager = (SettingsManager)Ioc.Default.GetService<ISettingsManager>();
// restore the layout
//_uniDockService.RestoreFromFile(Path.Combine(settingsManager.DataRoot, "DockSerialization.xml"));
foreach (var docItem in _uniDockService.DockItemsViewModels)
{
}
//_uniDockService.SaveViewModelsToFile(Path.Combine(settingsManager.DataRoot, "DockVMSerialization.xml"));
};
(this.DataContext as MainDockWindowViewModel).LoadHandler += (_, __) =>
{
var settingsManager = (SettingsManager)Ioc.Default.GetService<ISettingsManager>();
//_uniDockService.DockItemsViewModels = null;
_dockManager.RestoreFromFile(Path.Combine(settingsManager.DataRoot, "DockSerialization.xml"));
var viewLocator = new ViewLocator();
foreach (var docItem in _dockManager.ConnectedGroups.NullToEmpty().Where(e => e is DockItem))
{
Console.WriteLine(docItem);
}
_dockManager.DockItemsViewModels.Add(new DockItemViewModelBase()
{
DockId = "plugins",
Header = "Plugins",
DefaultDockGroupId = "Tabs",
Content = new PluginListViewModel()
});
_dockManager.DockItemsViewModels?.OfType<DockItemViewModelBase>().FirstOrDefault()?.Select();
};
}
private void Exit_OnClick(object? sender, RoutedEventArgs e)
{
var settingsManager = (SettingsManager)Ioc.Default.GetService<ISettingsManager>();
// save the layout
//_uniDockService.SaveToFile(Path.Combine(settingsManager.DataRoot, "DockSerialization.xml"));
// save the view models
//_uniDockService.SaveViewModelsToFile(Path.Combine(settingsManager.DataRoot, "DockVMSerialization.xml"));
Close();
}
private void Settings_OnClick(object? sender, RoutedEventArgs e)
{
_uniDockService.DockItemsViewModels.Add
(
new DockItemViewModelBase
{
DockId = "tabStr",
Header = "tabStr",
Content = $"This is tab ",
DefaultDockGroupId = "Tabs",
DefaultDockOrderInGroup = 1,
IsSelected = true,
IsActive = true
});
return;
SettingsWindow settings = new SettingsWindow
{
DataContext = new SettingsViewModel(),

View File

@ -0,0 +1,16 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:PSCHelpdesk.Views">
<Design.PreviewWith>
<controls:TestTemplateView />
</Design.PreviewWith>
<Style Selector="controls|TestTemplateView">
<!-- Set Defaults -->
<Setter Property="Template">
<ControlTemplate>
<TextBlock Text="Templated Control" />
</ControlTemplate>
</Setter>
</Style>
</Styles>

View File

@ -0,0 +1,9 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
namespace PSCHelpdesk.Views;
public class TestTemplateView : TemplatedControl
{
}

View File

@ -2,10 +2,11 @@
using System.ComponentModel;
using System.Runtime.CompilerServices;
using NP.Ava.UniDockService;
using NP.Utilities;
namespace PSCHelpdesk.Shared.ViewModels;
public class ViewModelBase :INotifyPropertyChanged
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;

View File

@ -1,14 +0,0 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
namespace Prise.Mvc
{
public static class ApplicationBuilderExtensions
{
public static IApplicationBuilder EnsureStaticPluginCache(this IApplicationBuilder app)
{
app.ApplicationServices.GetRequiredService<IPluginCacheAccessorBootstrapper>();
return app;
}
}
}

View File

@ -1,71 +0,0 @@
using System;
using System.IO;
using System.Threading.Tasks;
using System.Collections.Generic;
using Prise.Caching;
using Prise.AssemblyScanning;
using Prise.AssemblyLoading;
using System.Linq;
using Prise.Utils;
namespace Prise.Mvc
{
public class DefaultMvcPluginLoader : IMvcPluginLoader
{
protected readonly IAssemblyScanner assemblyScanner;
protected readonly IPluginTypeSelector pluginTypeSelector;
protected readonly IAssemblyLoader assemblyLoader;
protected readonly IPluginCache pluginCache;
public DefaultMvcPluginLoader(IAssemblyScanner assemblyScanner,
IPluginTypeSelector pluginTypeSelector,
IAssemblyLoader assemblyLoader,
IPluginCache pluginCache)
{
this.assemblyScanner = assemblyScanner;
this.pluginTypeSelector = pluginTypeSelector;
this.assemblyLoader = assemblyLoader;
this.pluginCache = pluginCache;
}
public async virtual Task<IEnumerable<AssemblyScanResult>> FindPlugins<T>(string pathToPlugins)
{
return (await this.assemblyScanner.Scan(new AssemblyScannerOptions
{
StartingPath = pathToPlugins,
PluginType = typeof(T)
}));
}
public async virtual Task<IAssemblyShim> LoadPluginAssembly<T>(AssemblyScanResult plugin, Action<PluginLoadContext> configureLoadContext = null)
{
var pluginLoadContext = ToPluginLoadContext<T>(plugin);
configureLoadContext?.Invoke(pluginLoadContext);
pluginLoadContext.AddMvcTypes();
var pluginAssembly = await this.assemblyLoader.Load(pluginLoadContext);
this.pluginCache.Add(pluginAssembly, pluginLoadContext.HostServices.Select(s => s.ServiceType));
return pluginAssembly;
}
public async virtual Task UnloadPluginAssembly<T>(AssemblyScanResult plugin)
{
var pluginLoadContext = ToPluginLoadContext<T>(plugin);
await this.assemblyLoader.Unload(pluginLoadContext);
var pathToAssembly = Path.Combine(plugin.AssemblyPath, plugin.AssemblyName);
this.pluginCache.Remove(pathToAssembly);
}
protected PluginLoadContext ToPluginLoadContext<T>(AssemblyScanResult plugin)
{
var hostFramework = HostFrameworkUtils.GetHostframeworkFromHost();
var pathToAssembly = Path.Combine(plugin.AssemblyPath, plugin.AssemblyName);
return PluginLoadContext.DefaultPluginLoadContext(pathToAssembly, typeof(T), hostFramework);
}
}
}

View File

@ -1,34 +0,0 @@
using System;
using System.Threading.Tasks;
using Prise.Caching;
using Prise.AssemblyScanning;
using Prise.AssemblyLoading;
using System.Linq;
namespace Prise.Mvc
{
public class DefaultMvcRazorPluginLoader : DefaultMvcPluginLoader
{
public DefaultMvcRazorPluginLoader(IAssemblyScanner assemblyScanner,
IPluginTypeSelector pluginTypeSelector,
IAssemblyLoader assemblyLoader,
IPluginCache pluginCache) : base(assemblyScanner, pluginTypeSelector, assemblyLoader, pluginCache) { }
public override async Task<IAssemblyShim> LoadPluginAssembly<T>(AssemblyScanResult plugin, Action<PluginLoadContext> configureLoadContext = null)
{
var pluginLoadContext = ToPluginLoadContext<T>(plugin);
configureLoadContext?.Invoke(pluginLoadContext);
pluginLoadContext
.AddMvcRazorTypes();
var pluginAssembly = await this.assemblyLoader.Load(pluginLoadContext);
this.pluginCache.Add(pluginAssembly, pluginLoadContext.HostServices.Select(s => s.ServiceType));
return pluginAssembly;
}
}
}

View File

@ -1,25 +0,0 @@
using System.Threading;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.Extensions.Primitives;
namespace Prise.Mvc
{
public class DefaultPriseMvcActionDescriptorChangeProvider : IActionDescriptorChangeProvider, IPriseMvcActionDescriptorChangeProvider
{
public CancellationTokenSource TokenSource { get; private set; }
public bool HasChanged { get; set; }
public IChangeToken GetChangeToken()
{
TokenSource = new CancellationTokenSource();
return new CancellationChangeToken(TokenSource.Token);
}
public void TriggerPluginChanged()
{
HasChanged = true;
TokenSource.Cancel();
}
}
}

View File

@ -1,76 +0,0 @@
using System;
using System.Linq;
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.Extensions.DependencyInjection;
using Prise.Activation;
using Prise.Infrastructure;
using Prise.Plugin;
using Prise.Proxy;
using Prise.Caching;
namespace Prise.Mvc
{
public class DefaultPriseMvcControllerActivator : IControllerActivator
{
public object Create(ControllerContext context)
{
var cache = context.HttpContext.RequestServices.GetRequiredService<IPluginCache>();
var controllerType = context.ActionDescriptor.ControllerTypeInfo.AsType();
foreach (var cachedPluginAssembly in cache.GetAll())
{
var pluginAssembly = cachedPluginAssembly.AssemblyShim.Assembly;
var pluginControllerType = pluginAssembly.GetTypes().FirstOrDefault(t => t.Name == controllerType.Name);
if (pluginControllerType != null)
{
var activatorContextProvider = context.HttpContext.RequestServices.GetRequiredService<IPluginActivationContextProvider>();
var remotePluginActivator = context.HttpContext.RequestServices.GetRequiredService<IRemotePluginActivator>();
var proxyCreator = context.HttpContext.RequestServices.GetRequiredService<IPluginProxyCreator>();
var resultConverter = context.HttpContext.RequestServices.GetRequiredService<IResultConverter>();
var parameterConverter = context.HttpContext.RequestServices.GetRequiredService<IParameterConverter>();
object controller = null;
IPluginBootstrapper bootstrapperProxy = null;
IServiceCollection hostServices = new ServiceCollection();
foreach (var hostServiceType in cachedPluginAssembly.HostTypes)
hostServices.Add(new ServiceDescriptor(hostServiceType, context.HttpContext.RequestServices.GetRequiredService(hostServiceType)));
var pluginActivationContext = activatorContextProvider.ProvideActivationContext(pluginControllerType, cachedPluginAssembly.AssemblyShim);
if (pluginActivationContext.PluginBootstrapperType != null)
{
var remoteBootstrapperInstance = remotePluginActivator.CreateRemoteBootstrapper(pluginActivationContext, hostServices);
var remoteBootstrapperProxy = proxyCreator.CreateBootstrapperProxy(remoteBootstrapperInstance);
bootstrapperProxy = remoteBootstrapperProxy;
}
controller = remotePluginActivator.CreateRemoteInstance(
pluginActivationContext,
bootstrapperProxy,
hostServices: hostServices
);
var controllerContext = new ControllerContext();
controllerContext.HttpContext = context.HttpContext;
var controllerContextProperty = controllerType.GetProperty("ControllerContext");
controllerContextProperty.SetValue(controller, controllerContext);
return controller;
}
}
// Use MSFT's own activator utilities to create a controller instance
// This avoids us to require to register all controllers as services
return ActivatorUtilities.CreateInstance(context.HttpContext.RequestServices, controllerType);
}
public void Release(ControllerContext context, object controller)
{
(controller as IDisposable)?.Dispose();
}
}
}

View File

@ -1,72 +0,0 @@
using System;
using System.IO;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Primitives;
using Prise.Caching;
namespace Prise.Mvc
{
public class DefaultPrisePluginViewsAssemblyFileProvider : IFileProvider
{
protected readonly PhysicalFileProvider webRootFileProvider;
protected readonly string pathToPlugins;
public DefaultPrisePluginViewsAssemblyFileProvider(string hostingRootPath, string pathToPlugins)
{
if (!Path.IsPathRooted(pathToPlugins))
throw new ArgumentException($"{nameof(pathToPlugins)} must be rooted (absolute path).");
this.pathToPlugins = pathToPlugins;
this.webRootFileProvider = new PhysicalFileProvider(hostingRootPath);
}
private IPluginCache GetLoadedPluginsCache()
{
return DefaultStaticPluginCacheAccessor.CurrentCache;
}
private IFileProvider GetPluginFileProvider(string subpath)
{
var cache = GetLoadedPluginsCache();
if (cache == null)
return null;
foreach (var loadedPlugin in cache.GetAll())
{
var pluginAssemblyName = loadedPlugin.AssemblyShim.Assembly.GetName().Name;
var pathToPlugin = Path.Combine(pathToPlugins, pluginAssemblyName);
var pathCandidate = Path.Combine(pathToPlugin, SanitizeSubPath(subpath));
if (File.Exists(pathCandidate))
return new PhysicalFileProvider(pathToPlugin);
}
return null;
}
private string SanitizeSubPath(string subPath)
{
if (subPath.StartsWith('/'))
return subPath.Substring(1);
return subPath;
}
public IDirectoryContents GetDirectoryContents(string subpath)
{
var pluginFileProvider = GetPluginFileProvider(subpath);
if (pluginFileProvider != null)
return pluginFileProvider.GetDirectoryContents(subpath);
return this.webRootFileProvider.GetDirectoryContents(subpath);
}
public IFileInfo GetFileInfo(string subpath)
{
var pluginFileProvider = GetPluginFileProvider(subpath);
if (pluginFileProvider != null)
return pluginFileProvider.GetFileInfo(subpath);
return this.webRootFileProvider.GetFileInfo(subpath);
}
public IChangeToken Watch(string filter)
{
return this.webRootFileProvider.Watch(filter);
}
}
}

View File

@ -1,9 +0,0 @@
using Prise.Caching;
namespace Prise.Mvc
{
public static class DefaultStaticPluginCacheAccessor
{
public static IPluginCache CurrentCache { get; internal set; }
}
}

View File

@ -1,23 +0,0 @@
using System;
using Prise.Caching;
namespace Prise.Mvc
{
public class DefaultStaticPluginCacheAccessorBootstrapper : IPluginCacheAccessorBootstrapper
{
protected bool isBootstrapped;
public DefaultStaticPluginCacheAccessorBootstrapper(IPluginCache cache)
{
if (this.isBootstrapped)
throw new NotSupportedException($"IPluginCache was already bootstrapped");
this.SetCurrentCache(cache);
this.isBootstrapped = true;
}
public void SetCurrentCache(IPluginCache cache)
{
DefaultStaticPluginCacheAccessor.CurrentCache = cache;
}
}
}

View File

@ -1,14 +0,0 @@
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
namespace Prise.Mvc
{
public interface IMvcPluginLoader
{
Task<IEnumerable<AssemblyScanResult>> FindPlugins<T>(string pathToPlugins);
Task<IAssemblyShim> LoadPluginAssembly<T>(AssemblyScanResult plugin, Action<PluginLoadContext> configure = null);
Task UnloadPluginAssembly<T>(AssemblyScanResult plugin);
}
}

View File

@ -1,9 +0,0 @@
using Prise.Caching;
namespace Prise.Mvc
{
public interface IPluginCacheAccessorBootstrapper
{
void SetCurrentCache(IPluginCache cache);
}
}

View File

@ -1,7 +0,0 @@
namespace Prise.Mvc
{
public interface IPriseMvcActionDescriptorChangeProvider
{
void TriggerPluginChanged();
}
}

View File

@ -1,15 +0,0 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
namespace Prise.Mvc
{
public class PluginAssemblyPart : AssemblyPart, ICompilationReferencesProvider
{
public PluginAssemblyPart(Assembly assembly) : base(assembly) { }
// This solves the NullRef bug for in-memory assemblies from Prise
IEnumerable<string> ICompilationReferencesProvider.GetReferencePaths() => Array.Empty<string>();
}
}

View File

@ -1,98 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!-- <TargetFrameworks>netcoreapp2.1;</TargetFrameworks> -->
<TargetFrameworks>netcoreapp2.1;netcoreapp3.1;net5.0;net6.0</TargetFrameworks>
<Title>Prise.Mvc</Title>
<PackageId>Prise.Mvc</PackageId>
<PackageDescription>Adds ASP.NET MVC features to an existing Prise setup!</PackageDescription>
<Authors>Maarten Merken</Authors>
<Company>MRKN</Company>
<PackageTags>mvc;controllers;plugin</PackageTags>
<PackageLicenseUrl>https://raw.githubusercontent.com/merken/Prise/master/LICENSE</PackageLicenseUrl>
<PackageProjectUrl>https://github.com/merken/Prise</PackageProjectUrl>
<RepositoryUrl>https://github.com/merken/Prise.git</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);CopyProjectReferencesToPackage</TargetsForTfmSpecificBuildOutput>
</PropertyGroup>
<Target DependsOnTargets="ResolveReferences" Name="CopyProjectReferencesToPackage">
<ItemGroup>
<BuildOutputInPackage Include="@(ReferenceCopyLocalPaths-&gt;WithMetadataValue('ReferenceSourceTarget', 'ProjectReference'))" />
</ItemGroup>
</Target>
<PropertyGroup Condition="'$(TargetFramework)' == 'netcoreapp2.1'">
<DefineConstants>NETCORE2_1</DefineConstants>
</PropertyGroup>
<!-- Constants (NETCORE2_1, NETCORE3_1) are one or the other, if multiple constants are required, prefix it with $(DefineConstants);-->
<PropertyGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'">
<DefineConstants>NETCORE3_1</DefineConstants>
</PropertyGroup>
<PropertyGroup>
<PackageIcon>icon.png</PackageIcon>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
<ItemGroup>
<None Include="../icon.png">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp2.1'">
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.1.3" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor" Version="2.1.3" />
<PackageReference Include="Microsoft.Extensions.FileProviders.Physical" Version="2.1.1" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.0'">
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.FileProviders.Physical" Version="3.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="3.0.2" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'">
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.FileProviders.Physical" Version="3.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="3.1.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net5.0'">
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="5.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.FileProviders.Physical" Version="5.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="5.0.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net6.0'">
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.FileProviders.Physical" Version="6.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="6.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Prise.Plugin\Prise.Plugin.csproj">
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
<IncludeAssets>Prise.Plugin.dll</IncludeAssets>
</ProjectReference>
<ProjectReference Include="..\Prise.Proxy\Prise.Proxy.csproj">
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
<IncludeAssets>Prise.Proxy.dll</IncludeAssets>
</ProjectReference>
<ProjectReference Include="..\Prise\Prise.csproj">
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
<IncludeAssets>Prise.dll</IncludeAssets>
</ProjectReference>
</ItemGroup>
</Project>

View File

@ -1,118 +0,0 @@
using System;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.Razor;
#if !NETCORE2_1
using Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation;
#endif
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Prise.DependencyInjection;
using Prise.Activation;
using Prise.AssemblyLoading;
using Prise.AssemblyScanning;
using Prise.Proxy;
using Prise.Caching;
namespace Prise.Mvc
{
public static class PriseMvcExtensions
{
internal static PluginLoadContext AddMvcTypes(this PluginLoadContext loadContext)
{
return loadContext.AddHostTypes(new[] { typeof(ControllerBase) });
}
internal static PluginLoadContext AddMvcRazorTypes(this PluginLoadContext loadContext)
{
return loadContext.AddHostTypes(new[] { typeof(ControllerBase), typeof(ITempDataDictionaryFactory) });
}
public static IServiceCollection AddCorePriseServices(this IServiceCollection services)
{
return services
.AddFactory<IAssemblyScanner>(DefaultFactories.DefaultAssemblyScanner, ServiceLifetime.Scoped)
.AddFactory<IPluginTypeSelector>(DefaultFactories.DefaultPluginTypeSelector, ServiceLifetime.Scoped)
.AddFactory<IParameterConverter>(DefaultFactories.DefaultParameterConverter, ServiceLifetime.Scoped)
.AddFactory<IResultConverter>(DefaultFactories.DefaultResultConverter, ServiceLifetime.Scoped)
.AddFactory<IPluginActivationContextProvider>(DefaultFactories.DefaultPluginActivationContextProvider, ServiceLifetime.Scoped)
.AddFactory<IRemotePluginActivator>(DefaultFactories.DefaultRemotePluginActivator, ServiceLifetime.Scoped)
.AddFactory<IPluginProxyCreator>(DefaultFactories.DefaultPluginProxyCreator, ServiceLifetime.Scoped)
.AddFactory<IAssemblyLoader>(DefaultFactories.DefaultAssemblyLoader, ServiceLifetime.Singleton);
}
/// <summary>
/// Does all of the plumbing to load API Controllers as Prise Plugins.
/// Limitiations:
/// - No DispatchProxy can be used, backwards compatability is compromised (DispatchProxy requires an interface as base class, not ControllerBase)
/// - Plugin Cache is set to Singleton because we cannot unload assemblies, this would disable the controller routing (and result in 404)
/// - Assembly unloading is disabled, memory leaks can occur
/// </summary>
/// <returns>A fully configured Prise setup that allows you to load plugins via the IMvcPluginLoader</returns>
public static IServiceCollection AddPriseMvc(this IServiceCollection services)
{
return services
.AddCorePriseServices()
.AddSingleton<IPluginCache, DefaultScopedPluginCache>()
.AddScoped<IMvcPluginLoader, DefaultMvcPluginLoader>()
.ConfigureMvcServices()
;
}
/// <summary>
/// Does all of the plumbing to load API Controllers and RAZOR Controllers as Prise Plugins.
/// Limitiations:
/// - No DispatchProxy can be used, backwards compatability is compromised (DispatchProxy requires an interface as base class, not ControllerBase)
/// - Plugin Cache is set to Singleton because we cannot unload assemblies, this would disable the controller routing (and result in 404)
/// - Assembly unloading is disabled, memory leaks can occur
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="builder"></param>
/// <param name="webRootPath">By default, this should be the IWebHostEnvironment.WebRootPaht or IHostingEnvironment.WebRootPath</param>
/// <returns></returns>
public static IServiceCollection AddPriseRazorPlugins(this IServiceCollection services, string webRootPath, string pathToPlugins)
{
return services
.AddCorePriseServices()
.AddSingleton<IPluginCache, DefaultScopedPluginCache>()
.AddScoped<IMvcPluginLoader, DefaultMvcRazorPluginLoader>()
.ConfigureMvcServices()
.ConfigureRazorServices(webRootPath, pathToPlugins)
;
}
private static IServiceCollection ConfigureMvcServices(this IServiceCollection services)
{
var actionDescriptorChangeProvider = new DefaultPriseMvcActionDescriptorChangeProvider();
// Registers the change provider
return services
.AddSingleton<IPriseMvcActionDescriptorChangeProvider>(actionDescriptorChangeProvider)
.AddSingleton<IActionDescriptorChangeProvider>(actionDescriptorChangeProvider)
// Registers the activator for controllers from plugin assemblies
.Replace(ServiceDescriptor.Transient<IControllerActivator, DefaultPriseMvcControllerActivator>());
}
private static IServiceCollection ConfigureRazorServices(this IServiceCollection services, string webRootPath, string pathToPlugins)
{
return services
#if NETCORE2_1
.Configure<RazorViewEngineOptions>(options =>
{
options.FileProviders.Add(new DefaultPrisePluginViewsAssemblyFileProvider(webRootPath, pathToPlugins));
})
#else
.Configure<MvcRazorRuntimeCompilationOptions>(options =>
{
options.FileProviders.Add(new DefaultPrisePluginViewsAssemblyFileProvider(webRootPath, pathToPlugins));
})
#endif
// Registers the static Plugin Cache Accessor
.AddSingleton<IPluginCacheAccessorBootstrapper, DefaultStaticPluginCacheAccessorBootstrapper>();
}
}
}

View File

@ -1,30 +0,0 @@
using System;
namespace Prise.Plugin
{
[System.AttributeUsage(System.AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
public sealed class BootstrapperServiceAttribute : System.Attribute
{
Type serviceType;
public Type ServiceType
{
get { return this.serviceType; }
set { this.serviceType = value; }
}
Type bridgeType;
[Obsolete("Usage of a BridgeType is obsolete, please use ProxyType instead. Existing plugins will continue to function as normal.", false)]
public Type BridgeType
{
get { return this.bridgeType; }
set { this.bridgeType = value; }
}
Type proxyType;
public Type ProxyType
{
get { return this.proxyType; }
set { this.proxyType = value; }
}
}
}

View File

@ -1,9 +0,0 @@
using Microsoft.Extensions.DependencyInjection;
namespace Prise.Plugin
{
public interface IPluginBootstrapper
{
IServiceCollection Bootstrap(IServiceCollection services);
}
}

View File

@ -1,5 +0,0 @@
namespace Prise.Plugin
{
[System.AttributeUsage(System.AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
public sealed class PluginActivatedAttribute : System.Attribute { }
}

View File

@ -1,15 +0,0 @@
using System;
namespace Prise.Plugin
{
[System.AttributeUsage(System.AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public sealed class PluginAttribute : System.Attribute
{
Type pluginType;
public Type PluginType
{
get { return this.pluginType; }
set { this.pluginType = value; }
}
}
}

View File

@ -1,15 +0,0 @@
using System;
namespace Prise.Plugin
{
[System.AttributeUsage(System.AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
public sealed class PluginBootstrapperAttribute : System.Attribute
{
Type pluginType;
public Type PluginType
{
get { return this.pluginType; }
set { this.pluginType = value; }
}
}
}

View File

@ -1,8 +0,0 @@
using System;
namespace Prise.Plugin
{
[Obsolete("Usage of a PluginFactory is obsolete, please use field injection instead. Existing plugins will continue to function as normal.", false)]
[System.AttributeUsage(System.AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
public sealed class PluginFactoryAttribute : System.Attribute { }
}

View File

@ -1,37 +0,0 @@
using System;
namespace Prise.Plugin
{
[System.AttributeUsage(System.AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
public sealed class PluginServiceAttribute : System.Attribute
{
Type serviceType;
public Type ServiceType
{
get { return this.serviceType; }
set { this.serviceType = value; }
}
ProvidedBy providedBy;
public ProvidedBy ProvidedBy
{
get { return this.providedBy; }
set { this.providedBy = value; }
}
Type bridgeType;
[Obsolete("Usage of a BridgeType is obsolete, please use ProxyType instead. Existing plugins will continue to function as normal.", false)]
public Type BridgeType
{
get { return this.bridgeType; }
set { this.bridgeType = value; }
}
Type proxyType;
public Type ProxyType
{
get { return this.proxyType; }
set { this.proxyType = value; }
}
}
}

View File

@ -1,32 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Title>Prise.Plugin</Title>
<PackageId>Prise.Plugin</PackageId>
<PackageDescription>Prise, A .NET Plugin Framework!</PackageDescription>
<Authors>Maarten Merken</Authors>
<Company>MRKN</Company>
<PackageTags>plugin;framework;prise;decoupling;assembly;dispatchproxy;proxy</PackageTags>
<PackageLicenseUrl>https://raw.githubusercontent.com/merken/Prise/master/LICENSE</PackageLicenseUrl>
<PackageProjectUrl>https://github.com/merken/Prise</PackageProjectUrl>
<RepositoryUrl>https://github.com/merken/Prise.git</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<LangVersion>default</LangVersion>
</PropertyGroup>
<PropertyGroup>
<PackageIcon>icon.png</PackageIcon>
</PropertyGroup>
<ItemGroup>
<None Include="../icon.png">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.1.0" />
</ItemGroup>
</Project>

View File

@ -1,8 +0,0 @@
namespace Prise.Plugin
{
public enum ProvidedBy
{
Plugin = 0,
Host
}
}

View File

@ -1,9 +0,0 @@
using System;
namespace Prise.Proxy
{
public interface IParameterConverter : IDisposable
{
object ConvertToRemoteType(Type localType, object value);
}
}

View File

@ -1,28 +0,0 @@
using System;
using System.Threading.Tasks;
namespace Prise.Proxy
{
public interface IResultConverter : IDisposable
{
/// <summary>
/// This method should convert a remote value into a local one.
/// This method will be called in case the remote type is not a Task.
/// </summary>
/// <param name="localType">The return type of the host</param>
/// <param name="remoteType">The return type of the remote</param>
/// <param name="value">The value from the remote, this can be different from the remoteType if the remote uses an old contract, in this case, convert to correct type.</param>
/// <returns>A converted local instance</returns>
object ConvertToLocalType(Type localType, Type remoteType, object value);
/// <summary>
/// This method should convert a remote value into a local one.
/// This method will be called in case the remote type is a Task.
/// </summary>
/// <param name="localType">The return type of the host, Task<localType></param>
/// <param name="remoteType">The return type of the remote, Task<remoteType></param>
/// <param name="task">The Task that holds the value from the remote, this can be different from the remoteType if the remote uses an old contract, in this case, convert to correct type.</param>
/// <returns>A Task containing the local type with the remote value</returns>
object ConvertToLocalTypeAsync(Type localType, Type remoteType, Task task);
}
}

View File

@ -1,16 +0,0 @@
using System;
namespace Prise.Proxy
{
public struct Method
{
public string Name { get; }
public Type? ReturnType { get; }
public Method(string name, Type? returnType = null)
{
this.Name = name;
this.ReturnType = returnType;
}
}
}

View File

@ -1,13 +0,0 @@
using System;
namespace Prise.Proxy
{
[Flags]
public enum MethodFindingStrategy
{
MethodNameMustMatch,
MethodReturnTypeMustMatch,
ParameterCountMustMatch,
ParameterTypeMustMatch
}
}

View File

@ -1,16 +0,0 @@
using System;
namespace Prise.Proxy
{
public struct Parameter
{
public string Name { get; }
public Type? Type { get; }
public Parameter(string name, Type? type = null)
{
this.Name = name;
this.Type = type;
}
}
}

View File

@ -1,29 +0,0 @@
using System;
namespace Prise.Proxy
{
public class PassthroughParameterConverter : IParameterConverter
{
protected bool disposed = false;
public object ConvertToRemoteType(Type localType, object value)
{
return value;
}
protected virtual void Dispose(bool disposing)
{
if (!this.disposed && disposing)
{
// Nothing to do here
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}

View File

@ -1,12 +0,0 @@
using System;
namespace Prise.Proxy
{
public class PassthroughResultConverter : ResultConverter
{
public override object Deserialize(Type localType, Type remoteType, object value)
{
return value;
}
}
}

View File

@ -1,42 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Title>Prise.Proxy</Title>
<PackageId>Prise.Proxy</PackageId>
<PackageDescription>Prise, A .NET Plugin Framework!</PackageDescription>
<Authors>Maarten Merken</Authors>
<Company>MRKN</Company>
<PackageTags>plugin;framework;prise;decoupling;assembly;dispatchproxy;proxy</PackageTags>
<TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);CopyProjectReferencesToPackage</TargetsForTfmSpecificBuildOutput>
<Nullable>enable</Nullable>
<LangVersion>default</LangVersion>
<PackageLicenseUrl>https://raw.githubusercontent.com/merken/Prise/master/LICENSE</PackageLicenseUrl>
<PackageProjectUrl>https://github.com/merken/Prise</PackageProjectUrl>
<RepositoryUrl>https://github.com/merken/Prise.git</RepositoryUrl>
<RepositoryType>git</RepositoryType>
</PropertyGroup>
<Target DependsOnTargets="ResolveReferences" Name="CopyProjectReferencesToPackage">
<ItemGroup>
<BuildOutputInPackage Include="@(ReferenceCopyLocalPaths-&gt;WithMetadataValue('ReferenceSourceTarget', 'ProjectReference'))" />
</ItemGroup>
</Target>
<ItemGroup>
<PackageReference Include="System.Reflection.Emit" Version="4.7.0" />
</ItemGroup>
<PropertyGroup>
<PackageIcon>icon.png</PackageIcon>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
<ItemGroup>
<None Include="../icon.png">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
</ItemGroup>
</Project>

View File

@ -1,254 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Prise.Proxy
{
/// <summary>
/// This is the PriseProxy static class that encapsulates most of the boilerplate static methods in order to interact with the remote object (Plugin)
/// TODO
/// - Generic Methods (Task<string> Do<T>(T stuff))
/// - Events (not sure if this is ever possible)
/// </summary>
public static class PriseProxy
{
public static object Invoke(object remoteObject, MethodInfo targetMethod, object[] args)
=> Invoke(remoteObject, targetMethod, args, new PassthroughParameterConverter(),
new PassthroughResultConverter());
public static object Invoke(object remoteObject, MethodInfo targetMethod, object[] args,
IParameterConverter parameterConverter, IResultConverter resultConverter)
{
try
{
var localType = targetMethod.ReturnType;
var remoteMethod = FindMethodOnObject(targetMethod, remoteObject);
if (remoteMethod == null)
throw new PriseProxyException(
$"Target method {targetMethod.Name} is not found on Proxy Type {remoteObject.GetType().Name}.");
object result = null;
if (remoteMethod.IsGenericMethod)
{
var generic = remoteMethod.MakeGenericMethod(targetMethod.GetGenericArguments());
result = generic.Invoke(remoteObject, SerializeParameters(parameterConverter, remoteMethod, args));
}
else
result = remoteMethod.Invoke(remoteObject,
SerializeParameters(parameterConverter, remoteMethod, args));
var remoteType = remoteMethod.ReturnType;
if (remoteType.BaseType == typeof(System.Threading.Tasks.Task))
return resultConverter.ConvertToLocalTypeAsync(localType, remoteType,
result as System.Threading.Tasks.Task);
if (remoteType == typeof(System.Threading.Tasks.Task))
return resultConverter.ConvertToLocalTypeAsync(localType, remoteType,
result as System.Threading.Tasks.Task);
if (remoteType == typeof(void))
return null;
return resultConverter.ConvertToLocalType(localType, remoteType, result);
}
catch (Exception ex) when (ex is TargetInvocationException)
{
throw ex.InnerException ?? ex;
}
}
public static MethodInfo FindMethodOnObject(MethodInfo callingMethod, object targetObject)
=> FindMethodOnObject(
targetObject,
new Method(callingMethod.Name, callingMethod.ReturnType),
callingMethod.GetParameters().Select(p => new Parameter(p.Name, p.ParameterType)).ToArray(),
throwOnError: true)!; // Throws error when null
public static MethodInfo? TryFindMethodOnObject(MethodInfo callingMethod, object targetObject)
=> FindMethodOnObject(
targetObject,
new Method(callingMethod.Name, callingMethod.ReturnType),
callingMethod.GetParameters().Select(p => new Parameter(p.Name, p.ParameterType)).ToArray());
public static MethodInfo? FindMethodOnObject(
object targetObject,
Method method,
Parameter[] parameters,
MethodFindingStrategy strategy = MethodFindingStrategy.MethodNameMustMatch |
MethodFindingStrategy.MethodReturnTypeMustMatch |
MethodFindingStrategy.ParameterCountMustMatch |
MethodFindingStrategy.ParameterTypeMustMatch,
bool throwOnError = false)
{
bool isNameCorrect(MethodInfo targetMethod) => targetMethod.Name == method.Name;
// First, find by method name
var targetMethods = targetObject.GetType().GetMethods().AsEnumerable();
if (strategy.HasFlag(MethodFindingStrategy.MethodNameMustMatch))
targetMethods = targetMethods.Where(isNameCorrect);
if (!targetMethods.Any())
if (throwOnError)
throw new PriseProxyException(
$"Target method {method.Name} is not found on Proxy Type {targetObject.GetType().Name}.");
else
return null;
if (targetMethods.Count() == 1)
return targetMethods.First();
bool isReturnTypeCorrect(MethodInfo targetMethod) => targetMethod.ReturnType == method.ReturnType;
if (strategy.HasFlag(MethodFindingStrategy.MethodReturnTypeMustMatch))
// Second, find by method name AND return type
targetMethods = targetMethods.Where(isReturnTypeCorrect);
if (targetMethods.Count() == 1)
return targetMethods.First();
bool isParameterCountCorrect(MethodInfo targetMethod) =>
targetMethod.GetParameters().Count() == parameters.Length;
bool doAllParametersMatch(MethodInfo targetMethod)
{
var callingMethodParameters = parameters;
var targetMethodParameters = targetMethod.GetParameters();
for (var index = 0; index < callingMethodParameters.Count(); index++)
{
var callingParam = callingMethodParameters[index];
if (callingParam.Type is null)
throw new PriseProxyException(
$"When using {nameof(MethodFindingStrategy.ParameterTypeMustMatch)}, Parameter.Type must be provided");
var targetParam = targetMethodParameters[index];
if (!(targetParam.Name == callingParam.Name &&
targetParam.ParameterType.Name == callingParam.Type.Name))
return false;
}
return true;
}
targetMethods = targetMethods.Where(targetMethod =>
(!strategy.HasFlag(MethodFindingStrategy.ParameterCountMustMatch) ||
isParameterCountCorrect(targetMethod)) &&
(!strategy.HasFlag(MethodFindingStrategy.ParameterTypeMustMatch) || doAllParametersMatch(targetMethod))
);
if (!targetMethods.Any())
if (throwOnError)
throw new PriseProxyException(
$"Target method {method.Name} is not found on Proxy Type {targetObject.GetType().Name}.");
else
return null;
if (targetMethods.Count() > 1)
if (throwOnError)
throw new PriseProxyException(
$"Target method {method.Name} could not be determined on object {targetObject.GetType().Name}.");
else
return null;
return targetMethods.First();
}
internal static object[] SerializeParameters(IParameterConverter parameterConverter, MethodInfo targetMethod,
object[] args)
{
var parameters = targetMethod.GetParameters();
var results = new List<object>();
for (var index = 0; index < parameters.Count(); index++)
{
var parameter = parameters[index];
var parameterValue = args[index];
if (parameter.ParameterType.BaseType == typeof(System.MulticastDelegate))
{
if (parameter.ParameterType.GenericTypeArguments.Any(g => g != typeof(EventArgs)))
throw new PriseProxyException($"Custom EventArgs are not supported in Prise");
results.Add(parameterValue);
continue;
}
object result = null;
if (parameter.ParameterType.IsGenericParameter)
{
var runtimeType = parameterValue.GetType();
result = parameterConverter.ConvertToRemoteType(runtimeType, parameterValue);
}
else
result = parameterConverter.ConvertToRemoteType(parameter.ParameterType, parameterValue);
results.Add(result);
}
return results.ToArray();
}
}
/// <summary>
/// This is the PriseProxy wrapper class that will acts as the communication layer between the Host and the Plugin.
/// Every call from the Host to the Plugin will go through here.
/// </summary>
/// <typeparam name="T">The Plugin type</typeparam>
public class PriseProxy<T> : DispatchProxy, IDisposable
{
private IParameterConverter parameterConverter;
private IResultConverter resultConverter;
private object remoteObject;
protected bool disposed = false;
protected override object Invoke(MethodInfo targetMethod, object[] args) => PriseProxy.Invoke(this.remoteObject,
targetMethod, args, this.parameterConverter, this.resultConverter);
public static object Create() => Create<T, PriseProxy<T>>();
internal PriseProxy<T> SetRemoteObject(object remoteObject)
{
if (remoteObject == null)
throw new PriseProxyException($"Remote object for Proxy<{typeof(T).Name}> was null");
this.remoteObject = remoteObject;
return this;
}
internal PriseProxy<T> SetParameterConverter(IParameterConverter parameterConverter)
{
if (parameterConverter == null)
throw new PriseProxyException($"IParameterConverter for Proxy<{typeof(T).Name}> was null");
this.parameterConverter = parameterConverter;
return this;
}
internal PriseProxy<T> SetResultConverter(IResultConverter resultConverter)
{
if (resultConverter == null)
throw new PriseProxyException($"IResultConverter for Proxy<{typeof(T).Name}> was null");
this.resultConverter = resultConverter;
return this;
}
protected virtual void Dispose(bool disposing)
{
if (!this.disposed && disposing)
{
this.parameterConverter = null;
this.resultConverter = null;
this.remoteObject = null;
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}

View File

@ -1,25 +0,0 @@
using System;
using System.Runtime.Serialization;
namespace Prise.Proxy
{
[Serializable]
public class PriseProxyException : Exception
{
public PriseProxyException(string message) : base(message)
{
}
public PriseProxyException(string message, Exception innerException) : base(message, innerException)
{
}
public PriseProxyException()
{
}
protected PriseProxyException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
}
}

View File

@ -1,32 +0,0 @@
using System;
namespace Prise.Proxy
{
public static class ProxyCreator
{
public static object CreateGenericProxy(Type proxyType, object remoteObject)
{
return typeof(ProxyCreator).GetMethod(nameof(ProxyCreator.CreateProxy)).MakeGenericMethod(proxyType).Invoke(null, new[] { remoteObject, null, null });
}
public static TProxyType CreateProxy<TProxyType>(
object remoteObject,
IParameterConverter parameterConverter = null,
IResultConverter resultConverter = null)
{
if (parameterConverter == null)
parameterConverter = new PassthroughParameterConverter();
if (resultConverter == null)
resultConverter = new PassthroughResultConverter();
var proxy = PriseProxy<TProxyType>.Create();
((PriseProxy<TProxyType>)proxy)
.SetRemoteObject(remoteObject)
.SetParameterConverter(parameterConverter)
.SetResultConverter(resultConverter);
return (TProxyType)proxy;
}
}
}

View File

@ -1,63 +0,0 @@
using System;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
namespace Prise.Proxy
{
public abstract class ResultConverter : IResultConverter
{
private bool disposed = false;
public abstract object Deserialize(Type localType, Type remoteType, object value);
public object ConvertToLocalType(Type localType, Type remoteType, object value)
{
return Deserialize(localType, remoteType, value);
}
public object ConvertToLocalTypeAsync(Type localType, Type remoteType, Task task)
{
var taskResultType = localType.GenericTypeArguments != null && localType.GenericTypeArguments.Any() ? localType.GenericTypeArguments[0] : null;
var taskCompletionSource = new TaskCompletionSource(taskResultType ?? typeof(object));
task.ContinueWith(t =>
{
if (t.IsCanceled)
taskCompletionSource.TrySetCanceled();
else if (t.IsFaulted)
taskCompletionSource.TrySetException(t.Exception);
else if (taskResultType == null)
taskCompletionSource.TrySetResult(null);
else
{
var property = t.GetType()
.GetTypeInfo()
.GetProperties()
.FirstOrDefault(p => p.Name == "Result");
if (property != null)
{
var value = Deserialize(localType, remoteType, property.GetValue(task));
taskCompletionSource.TrySetResult(value);
}
}
});
return taskCompletionSource.Task;
}
protected virtual void Dispose(bool disposing)
{
if (!this.disposed && disposing)
{
// Nothing to do here
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}

View File

@ -1,56 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
namespace Prise.Proxy
{
/// <summary>
/// This is a non-generic TaskCompletionSource<T>
/// It allows you to set a type via its constructor
/// </summary>
public class TaskCompletionSource
{
private readonly Type type;
private readonly object taskCompletionSource;
public TaskCompletionSource(Type type)
{
this.type = type;
this.taskCompletionSource = typeof(TaskCompletionSource<>)
.MakeGenericType(type)
.GetConstructors(BindingFlags.Public | BindingFlags.Instance)[0]
.Invoke(null);
}
public bool TrySetCanceled()
{
var trySetCanceled = taskCompletionSource.GetType().GetMethod("TrySetCanceled");
return (bool)trySetCanceled.Invoke(this.taskCompletionSource, null);
}
public bool TrySetException(Exception ex)
{
var trySetException = taskCompletionSource.GetType()
.GetMethods()
.First(m => m.Name == "TrySetException" && m.GetParameters().First().ParameterType == typeof(IEnumerable<Exception>));
return (bool)trySetException.Invoke(this.taskCompletionSource, new[] { new[] { ex } });
}
public bool TrySetResult(object result)
{
var trySetResult = taskCompletionSource.GetType().GetMethod("TrySetResult");
return (bool)trySetResult.Invoke(this.taskCompletionSource, new[] { result });
}
public Task Task
{
get
{
var taskProperty = taskCompletionSource.GetType().GetProperty("Task");
return taskProperty.GetValue(this.taskCompletionSource) as Task;
}
}
}
}

View File

@ -1,38 +0,0 @@
namespace System.Reflection
{
/// <summary>
/// DispatchProxy provides a mechanism for the instantiation of proxy objects and handling of
/// their method dispatch.
/// Original file: https://github.com/dotnet/runtime/blob/6072e4d3a7a2a1493f514cdf4be75a3d56580e84/src/libraries/System.Reflection.DispatchProxy/src/System/Reflection/DispatchProxy.cs
/// </summary>
public abstract class DispatchProxy
{
protected DispatchProxy()
{
}
/// <summary>
/// Whenever any method on the generated proxy type is called, this method
/// will be invoked to dispatch control.
/// </summary>
/// <param name="targetMethod">The method the caller invoked</param>
/// <param name="args">The arguments the caller passed to the method</param>
/// <returns>The object to return to the caller, or <c>null</c> for void methods</returns>
protected abstract object? Invoke(MethodInfo? targetMethod, object?[]? args);
/// <summary>
/// Creates an object instance that derives from class <typeparamref name="TProxy"/>
/// and implements interface <typeparamref name="T"/>.
/// </summary>
/// <typeparam name="T">The interface the proxy should implement.</typeparam>
/// <typeparam name="TProxy">The base class to use for the proxy class.</typeparam>
/// <returns>An object instance that implements <typeparamref name="T"/>.</returns>
/// <exception cref="System.ArgumentException"><typeparamref name="T"/> is a class,
/// or <typeparamref name="TProxy"/> is sealed or does not have a parameterless constructor</exception>
public static T Create<T, TProxy>()
where TProxy : DispatchProxy
{
return (T)DispatchProxyGenerator.CreateProxyInstance(typeof(TProxy), typeof(T));
}
}
}

View File

@ -1,935 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// Original file: https://github.com/dotnet/runtime/blob/6072e4d3a7a2a1493f514cdf4be75a3d56580e84/src/libraries/System.Reflection.DispatchProxy/src/System/Reflection/DispatchProxyGenerator.cs
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.ExceptionServices;
using System.Threading;
namespace System.Reflection
{
// Helper class to handle the IL EMIT for the generation of proxies.
// Much of this code was taken directly from the Silverlight proxy generation.
// Differences between this and the Silverlight version are:
// 1. This version is based on DispatchProxy from NET Native and CoreCLR, not RealProxy in Silverlight ServiceModel.
// There are several notable differences between them.
// 2. Both DispatchProxy and RealProxy permit the caller to ask for a proxy specifying a pair of types:
// the interface type to implement, and a base type. But they behave slightly differently:
// - RealProxy generates a proxy type that derives from Object and *implements" all the base type's
// interfaces plus all the interface type's interfaces.
// - DispatchProxy generates a proxy type that *derives* from the base type and implements all
// the interface type's interfaces. This is true for both the CLR version in NET Native and this
// version for CoreCLR.
// 3. DispatchProxy and RealProxy use different type hierarchies for the generated proxies:
// - RealProxy type hierarchy is:
// proxyType : proxyBaseType : object
// Presumably the 'proxyBaseType' in the middle is to allow it to implement the base type's interfaces
// explicitly, preventing collision for same name methods on the base and interface types.
// - DispatchProxy hierarchy is:
// proxyType : baseType (where baseType : DispatchProxy)
// The generated DispatchProxy proxy type does not need to generate implementation methods
// for the base type's interfaces, because the base type already must have implemented them.
// 4. RealProxy required a proxy instance to hold a backpointer to the RealProxy instance to mirror
// the .NET Remoting design that required the proxy and RealProxy to be separate instances.
// But the DispatchProxy design encourages the proxy type to *be* an DispatchProxy. Therefore,
// the proxy's 'this' becomes the equivalent of RealProxy's backpointer to RealProxy, so we were
// able to remove an extraneous field and ctor arg from the DispatchProxy proxies.
//
internal static class DispatchProxyGenerator
{
// Generated proxies have a private Action field that all generated methods
// invoke. It is the first field in the class and the first ctor parameter.
private const int InvokeActionFieldAndCtorParameterIndex = 0;
// Proxies are requested for a pair of types: base type and interface type.
// The generated proxy will subclass the given base type and implement the interface type.
// We maintain a cache keyed by 'base type' containing a dictionary keyed by interface type,
// containing the generated proxy type for that pair. There are likely to be few (maybe only 1)
// base type in use for many interface types.
// Note: this differs from Silverlight's RealProxy implementation which keys strictly off the
// interface type. But this does not allow the same interface type to be used with more than a
// single base type. The implementation here permits multiple interface types to be used with
// multiple base types, and the generated proxy types will be unique.
// This cache of generated types grows unbounded, one element per unique T/ProxyT pair.
// This approach is used to prevent regenerating identical proxy types for identical T/Proxy pairs,
// which would ultimately be a more expensive leak.
// Proxy instances are not cached. Their lifetime is entirely owned by the caller of DispatchProxy.Create.
private static readonly Dictionary<Type, Dictionary<Type, Type>> s_baseTypeAndInterfaceToGeneratedProxyType = new Dictionary<Type, Dictionary<Type, Type>>();
private static readonly ProxyAssembly s_proxyAssembly = new ProxyAssembly();
private static readonly MethodInfo s_dispatchProxyInvokeMethod = typeof(DispatchProxy).GetTypeInfo().GetDeclaredMethod("Invoke")!;
// Returns a new instance of a proxy the derives from 'baseType' and implements 'interfaceType'
internal static object CreateProxyInstance(Type baseType, Type interfaceType)
{
Debug.Assert(baseType != null);
Debug.Assert(interfaceType != null);
Type proxiedType = GetProxyType(baseType!, interfaceType!);
return Activator.CreateInstance(proxiedType, (Action<object[]>)DispatchProxyGenerator.Invoke)!;
}
private static Type GetProxyType(Type baseType, Type interfaceType)
{
lock (s_baseTypeAndInterfaceToGeneratedProxyType)
{
if (!s_baseTypeAndInterfaceToGeneratedProxyType.TryGetValue(baseType, out Dictionary<Type, Type>? interfaceToProxy))
{
interfaceToProxy = new Dictionary<Type, Type>();
s_baseTypeAndInterfaceToGeneratedProxyType[baseType] = interfaceToProxy;
}
if (!interfaceToProxy.TryGetValue(interfaceType, out Type? generatedProxy))
{
generatedProxy = GenerateProxyType(baseType, interfaceType);
interfaceToProxy[interfaceType] = generatedProxy;
}
return generatedProxy;
}
}
// Unconditionally generates a new proxy type derived from 'baseType' and implements 'interfaceType'
private static Type GenerateProxyType(Type baseType, Type interfaceType)
{
// Parameter validation is deferred until the point we need to create the proxy.
// This prevents unnecessary overhead revalidating cached proxy types.
TypeInfo baseTypeInfo = baseType.GetTypeInfo();
// The interface type must be an interface, not a class
if (!interfaceType.GetTypeInfo().IsInterface)
{
// "T" is the generic parameter seen via the public contract
throw new ArgumentException("SR.Format(SR.InterfaceType_Must_Be_Interface, interfaceType.FullName)", "T");
}
// The base type cannot be sealed because the proxy needs to subclass it.
if (baseTypeInfo.IsSealed)
{
// "TProxy" is the generic parameter seen via the public contract
throw new ArgumentException("SR.Format(SR.BaseType_Cannot_Be_Sealed, baseTypeInfo.FullName)", "TProxy");
}
// The base type cannot be abstract
if (baseTypeInfo.IsAbstract)
{
throw new ArgumentException("SR.Format(SR.BaseType_Cannot_Be_Abstract, baseType.FullName)", "TProxy");
}
// The base type must have a public default ctor
if (!baseTypeInfo.DeclaredConstructors.Any(c => c.IsPublic && c.GetParameters().Length == 0))
{
throw new ArgumentException("SR.Format(SR.BaseType_Must_Have_Default_Ctor, baseType.FullName)", "TProxy");
}
// Create a type that derives from 'baseType' provided by caller
ProxyBuilder pb = s_proxyAssembly.CreateProxy("generatedProxy", baseType);
foreach (Type t in interfaceType.GetTypeInfo().ImplementedInterfaces)
pb.AddInterfaceImpl(t);
pb.AddInterfaceImpl(interfaceType);
Type generatedProxyType = pb.CreateType();
return generatedProxyType;
}
// All generated proxy methods call this static helper method to dispatch.
// Its job is to unpack the arguments and the 'this' instance and to dispatch directly
// to the (abstract) DispatchProxy.Invoke() method.
private static void Invoke(object?[] args)
{
PackedArgs packed = new PackedArgs(args);
MethodBase method = s_proxyAssembly.ResolveMethodToken(packed.DeclaringType, packed.MethodToken);
if (method.IsGenericMethodDefinition)
method = ((MethodInfo)method).MakeGenericMethod(packed.GenericTypes!);
// Call (protected method) DispatchProxy.Invoke()
try
{
Debug.Assert(s_dispatchProxyInvokeMethod != null);
object? returnValue = s_dispatchProxyInvokeMethod!.Invoke(packed.DispatchProxy,
new object?[] { method, packed.Args });
packed.ReturnValue = returnValue;
}
catch (TargetInvocationException tie)
{
Debug.Assert(tie.InnerException != null);
ExceptionDispatchInfo.Capture(tie.InnerException).Throw();
}
}
private class PackedArgs
{
internal const int DispatchProxyPosition = 0;
internal const int DeclaringTypePosition = 1;
internal const int MethodTokenPosition = 2;
internal const int ArgsPosition = 3;
internal const int GenericTypesPosition = 4;
internal const int ReturnValuePosition = 5;
internal static readonly Type[] PackedTypes = new Type[] { typeof(object), typeof(Type), typeof(int), typeof(object[]), typeof(Type[]), typeof(object) };
private readonly object?[] _args;
internal PackedArgs() : this(new object[PackedTypes.Length]) { }
internal PackedArgs(object?[] args) { _args = args; }
internal DispatchProxy? DispatchProxy { get { return (DispatchProxy?)_args[DispatchProxyPosition]; } }
internal Type? DeclaringType { get { return (Type?)_args[DeclaringTypePosition]; } }
internal int MethodToken { get { return (int)_args[MethodTokenPosition]!; } }
internal object[]? Args { get { return (object[]?)_args[ArgsPosition]; } }
internal Type[]? GenericTypes { get { return (Type[]?)_args[GenericTypesPosition]; } }
internal object? ReturnValue { /*get { return args[ReturnValuePosition]; }*/ set { _args[ReturnValuePosition] = value; } }
}
private class ProxyAssembly
{
private readonly AssemblyBuilder _ab;
private readonly ModuleBuilder _mb;
private int _typeId;
// Maintain a MethodBase-->int, int-->MethodBase mapping to permit generated code
// to pass methods by token
private readonly Dictionary<MethodBase, int> _methodToToken = new Dictionary<MethodBase, int>();
private readonly List<MethodBase> _methodsByToken = new List<MethodBase>();
private readonly HashSet<string?> _ignoresAccessAssemblyNames = new HashSet<string?>();
private ConstructorInfo? _ignoresAccessChecksToAttributeConstructor;
public ProxyAssembly()
{
_ab = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("ProxyBuilder"), AssemblyBuilderAccess.Run);
_mb = _ab.DefineDynamicModule("testmod");
}
// Gets or creates the ConstructorInfo for the IgnoresAccessChecksAttribute.
// This attribute is both defined and referenced in the dynamic assembly to
// allow access to internal types in other assemblies.
internal ConstructorInfo IgnoresAccessChecksAttributeConstructor
{
get
{
if (_ignoresAccessChecksToAttributeConstructor == null)
{
_ignoresAccessChecksToAttributeConstructor = IgnoreAccessChecksToAttributeBuilder.AddToModule(_mb);
}
return null;
}
}
public ProxyBuilder CreateProxy(string name, Type proxyBaseType)
{
int nextId = Interlocked.Increment(ref _typeId);
TypeBuilder tb = _mb.DefineType(name + "_" + nextId, TypeAttributes.Public, proxyBaseType);
return new ProxyBuilder(this, tb, proxyBaseType);
}
// Generates an instance of the IgnoresAccessChecksToAttribute to
// identify the given assembly as one which contains internal types
// the dynamic assembly will need to reference.
internal void GenerateInstanceOfIgnoresAccessChecksToAttribute(string assemblyName)
{
// Add this assembly level attribute:
// [assembly: System.Runtime.CompilerServices.IgnoresAccessChecksToAttribute(assemblyName)]
ConstructorInfo attributeConstructor = IgnoresAccessChecksAttributeConstructor;
CustomAttributeBuilder customAttributeBuilder =
new CustomAttributeBuilder(attributeConstructor, new object[] { assemblyName });
_ab.SetCustomAttribute(customAttributeBuilder);
}
// Ensures the type we will reference from the dynamic assembly
// is visible. Non-public types need to emit an attribute that
// allows access from the dynamic assembly.
internal void EnsureTypeIsVisible(Type type)
{
TypeInfo typeInfo = type.GetTypeInfo();
if (!typeInfo.IsVisible)
{
string assemblyName = typeInfo.Assembly.GetName().Name!;
if (!_ignoresAccessAssemblyNames.Contains(assemblyName))
{
GenerateInstanceOfIgnoresAccessChecksToAttribute(assemblyName);
_ignoresAccessAssemblyNames.Add(assemblyName);
}
}
}
internal void GetTokenForMethod(MethodBase method, out Type type, out int token)
{
Debug.Assert(method.DeclaringType != null);
type = method.DeclaringType!;
token = 0;
if (!_methodToToken.TryGetValue(method, out token))
{
_methodsByToken.Add(method);
token = _methodsByToken.Count - 1;
_methodToToken[method] = token;
}
}
internal MethodBase ResolveMethodToken(Type? type, int token)
{
Debug.Assert(token >= 0 && token < _methodsByToken.Count);
return _methodsByToken[token];
}
}
private class ProxyBuilder
{
private static readonly MethodInfo s_delegateInvoke = typeof(Action<object[]>).GetTypeInfo().GetDeclaredMethod("Invoke")!;
private readonly ProxyAssembly _assembly;
private readonly TypeBuilder _tb;
private readonly Type _proxyBaseType;
private readonly List<FieldBuilder> _fields;
internal ProxyBuilder(ProxyAssembly assembly, TypeBuilder tb, Type proxyBaseType)
{
_assembly = assembly;
_tb = tb;
_proxyBaseType = proxyBaseType;
_fields = new List<FieldBuilder>();
_fields.Add(tb.DefineField("invoke", typeof(Action<object[]>), FieldAttributes.Private));
}
private void Complete()
{
Type[] args = new Type[_fields.Count];
for (int i = 0; i < args.Length; i++)
{
args[i] = _fields[i].FieldType;
}
ConstructorBuilder cb = _tb.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, args);
ILGenerator il = cb.GetILGenerator();
// chained ctor call
ConstructorInfo? baseCtor = _proxyBaseType.GetTypeInfo().DeclaredConstructors.SingleOrDefault(c => c.IsPublic && c.GetParameters().Length == 0);
Debug.Assert(baseCtor != null);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, baseCtor!);
// store all the fields
for (int i = 0; i < args.Length; i++)
{
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg, i + 1);
il.Emit(OpCodes.Stfld, _fields[i]);
}
il.Emit(OpCodes.Ret);
}
internal Type CreateType()
{
this.Complete();
return _tb.CreateTypeInfo()!.AsType();
}
internal void AddInterfaceImpl(Type iface)
{
// If necessary, generate an attribute to permit visibility
// to internal types.
_assembly.EnsureTypeIsVisible(iface);
_tb.AddInterfaceImplementation(iface);
// AccessorMethods -> Metadata mappings.
var propertyMap = new Dictionary<MethodInfo, PropertyAccessorInfo>(MethodInfoEqualityComparer.Instance);
foreach (PropertyInfo pi in iface.GetRuntimeProperties())
{
var ai = new PropertyAccessorInfo(pi.GetMethod, pi.SetMethod);
if (pi.GetMethod != null)
propertyMap[pi.GetMethod] = ai;
if (pi.SetMethod != null)
propertyMap[pi.SetMethod] = ai;
}
var eventMap = new Dictionary<MethodInfo, EventAccessorInfo>(MethodInfoEqualityComparer.Instance);
foreach (EventInfo ei in iface.GetRuntimeEvents())
{
var ai = new EventAccessorInfo(ei.AddMethod, ei.RemoveMethod, ei.RaiseMethod);
if (ei.AddMethod != null)
eventMap[ei.AddMethod] = ai;
if (ei.RemoveMethod != null)
eventMap[ei.RemoveMethod] = ai;
if (ei.RaiseMethod != null)
eventMap[ei.RaiseMethod] = ai;
}
foreach (MethodInfo mi in iface.GetRuntimeMethods())
{
// Skip regular/non-virtual instance methods, static methods, and methods that cannot be overriden
// ("methods that cannot be overriden" includes default implementation of other interface methods).
if (!mi.IsVirtual || mi.IsFinal)
continue;
MethodBuilder mdb = AddMethodImpl(mi);
if (propertyMap.TryGetValue(mi, out PropertyAccessorInfo? associatedProperty))
{
if (MethodInfoEqualityComparer.Instance.Equals(associatedProperty.InterfaceGetMethod, mi))
associatedProperty.GetMethodBuilder = mdb;
else
associatedProperty.SetMethodBuilder = mdb;
}
if (eventMap.TryGetValue(mi, out EventAccessorInfo? associatedEvent))
{
if (MethodInfoEqualityComparer.Instance.Equals(associatedEvent.InterfaceAddMethod, mi))
associatedEvent.AddMethodBuilder = mdb;
else if (MethodInfoEqualityComparer.Instance.Equals(associatedEvent.InterfaceRemoveMethod, mi))
associatedEvent.RemoveMethodBuilder = mdb;
else
associatedEvent.RaiseMethodBuilder = mdb;
}
}
foreach (PropertyInfo pi in iface.GetRuntimeProperties())
{
PropertyAccessorInfo ai = propertyMap[pi.GetMethod ?? pi.SetMethod!];
// If we didn't make an overriden accessor above, this was a static property, non-virtual property,
// or a default implementation of a property of a different interface. In any case, we don't need
// to redeclare it.
if (ai.GetMethodBuilder == null && ai.SetMethodBuilder == null)
continue;
PropertyBuilder pb = _tb.DefineProperty(pi.Name, pi.Attributes, pi.PropertyType, pi.GetIndexParameters().Select(p => p.ParameterType).ToArray());
if (ai.GetMethodBuilder != null)
pb.SetGetMethod(ai.GetMethodBuilder);
if (ai.SetMethodBuilder != null)
pb.SetSetMethod(ai.SetMethodBuilder);
}
foreach (EventInfo ei in iface.GetRuntimeEvents())
{
EventAccessorInfo ai = eventMap[ei.AddMethod ?? ei.RemoveMethod!];
// If we didn't make an overriden accessor above, this was a static event, non-virtual event,
// or a default implementation of an event of a different interface. In any case, we don't
// need to redeclare it.
if (ai.AddMethodBuilder == null && ai.RemoveMethodBuilder == null && ai.RaiseMethodBuilder == null)
continue;
Debug.Assert(ei.EventHandlerType != null);
EventBuilder eb = _tb.DefineEvent(ei.Name, ei.Attributes, ei.EventHandlerType!);
if (ai.AddMethodBuilder != null)
eb.SetAddOnMethod(ai.AddMethodBuilder);
if (ai.RemoveMethodBuilder != null)
eb.SetRemoveOnMethod(ai.RemoveMethodBuilder);
if (ai.RaiseMethodBuilder != null)
eb.SetRaiseMethod(ai.RaiseMethodBuilder);
}
}
private MethodBuilder AddMethodImpl(MethodInfo mi)
{
ParameterInfo[] parameters = mi.GetParameters();
Type[] paramTypes = ParamTypes(parameters, false);
MethodBuilder mdb = _tb.DefineMethod(mi.Name, MethodAttributes.Public | MethodAttributes.Virtual, mi.ReturnType, paramTypes);
if (mi.ContainsGenericParameters)
{
Type[] ts = mi.GetGenericArguments();
string[] ss = new string[ts.Length];
for (int i = 0; i < ts.Length; i++)
{
ss[i] = ts[i].Name;
}
GenericTypeParameterBuilder[] genericParameters = mdb.DefineGenericParameters(ss);
for (int i = 0; i < genericParameters.Length; i++)
{
genericParameters[i].SetGenericParameterAttributes(ts[i].GetTypeInfo().GenericParameterAttributes);
}
}
ILGenerator il = mdb.GetILGenerator();
ParametersArray args = new ParametersArray(il, paramTypes);
// object[] args = new object[paramCount];
il.Emit(OpCodes.Nop);
GenericArray<object> argsArr = new GenericArray<object>(il, ParamTypes(parameters, true).Length);
for (int i = 0; i < parameters.Length; i++)
{
// args[i] = argi;
bool isOutRef = parameters[i].IsOut && parameters[i].ParameterType.IsByRef && !parameters[i].IsIn;
if (!isOutRef)
{
argsArr.BeginSet(i);
args.Get(i);
argsArr.EndSet(parameters[i].ParameterType);
}
}
// object[] packed = new object[PackedArgs.PackedTypes.Length];
GenericArray<object> packedArr = new GenericArray<object>(il, PackedArgs.PackedTypes.Length);
// packed[PackedArgs.DispatchProxyPosition] = this;
packedArr.BeginSet(PackedArgs.DispatchProxyPosition);
il.Emit(OpCodes.Ldarg_0);
packedArr.EndSet(typeof(DispatchProxy));
// packed[PackedArgs.DeclaringTypePosition] = typeof(iface);
MethodInfo Type_GetTypeFromHandle = typeof(Type).GetRuntimeMethod("GetTypeFromHandle", new Type[] { typeof(RuntimeTypeHandle) })!;
_assembly.GetTokenForMethod(mi, out Type declaringType, out int methodToken);
packedArr.BeginSet(PackedArgs.DeclaringTypePosition);
il.Emit(OpCodes.Ldtoken, declaringType);
il.Emit(OpCodes.Call, Type_GetTypeFromHandle);
packedArr.EndSet(typeof(object));
// packed[PackedArgs.MethodTokenPosition] = iface method token;
packedArr.BeginSet(PackedArgs.MethodTokenPosition);
il.Emit(OpCodes.Ldc_I4, methodToken);
packedArr.EndSet(typeof(int));
// packed[PackedArgs.ArgsPosition] = args;
packedArr.BeginSet(PackedArgs.ArgsPosition);
argsArr.Load();
packedArr.EndSet(typeof(object[]));
// packed[PackedArgs.GenericTypesPosition] = mi.GetGenericArguments();
if (mi.ContainsGenericParameters)
{
packedArr.BeginSet(PackedArgs.GenericTypesPosition);
Type[] genericTypes = mi.GetGenericArguments();
GenericArray<Type> typeArr = new GenericArray<Type>(il, genericTypes.Length);
for (int i = 0; i < genericTypes.Length; ++i)
{
typeArr.BeginSet(i);
il.Emit(OpCodes.Ldtoken, genericTypes[i]);
il.Emit(OpCodes.Call, Type_GetTypeFromHandle);
typeArr.EndSet(typeof(Type));
}
typeArr.Load();
packedArr.EndSet(typeof(Type[]));
}
// Call static DispatchProxyHelper.Invoke(object[])
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, _fields[InvokeActionFieldAndCtorParameterIndex]); // delegate
packedArr.Load();
il.Emit(OpCodes.Call, s_delegateInvoke);
for (int i = 0; i < parameters.Length; i++)
{
if (parameters[i].ParameterType.IsByRef)
{
args.BeginSet(i);
argsArr.Get(i);
args.EndSet(i, typeof(object));
}
}
if (mi.ReturnType != typeof(void))
{
packedArr.Get(PackedArgs.ReturnValuePosition);
Convert(il, typeof(object), mi.ReturnType, false);
}
il.Emit(OpCodes.Ret);
_tb.DefineMethodOverride(mdb, mi);
return mdb;
}
private static Type[] ParamTypes(ParameterInfo[] parms, bool noByRef)
{
Type[] types = new Type[parms.Length];
for (int i = 0; i < parms.Length; i++)
{
types[i] = parms[i].ParameterType;
if (noByRef && types[i].IsByRef)
types[i] = types[i].GetElementType()!;
}
return types;
}
// TypeCode does not exist in ProjectK or ProjectN.
// This lookup method was copied from PortableLibraryThunks\Internal\PortableLibraryThunks\System\TypeThunks.cs
// but returns the integer value equivalent to its TypeCode enum.
private static int GetTypeCode(Type? type)
{
if (type == null)
return 0; // TypeCode.Empty;
if (type == typeof(bool))
return 3; // TypeCode.Boolean;
if (type == typeof(char))
return 4; // TypeCode.Char;
if (type == typeof(sbyte))
return 5; // TypeCode.SByte;
if (type == typeof(byte))
return 6; // TypeCode.Byte;
if (type == typeof(short))
return 7; // TypeCode.Int16;
if (type == typeof(ushort))
return 8; // TypeCode.UInt16;
if (type == typeof(int))
return 9; // TypeCode.Int32;
if (type == typeof(uint))
return 10; // TypeCode.UInt32;
if (type == typeof(long))
return 11; // TypeCode.Int64;
if (type == typeof(ulong))
return 12; // TypeCode.UInt64;
if (type == typeof(float))
return 13; // TypeCode.Single;
if (type == typeof(double))
return 14; // TypeCode.Double;
if (type == typeof(decimal))
return 15; // TypeCode.Decimal;
if (type == typeof(DateTime))
return 16; // TypeCode.DateTime;
if (type == typeof(string))
return 18; // TypeCode.String;
if (type.GetTypeInfo().IsEnum)
return GetTypeCode(Enum.GetUnderlyingType(type));
return 1; // TypeCode.Object;
}
private static readonly OpCode[] s_convOpCodes = new OpCode[] {
OpCodes.Nop, //Empty = 0,
OpCodes.Nop, //Object = 1,
OpCodes.Nop, //DBNull = 2,
OpCodes.Conv_I1, //Boolean = 3,
OpCodes.Conv_I2, //Char = 4,
OpCodes.Conv_I1, //SByte = 5,
OpCodes.Conv_U1, //Byte = 6,
OpCodes.Conv_I2, //Int16 = 7,
OpCodes.Conv_U2, //UInt16 = 8,
OpCodes.Conv_I4, //Int32 = 9,
OpCodes.Conv_U4, //UInt32 = 10,
OpCodes.Conv_I8, //Int64 = 11,
OpCodes.Conv_U8, //UInt64 = 12,
OpCodes.Conv_R4, //Single = 13,
OpCodes.Conv_R8, //Double = 14,
OpCodes.Nop, //Decimal = 15,
OpCodes.Nop, //DateTime = 16,
OpCodes.Nop, //17
OpCodes.Nop, //String = 18,
};
private static readonly OpCode[] s_ldindOpCodes = new OpCode[] {
OpCodes.Nop, //Empty = 0,
OpCodes.Nop, //Object = 1,
OpCodes.Nop, //DBNull = 2,
OpCodes.Ldind_I1, //Boolean = 3,
OpCodes.Ldind_I2, //Char = 4,
OpCodes.Ldind_I1, //SByte = 5,
OpCodes.Ldind_U1, //Byte = 6,
OpCodes.Ldind_I2, //Int16 = 7,
OpCodes.Ldind_U2, //UInt16 = 8,
OpCodes.Ldind_I4, //Int32 = 9,
OpCodes.Ldind_U4, //UInt32 = 10,
OpCodes.Ldind_I8, //Int64 = 11,
OpCodes.Ldind_I8, //UInt64 = 12,
OpCodes.Ldind_R4, //Single = 13,
OpCodes.Ldind_R8, //Double = 14,
OpCodes.Nop, //Decimal = 15,
OpCodes.Nop, //DateTime = 16,
OpCodes.Nop, //17
OpCodes.Ldind_Ref, //String = 18,
};
private static readonly OpCode[] s_stindOpCodes = new OpCode[] {
OpCodes.Nop, //Empty = 0,
OpCodes.Nop, //Object = 1,
OpCodes.Nop, //DBNull = 2,
OpCodes.Stind_I1, //Boolean = 3,
OpCodes.Stind_I2, //Char = 4,
OpCodes.Stind_I1, //SByte = 5,
OpCodes.Stind_I1, //Byte = 6,
OpCodes.Stind_I2, //Int16 = 7,
OpCodes.Stind_I2, //UInt16 = 8,
OpCodes.Stind_I4, //Int32 = 9,
OpCodes.Stind_I4, //UInt32 = 10,
OpCodes.Stind_I8, //Int64 = 11,
OpCodes.Stind_I8, //UInt64 = 12,
OpCodes.Stind_R4, //Single = 13,
OpCodes.Stind_R8, //Double = 14,
OpCodes.Nop, //Decimal = 15,
OpCodes.Nop, //DateTime = 16,
OpCodes.Nop, //17
OpCodes.Stind_Ref, //String = 18,
};
private static void Convert(ILGenerator il, Type source, Type target, bool isAddress)
{
Debug.Assert(!target.IsByRef);
if (target == source)
return;
TypeInfo sourceTypeInfo = source.GetTypeInfo();
TypeInfo targetTypeInfo = target.GetTypeInfo();
if (source.IsByRef)
{
Debug.Assert(!isAddress);
Type argType = source.GetElementType()!;
Ldind(il, argType);
Convert(il, argType, target, isAddress);
return;
}
if (targetTypeInfo.IsValueType)
{
if (sourceTypeInfo.IsValueType)
{
OpCode opCode = s_convOpCodes[GetTypeCode(target)];
Debug.Assert(!opCode.Equals(OpCodes.Nop));
il.Emit(opCode);
}
else
{
Debug.Assert(sourceTypeInfo.IsAssignableFrom(targetTypeInfo));
il.Emit(OpCodes.Unbox, target);
if (!isAddress)
Ldind(il, target);
}
}
else if (targetTypeInfo.IsAssignableFrom(sourceTypeInfo))
{
if (sourceTypeInfo.IsValueType || source.IsGenericParameter)
{
if (isAddress)
Ldind(il, source);
il.Emit(OpCodes.Box, source);
}
}
else
{
Debug.Assert(sourceTypeInfo.IsAssignableFrom(targetTypeInfo) || targetTypeInfo.IsInterface || sourceTypeInfo.IsInterface);
if (target.IsGenericParameter)
{
il.Emit(OpCodes.Unbox_Any, target);
}
else
{
il.Emit(OpCodes.Castclass, target);
}
}
}
private static void Ldind(ILGenerator il, Type type)
{
OpCode opCode = s_ldindOpCodes[GetTypeCode(type)];
if (!opCode.Equals(OpCodes.Nop))
{
il.Emit(opCode);
}
else
{
il.Emit(OpCodes.Ldobj, type);
}
}
private static void Stind(ILGenerator il, Type type)
{
OpCode opCode = s_stindOpCodes[GetTypeCode(type)];
if (!opCode.Equals(OpCodes.Nop))
{
il.Emit(opCode);
}
else
{
il.Emit(OpCodes.Stobj, type);
}
}
private class ParametersArray
{
private readonly ILGenerator _il;
private readonly Type[] _paramTypes;
internal ParametersArray(ILGenerator il, Type[] paramTypes)
{
_il = il;
_paramTypes = paramTypes;
}
internal void Get(int i)
{
_il.Emit(OpCodes.Ldarg, i + 1);
}
internal void BeginSet(int i)
{
_il.Emit(OpCodes.Ldarg, i + 1);
}
internal void EndSet(int i, Type stackType)
{
Debug.Assert(_paramTypes[i].IsByRef);
Type argType = _paramTypes[i].GetElementType()!;
Convert(_il, stackType, argType, false);
Stind(_il, argType);
}
}
private class GenericArray<T>
{
private readonly ILGenerator _il;
private readonly LocalBuilder _lb;
internal GenericArray(ILGenerator il, int len)
{
_il = il;
_lb = il.DeclareLocal(typeof(T[]));
il.Emit(OpCodes.Ldc_I4, len);
il.Emit(OpCodes.Newarr, typeof(T));
il.Emit(OpCodes.Stloc, _lb);
}
internal void Load()
{
_il.Emit(OpCodes.Ldloc, _lb);
}
internal void Get(int i)
{
_il.Emit(OpCodes.Ldloc, _lb);
_il.Emit(OpCodes.Ldc_I4, i);
_il.Emit(OpCodes.Ldelem_Ref);
}
internal void BeginSet(int i)
{
_il.Emit(OpCodes.Ldloc, _lb);
_il.Emit(OpCodes.Ldc_I4, i);
}
internal void EndSet(Type stackType)
{
Convert(_il, stackType, typeof(T), false);
_il.Emit(OpCodes.Stelem_Ref);
}
}
private sealed class PropertyAccessorInfo
{
public MethodInfo? InterfaceGetMethod { get; }
public MethodInfo? InterfaceSetMethod { get; }
public MethodBuilder? GetMethodBuilder { get; set; }
public MethodBuilder? SetMethodBuilder { get; set; }
public PropertyAccessorInfo(MethodInfo? interfaceGetMethod, MethodInfo? interfaceSetMethod)
{
InterfaceGetMethod = interfaceGetMethod;
InterfaceSetMethod = interfaceSetMethod;
}
}
private sealed class EventAccessorInfo
{
public MethodInfo? InterfaceAddMethod { get; }
public MethodInfo? InterfaceRemoveMethod { get; }
public MethodInfo? InterfaceRaiseMethod { get; }
public MethodBuilder? AddMethodBuilder { get; set; }
public MethodBuilder? RemoveMethodBuilder { get; set; }
public MethodBuilder? RaiseMethodBuilder { get; set; }
public EventAccessorInfo(MethodInfo? interfaceAddMethod, MethodInfo? interfaceRemoveMethod, MethodInfo? interfaceRaiseMethod)
{
InterfaceAddMethod = interfaceAddMethod;
InterfaceRemoveMethod = interfaceRemoveMethod;
InterfaceRaiseMethod = interfaceRaiseMethod;
}
}
private sealed class MethodInfoEqualityComparer : EqualityComparer<MethodInfo>
{
public static readonly MethodInfoEqualityComparer Instance = new MethodInfoEqualityComparer();
private MethodInfoEqualityComparer() { }
public sealed override bool Equals(MethodInfo? left, MethodInfo? right)
{
if (ReferenceEquals(left, right))
return true;
if (left == null)
return right == null;
else if (right == null)
return false;
// This assembly should work in netstandard1.3,
// so we cannot use MemberInfo.MetadataToken here.
// Therefore, it compares honestly referring ECMA-335 I.8.6.1.6 Signature Matching.
if (!Equals(left.DeclaringType, right.DeclaringType))
return false;
if (!Equals(left.ReturnType, right.ReturnType))
return false;
if (left.CallingConvention != right.CallingConvention)
return false;
if (left.IsStatic != right.IsStatic)
return false;
if (left.Name != right.Name)
return false;
Type[] leftGenericParameters = left.GetGenericArguments();
Type[] rightGenericParameters = right.GetGenericArguments();
if (leftGenericParameters.Length != rightGenericParameters.Length)
return false;
for (int i = 0; i < leftGenericParameters.Length; i++)
{
if (!Equals(leftGenericParameters[i], rightGenericParameters[i]))
return false;
}
ParameterInfo[] leftParameters = left.GetParameters();
ParameterInfo[] rightParameters = right.GetParameters();
if (leftParameters.Length != rightParameters.Length)
return false;
for (int i = 0; i < leftParameters.Length; i++)
{
if (!Equals(leftParameters[i].ParameterType, rightParameters[i].ParameterType))
return false;
}
return true;
}
public sealed override int GetHashCode(MethodInfo obj)
{
if (obj == null)
return 0;
Debug.Assert(obj.DeclaringType != null);
int hashCode = obj.DeclaringType!.GetHashCode();
hashCode ^= obj.Name.GetHashCode();
foreach (ParameterInfo parameter in obj.GetParameters())
{
hashCode ^= parameter.ParameterType.GetHashCode();
}
return hashCode;
}
}
}
}
}

View File

@ -1,101 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
// Original File: https://github.com/dotnet/runtime/blob/6072e4d3a7a2a1493f514cdf4be75a3d56580e84/src/libraries/Common/src/System/Reflection/Emit/IgnoreAccessChecksToAttributeBuilder.cs
using System.Linq;
namespace System.Reflection.Emit
{
internal static class IgnoreAccessChecksToAttributeBuilder
{
/// <summary>
/// Generate the declaration for the IgnoresAccessChecksToAttribute type.
/// This attribute will be both defined and used in the dynamic assembly.
/// Each usage identifies the name of the assembly containing non-public
/// types the dynamic assembly needs to access. Normally those types
/// would be inaccessible, but this attribute allows them to be visible.
/// It works like a reverse InternalsVisibleToAttribute.
/// This method returns the ConstructorInfo of the generated attribute.
/// </summary>
public static ConstructorInfo AddToModule(ModuleBuilder mb)
{
TypeBuilder attributeTypeBuilder =
mb.DefineType("System.Runtime.CompilerServices.IgnoresAccessChecksToAttribute",
TypeAttributes.Public | TypeAttributes.Class,
typeof(Attribute));
// Create backing field as:
// private string assemblyName;
FieldBuilder assemblyNameField =
attributeTypeBuilder.DefineField("assemblyName", typeof(string), FieldAttributes.Private);
// Create ctor as:
// public IgnoresAccessChecksToAttribute(string)
ConstructorBuilder constructorBuilder = attributeTypeBuilder.DefineConstructor(MethodAttributes.Public,
CallingConventions.HasThis,
new Type[] { assemblyNameField.FieldType });
ILGenerator il = constructorBuilder.GetILGenerator();
// Create ctor body as:
// this.assemblyName = {ctor parameter 0}
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg, 1);
il.Emit(OpCodes.Stfld, assemblyNameField);
// return
il.Emit(OpCodes.Ret);
// Define property as:
// public string AssemblyName {get { return this.assemblyName; } }
_ = attributeTypeBuilder.DefineProperty(
"AssemblyName",
PropertyAttributes.None,
CallingConventions.HasThis,
returnType: typeof(string),
parameterTypes: null);
MethodBuilder getterMethodBuilder = attributeTypeBuilder.DefineMethod(
"get_AssemblyName",
MethodAttributes.Public,
CallingConventions.HasThis,
returnType: typeof(string),
parameterTypes: null);
// Generate body:
// return this.assemblyName;
il = getterMethodBuilder.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, assemblyNameField);
il.Emit(OpCodes.Ret);
// Generate the AttributeUsage attribute for this attribute type:
// [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
TypeInfo attributeUsageTypeInfo = typeof(AttributeUsageAttribute).GetTypeInfo();
// Find the ctor that takes only AttributeTargets
ConstructorInfo attributeUsageConstructorInfo =
attributeUsageTypeInfo.DeclaredConstructors
.Single(c => c.GetParameters().Length == 1 &&
c.GetParameters()[0].ParameterType == typeof(AttributeTargets));
// Find the property to set AllowMultiple
PropertyInfo allowMultipleProperty =
attributeUsageTypeInfo.DeclaredProperties
.Single(f => string.Equals(f.Name, "AllowMultiple"));
// Create a builder to construct the instance via the ctor and property
CustomAttributeBuilder customAttributeBuilder =
new CustomAttributeBuilder(attributeUsageConstructorInfo,
new object[] { AttributeTargets.Assembly },
new PropertyInfo[] { allowMultipleProperty },
new object[] { true });
// Attach this attribute instance to the newly defined attribute type
attributeTypeBuilder.SetCustomAttribute(customAttributeBuilder);
// Make the TypeInfo real so the constructor can be used.
return attributeTypeBuilder.CreateTypeInfo()!.DeclaredConstructors.Single();
}
}
}

View File

@ -1,62 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Title>Prise.ReverseProxy</Title>
<PackageId>Prise.ReverseProxy</PackageId>
<PackageDescription>Adds support for sharing services between a Prise Host and a Prise Plugin</PackageDescription>
<Authors>Maarten Merken</Authors>
<Company>MRKN</Company>
<PackageTags>plugin;framework;prise;decoupling;assembly;dispatchproxy;proxy</PackageTags>
<TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);CopyProjectReferencesToPackage</TargetsForTfmSpecificBuildOutput>
<Nullable>enable</Nullable>
<LangVersion>default</LangVersion>
<PackageLicenseUrl>https://raw.githubusercontent.com/merken/Prise/master/LICENSE</PackageLicenseUrl>
<PackageProjectUrl>https://github.com/merken/Prise</PackageProjectUrl>
<RepositoryUrl>https://github.com/merken/Prise.git</RepositoryUrl>
<RepositoryType>git</RepositoryType>
</PropertyGroup>
<Target DependsOnTargets="ResolveReferences" Name="CopyProjectReferencesToPackage">
<ItemGroup>
<BuildOutputInPackage Include="@(ReferenceCopyLocalPaths-&gt;WithMetadataValue('ReferenceSourceTarget', 'ProjectReference'))" />
</ItemGroup>
</Target>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="System.Text.Json" Version="4.6.1" />
<PackageReference Include="System.Reflection.Emit" Version="4.7.0" />
</ItemGroup>
<ItemGroup>
<Compile Include="../Prise.Proxy/runtime/DispatchProxy.cs" Link="DispatchProxy.cs" />
<Compile Include="../Prise.Proxy/runtime/DispatchProxyGenerator.cs" Link="DispatchProxyGenerator.cs" />
<Compile Include="../Prise.Proxy/runtime/IngoreAccessChecksToAttributeBuilder.cs" Link="IngoreAccessChecksToAttributeBuilder.cs" />
<Compile Include="../Prise.Proxy/PriseProxyException.cs" Link="PriseProxyException.cs" />
<Compile Include="../Prise.Proxy/Infrastructure/IParameterConverter.cs" Link="IParameterConverter.cs" />
<Compile Include="../Prise.Proxy/Infrastructure/IResultConverter.cs" Link="IResultConverter.cs" />
<Compile Include="../Prise.Proxy/PassthroughParameterConverter.cs" Link="PassthroughParameterConverter.cs" />
<Compile Include="../Prise.Proxy/PassthroughResultConverter.cs" Link="PassthroughResultConverter.cs" />
<Compile Include="../Prise.Proxy/PriseProxy.cs" Link="PriseProxy.cs" />
<Compile Include="../Prise.Proxy/Method.cs" Link="Method.cs" />
<Compile Include="../Prise.Proxy/Parameter.cs" Link="Parameter.cs" />
<Compile Include="../Prise.Proxy/MethodFindingStrategy.cs" Link="MethodFindingStrategy.cs" />
<Compile Include="../Prise.Proxy/ResultConverter.cs" Link="ResultConverter.cs" />
<Compile Include="../Prise.Proxy/TaskCompletionSource.cs" Link="TaskCompletionSource.cs" />
<Compile Include="../Prise/Infrastructure/JsonSerializerParameterConverter.cs" Link="JsonSerializerParameterConverter.cs" />
<Compile Include="../Prise/Infrastructure/JsonSerializerResultConverter.cs" Link="JsonSerializerResultConverter.cs" />
</ItemGroup>
<PropertyGroup>
<PackageIcon>icon.png</PackageIcon>
</PropertyGroup>
<ItemGroup>
<None Include="../icon.png">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
</ItemGroup>
</Project>

View File

@ -1,53 +0,0 @@
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using Prise.Infrastructure;
namespace Prise.Proxy
{
/// <summary>
/// The ReverseProxy is a base class that will provide a proxy to a Host Service from the Plugin (in reverse).
/// </summary>
public abstract class ReverseProxy
{
protected object hostService;
protected ReverseProxy(object hostService)
{
this.hostService = hostService;
}
private MethodBase GetCallingMethod() => new StackTrace().GetFrame(2).GetMethod();
/// <summary>
/// This handles void proxy calls to the hostService
/// </summary>
/// <param name="parameters">The list of method parameters</param>
protected void InvokeOnHostService(params object[] parameters)
{
var callingMethod = GetCallingMethod();
var methodInfo = PriseProxy.FindMethodOnObject(callingMethod as MethodInfo, this);
if (methodInfo.GetParameters().Count() != parameters.Count())
throw new ReverseProxyException($"The number of parameters provided to this ReverseProxy {parameters?.Count()} do not match the actual parameter count of the hostService method ({methodInfo.GetParameters().Count()}). Did you forget to provide the correct number of parameters?");
this.Invoke(hostService, methodInfo, parameters ?? new object[] { });
}
/// <summary>
/// This handles proxy calls to the hostService
/// </summary>
/// <param name="parameters">The list of method parameters</param>
/// <typeparam name="T">Return reference type of the calling method</typeparam>
/// <returns>The response of the invocation on the host object</returns>
protected T InvokeOnHostService<T>(params object[] parameters)
{
var callingMethod = GetCallingMethod();
var methodInfo = PriseProxy.FindMethodOnObject(callingMethod as MethodInfo, this);
if (methodInfo.GetParameters().Count() != parameters.Count())
throw new ReverseProxyException($"The number of parameters provided to this ReverseProxy {parameters?.Count()} do not match the actual parameter count of the hostService method ({methodInfo.GetParameters().Count()}). Did you forget to provide the correct number of parameters?");
return (T)this.Invoke(hostService, methodInfo, parameters ?? new object[] { });
}
private object Invoke(object hostService, MethodInfo methodInfo, object[] parameters) => PriseProxy.Invoke(hostService, methodInfo, parameters ?? new object[] { }, new JsonSerializerParameterConverter(), new JsonSerializerResultConverter());
}
}

View File

@ -1,13 +0,0 @@
namespace Prise.Proxy
{
[System.Serializable]
public class ReverseProxyException : System.Exception
{
public ReverseProxyException() { }
public ReverseProxyException(string message) : base(message) { }
public ReverseProxyException(string message, System.Exception inner) : base(message, inner) { }
protected ReverseProxyException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
}
}

View File

@ -1,29 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<Title>Prise.Testing</Title>
<PackageId>Prise.Testing</PackageId>
<PackageDescription>Testing support for your Prise Plugins!</PackageDescription>
<Authors>Maarten Merken</Authors>
<Company>MRKN</Company>
<PackageTags>plugin;framework;prise;decoupling;assembly;dispatchproxy;proxy</PackageTags>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../Prise.Plugin/Prise.Plugin.csproj" />
</ItemGroup>
<PropertyGroup>
<PackageIcon>icon.png</PackageIcon>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
<ItemGroup>
<None Include="../icon.png">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
</ItemGroup>
</Project>

View File

@ -1,35 +0,0 @@
using System;
using System.Linq;
using System.Reflection;
namespace Prise
{
public static class Testing
{
public static T CreateTestPluginInstance<T>(params object[] pluginServices)
{
var pluginType = typeof(T);
var pluginInstance = typeof(T).Assembly.CreateInstance(typeof(T).FullName);
var services = pluginType.GetTypeInfo().DeclaredFields.Where(f => f.CustomAttributes.Any(c => c.AttributeType.Name == typeof(Prise.Plugin.PluginServiceAttribute).Name));
foreach (var service in services)
{
var serviceType = service.FieldType;
var pluginService = pluginServices.FirstOrDefault(p => serviceType.IsAssignableFrom(p.GetType()));
if (pluginService == null)
throw new ArgumentException($"A pluginService of type {serviceType.Name} is required for activating plugin {pluginType.Name}.");
pluginInstance
.GetType()
.GetTypeInfo()
.DeclaredFields
.First(f => f.Name == service.Name)
.SetValue(pluginInstance, pluginService);
var activationMethod = pluginType.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public).FirstOrDefault(m => m.CustomAttributes.Any(c => c.AttributeType.Name == typeof(Prise.Plugin.PluginActivatedAttribute).Name));
activationMethod.Invoke(pluginInstance, null);
}
return (T)pluginInstance;
}
}
}

View File

@ -1,19 +0,0 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "IntegrationTestHost",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
"program": "${workspaceFolder}/Prise.IntegrationTestsHost/bin/Debug/netcoreapp3.1/Prise.IntegrationTestsHost.dll",
"args": [],
"cwd": "${workspaceFolder}/Prise.IntegrationTestsHost",
"console": "externalTerminal",
"stopAtEntry": false
},
]
}

View File

@ -1,17 +0,0 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/Prise.IntegrationTestsHost/Prise.IntegrationTestsHost.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
}
]
}

View File

@ -1,23 +0,0 @@
{
"runtimeTarget": {
"name": ".NETCoreApp,Version=v3.1",
"signature": ""
},
"compilationOptions": {},
"targets": {
".NETCoreApp,Version=v3.1": {
"FileBulkDateChanger/1.0.0": {
"runtime": {
"FileBulkDateChanger.dll": {}
}
}
}
},
"libraries": {
"FileBulkDateChanger/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
}
}
}

View File

@ -1,10 +0,0 @@
{
"runtimeOptions": {
"additionalProbingPaths": [
"C:\\Users\\alper\\.dotnet\\store\\|arch|\\|tfm|",
"C:\\Users\\alper\\.nuget\\packages",
"C:\\Microsoft\\Xamarin\\NuGet",
"C:\\Program Files\\dotnet\\sdk\\NuGetFallbackFolder"
]
}
}

View File

@ -1,9 +0,0 @@
{
"runtimeOptions": {
"tfm": "netcoreapp3.1",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "3.1.0"
}
}
}

View File

@ -1,7 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
</Project>

View File

@ -1,18 +0,0 @@
namespace DomainForPluginC
{
public interface IDiscount
{
decimal Amount { get; }
}
public class Discount : IDiscount
{
private readonly decimal amount;
public Discount(decimal amount)
{
this.amount = amount;
}
public decimal Amount => amount;
}
}

View File

@ -1,23 +0,0 @@
using System;
namespace DomainForPluginC
{
public interface IDiscountService
{
decimal ApplyDiscount(decimal result);
}
public class DiscountService : IDiscountService
{
private readonly IDiscount discount;
public DiscountService(IDiscount discount)
{
this.discount = discount;
}
public decimal ApplyDiscount(decimal result)
{
return result * this.discount.Amount;
}
}
}

View File

@ -1,64 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Prise.IntegrationTestsContract;
using Prise.Plugin;
namespace PluginA
{
/// <summary>
/// This plugin does not require any 3rd party dependencies or dependency injection,
/// as long as a default parameterless constructor is present (implicitly or explicitly), this plugin will get loaded.
/// </summary>
[Plugin(PluginType = typeof(ICalculationPlugin))]
public class AdditionCalculationPlugin : ICalculationPlugin
{
public string Name => nameof(AdditionCalculationPlugin);
public string Description => "This plugin performs addition";
public int Calculate(int a, int b)
{
return a + b;
}
public decimal Calculate(decimal a, decimal b)
{
return a + b;
}
public decimal CalculateComplex(CalculationContext context)
{
return context.A + context.B;
}
public CalculationResult CalculateComplexResult(CalculationContext context)
{
return new CalculationResult
{
Result = context.A + context.B
};
}
public ComplexCalculationResult CalculateMutiple(ComplexCalculationContext context)
{
var results = new List<CalculationResult>();
results.AddRange(context.Calculations.Select(c => new CalculationResult { Result = c.A + c.B }));
return new ComplexCalculationResult
{
Results = results.ToArray()
};
}
public async Task<ComplexCalculationResult> CalculateMutipleAsync(ComplexCalculationContext context)
{
var results = new List<CalculationResult>();
results.AddRange(context.Calculations.Select(c => new CalculationResult { Result = c.A + c.B }));
await Task.Delay(2500);
return new ComplexCalculationResult
{
Results = results.ToArray()
};
}
}
}

View File

@ -1,12 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Prise.Plugin\Prise.Plugin.csproj" />
<ProjectReference Include="..\..\Prise.IntegrationTestsContract\Prise.IntegrationTestsContract.csproj" />
</ItemGroup>
</Project>

View File

@ -1,13 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AssemblyName>PluginA</AssemblyName>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Prise.Plugin\Prise.Plugin.csproj" />
<ProjectReference Include="..\..\Prise.IntegrationTestsContract\Prise.IntegrationTestsContract.csproj" />
</ItemGroup>
</Project>

View File

@ -1,65 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Prise.IntegrationTestsContract;
using Prise.Plugin;
namespace PluginA
{
/// <summary>
/// By default, only the first plugin is loaded, the first in alphabethical order
/// In order to execute the ZAdditionPlusOneCalculationPlugin, you need to have an IEnumerable<ICalculationPlugin> injected
/// or inject a IPluginLoader<ICalculationPlugin> and call the .LoadAll() method.
/// </summary>
[Plugin(PluginType = typeof(ICalculationPlugin))]
public class ZAdditionPlusOneCalculationPlugin : ICalculationPlugin
{
public string Name => nameof(ZAdditionPlusOneCalculationPlugin);
public string Description => "This plugin performs addition +1";
public int Calculate(int a, int b)
{
return a + b + 1;
}
public decimal Calculate(decimal a, decimal b)
{
return a + b + 1;
}
public decimal CalculateComplex(CalculationContext context)
{
return context.A + context.B + 1;
}
public CalculationResult CalculateComplexResult(CalculationContext context)
{
return new CalculationResult
{
Result = context.A + context.B + 1
};
}
public ComplexCalculationResult CalculateMutiple(ComplexCalculationContext context)
{
var results = new List<CalculationResult>();
results.AddRange(context.Calculations.Select(c => new CalculationResult { Result = c.A + c.B + 1 }));
return new ComplexCalculationResult
{
Results = results.ToArray()
};
}
public async Task<ComplexCalculationResult> CalculateMutipleAsync(ComplexCalculationContext context)
{
var results = new List<CalculationResult>();
results.AddRange(context.Calculations.Select(c => new CalculationResult { Result = c.A + c.B + 1 }));
await Task.Delay(2500);
return new ComplexCalculationResult
{
Results = results.ToArray()
};
}
}
}

View File

@ -1,6 +0,0 @@
{
"publishDir": "../../_dist",
"configuration": "Debug",
"nuspecFile": null,
"includeProjectNameInPublishDir": true
}

View File

@ -1,11 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Prise.Plugin\Prise.Plugin.csproj" />
<ProjectReference Include="..\..\Prise.IntegrationTestsContract\Prise.IntegrationTestsContract.csproj" />
</ItemGroup>
</Project>

View File

@ -1,12 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AssemblyName>PluginB</AssemblyName>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Prise.Plugin\Prise.Plugin.csproj" />
<ProjectReference Include="..\..\Prise.IntegrationTestsContract\Prise.IntegrationTestsContract.csproj" />
</ItemGroup>
</Project>

View File

@ -1,65 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Prise.IntegrationTestsContract;
using Prise.Plugin;
namespace PluginB
{
// This class does not implement the ICalculationPlugin interface
// Since all the methods are present, it will continue to work because the PluginAttribute is still present and the interface contract is respected
// This improves backwards compatibility.
[Plugin(PluginType = typeof(ICalculationPlugin))]
public class SubtractionCalculationPlugin
{
public string Name => nameof(SubtractionCalculationPlugin);
// Property Description will not be implemented in this plugin, all other methods can still be called
// public string Description => "This plugin performs subtraction";
// However, you could expose it this way:
// public string get_Description() => "This plugin performs subtraction";
public int Calculate(int a, int b)
{
return a - b;
}
public decimal Calculate(decimal a, decimal b)
{
return a - b;
}
public decimal CalculateComplex(CalculationContext context)
{
return context.A - context.B;
}
public CalculationResult CalculateComplexResult(CalculationContext context)
{
return new CalculationResult { Result = context.A - context.B };
}
public ComplexCalculationResult CalculateMutiple(ComplexCalculationContext context)
{
var results = new List<CalculationResult>();
results.AddRange(context.Calculations.Select(c => new CalculationResult { Result = c.A - c.B }));
return new ComplexCalculationResult
{
Results = results.ToArray()
};
}
public async Task<ComplexCalculationResult> CalculateMutipleAsync(ComplexCalculationContext context)
{
var results = new List<CalculationResult>();
results.AddRange(context.Calculations.Select(c => new CalculationResult { Result = c.A - c.B }));
await Task.Delay(2500);
return new ComplexCalculationResult
{
Results = results.ToArray()
};
}
}
}

View File

@ -1,6 +0,0 @@
{
"publishDir": "../../_dist",
"configuration": "Debug",
"nuspecFile": null,
"includeProjectNameInPublishDir": true
}

View File

@ -1,31 +0,0 @@
using DomainForPluginC;
namespace PluginC.Calculations
{
public interface ICanCalculate
{
decimal DoCalculation(decimal a, decimal b);
}
public class DivideCalculation : ICanCalculate
{
public decimal DoCalculation(decimal a, decimal b)
{
return a / b;
}
}
public class MultiplyCalculation : ICanCalculate
{
private readonly IDiscountService discountService;
public MultiplyCalculation(IDiscountService discountService)
{
this.discountService = discountService;
}
public decimal DoCalculation(decimal a, decimal b)
{
return this.discountService.ApplyDiscount((a * b));
}
}
}

View File

@ -1,31 +0,0 @@
using System;
using DomainForPluginC;
using Microsoft.Extensions.DependencyInjection;
using PluginC.Calculations;
using Prise.Plugin;
namespace PluginC
{
[PluginBootstrapper(PluginType = typeof(DivideOrMultiplyCalculationPlugin))]
public class DivideOrMultiplyCalculationBootstrapper : IPluginBootstrapper
{
public IServiceCollection Bootstrap(IServiceCollection services)
{
// Discount and DiscountService come from a third party assembly called Domain
// Add a fixed discount of 10%
services.AddSingleton<IDiscount>(new Discount(1.10m));
services.AddScoped<IDiscountService, DiscountService>();
// Randomly choose what service to use
// var random = new Random();
// if (random.Next() % 2 == 0)
// services.AddScoped<ICanCalculate, DivideCalculation>();
// else
// services.AddScoped<ICanCalculate, MultiplyCalculation>();
services.AddScoped<ICanCalculate, MultiplyCalculation>();
return services;
}
}
}

View File

@ -1,75 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Prise.IntegrationTestsContract;
using PluginC.Calculations;
using Prise.Plugin;
using System.Threading.Tasks;
namespace PluginC
{
// This plugin will Divide or Multiple, who knows, it's always a guess.
// The decision is made in a service, which dependend a discount from a third party dependency that no other plugin shares
[Plugin(PluginType = typeof(ICalculationPlugin))]
public class DivideOrMultiplyCalculationPlugin : ICalculationPlugin
{
public string Name => nameof(DivideOrMultiplyCalculationPlugin);
public string Description => $"This plugin performs division OR multiplication, check out {nameof(DivideOrMultiplyCalculationBootstrapper)} for more details";
private readonly ICanCalculate calculation;
internal DivideOrMultiplyCalculationPlugin(ICanCalculate calculation)
{
this.calculation = calculation;
}
public int Calculate(int a, int b)
{
return (int)this.calculation.DoCalculation(a, b);
}
public decimal Calculate(decimal a, decimal b)
{
return this.calculation.DoCalculation(a, b);
}
public decimal CalculateComplex(CalculationContext context)
{
return this.calculation.DoCalculation(context.A, context.B);
}
public CalculationResult CalculateComplexResult(CalculationContext context)
{
return new CalculationResult { Result = this.calculation.DoCalculation(context.A, context.B) };
}
public ComplexCalculationResult CalculateMutiple(ComplexCalculationContext context)
{
var results = new List<CalculationResult>();
results.AddRange(context.Calculations.Select(c => new CalculationResult { Result = this.calculation.DoCalculation(c.A, c.B) }));
return new ComplexCalculationResult
{
Results = results.ToArray()
};
}
public async Task<ComplexCalculationResult> CalculateMutipleAsync(ComplexCalculationContext context)
{
var results = new List<CalculationResult>();
results.AddRange(context.Calculations.Select(c => new CalculationResult { Result = this.calculation.DoCalculation(c.A, c.B) }));
await Task.Delay(2500);
return new ComplexCalculationResult
{
Results = results.ToArray()
};
}
[PluginFactory]
public static ICalculationPlugin ThisNameDoesNotMatterFactoryMethod(IServiceProvider serviceProvider)
{
return new DivideOrMultiplyCalculationPlugin((ICanCalculate)serviceProvider.GetService(typeof(ICanCalculate)));
}
}
}

View File

@ -1,12 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Prise.Plugin\Prise.Plugin.csproj" />
<ProjectReference Include="..\..\Prise.IntegrationTestsContract\Prise.IntegrationTestsContract.csproj" />
<ProjectReference Include="..\DomainForPluginC\DomainForPluginC.csproj" />
</ItemGroup>
</Project>

View File

@ -1,13 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AssemblyName>PluginC</AssemblyName>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Prise.Plugin\Prise.Plugin.csproj" />
<ProjectReference Include="..\..\Prise.IntegrationTestsContract\Prise.IntegrationTestsContract.csproj" />
<ProjectReference Include="..\DomainForPluginC\DomainForPluginC.csproj" />
</ItemGroup>
</Project>

View File

@ -1,6 +0,0 @@
{
"publishDir": "../../_dist",
"configuration": "Debug",
"nuspecFile": null,
"includeProjectNameInPublishDir": true
}

View File

@ -1,12 +0,0 @@
using Xunit;
namespace Prise.IntegrationTests
{
[CollectionDefinition("AppHost collection")]
public class AppHostCollection : ICollectionFixture<AppHostWebApplicationFactory>
{
// This class has no code, and is never created. Its purpose is simply
// to be the place to apply [CollectionDefinition] and all the
// ICollectionFixture<> interfaces.
}
}

View File

@ -1,27 +0,0 @@
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc.Testing;
using Prise.IntegrationTestsHost;
namespace Prise.IntegrationTests
{
public class CommandLineArgumentsLazy : ICommandLineArguments
{
public bool UseLazyService { get; set; }
public bool UseCollectibleAssemblies { get; set; }
}
public partial class AppHostWebApplicationFactory
: WebApplicationFactory<Prise.IntegrationTestsHost.Startup>
{
internal static AppHostWebApplicationFactory _instance = new AppHostWebApplicationFactory(new CommandLineArgumentsLazy(), null);
internal static AppHostWebApplicationFactory Default() => _instance;
private readonly Dictionary<string, string> settings;
private readonly ICommandLineArguments commandLineArguments;
public AppHostWebApplicationFactory(ICommandLineArguments commandLineArguments, Dictionary<string, string> settings = null)
{
this.commandLineArguments = commandLineArguments;
this.settings = settings;
}
}
}

View File

@ -1,24 +0,0 @@
using Prise.IntegrationTestsHost;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Configuration;
namespace Prise.IntegrationTests
{
public partial class AppHostWebApplicationFactory
: WebApplicationFactory<Prise.IntegrationTestsHost.Startup>
{
#if NETCORE2_1
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureAppConfiguration((c, b) => b.AddInMemoryCollection(this.settings));
builder.ConfigureServices(services =>
{
services.AddSingleton<ICommandLineArguments>((s) => this.commandLineArguments);
});
}
#endif
}
}

View File

@ -1,27 +0,0 @@
using Prise.IntegrationTestsHost;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Configuration;
namespace Prise.IntegrationTests
{
public partial class AppHostWebApplicationFactory
: WebApplicationFactory<Prise.IntegrationTestsHost.Startup>
{
#if NETCORE3_1
protected override IHostBuilder CreateHostBuilder()
{
return Host.CreateDefaultBuilder()
.ConfigureServices((hostContext, services) =>
services.AddSingleton<ICommandLineArguments>((s) => this.commandLineArguments))
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Prise.IntegrationTestsHost.Startup>();
webBuilder.ConfigureAppConfiguration(builder => builder.AddInMemoryCollection(this.settings));
});
}
#endif
}
}

View File

@ -1,30 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Xunit;
namespace Prise.IntegrationTests
{
#if NETCORE3_1
public class BreakTheServerTests : CalculationPluginTestsBase
{
public BreakTheServerTests() : base(AppHostWebApplicationFactory.Default()) { }
[Fact]
public async Task BreakWithLoop()
{
var tasks = new List<Task<string>>();
for (var i = 0; i < 250; i++)
{
tasks.Add(GetRaw(_client, "PluginA", "/disco"));
}
var results = await Task.WhenAll(tasks.ToArray());
Assert.All<string>(results, s => Assert.Equal("AdditionCalculationPlugin,ZAdditionPlusOneCalculationPlugin", s));
}
}
#endif
}

View File

@ -1,36 +0,0 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace Prise.IntegrationTests
{
public abstract class CalculationPluginTestsBase : PluginTestBase
{
protected CalculationPluginTestsBase(AppHostWebApplicationFactory factory) : base(factory) { }
protected async Task<T> Post<T>(HttpClient client, string pluginType, string endpoint, object content)
{
client.DefaultRequestHeaders.Add("PluginType", pluginType);
var response = await client.PostAsync(endpoint, new StringContent(JsonConvert.SerializeObject(content), Encoding.UTF8,
"application/json"));
if (!response.IsSuccessStatusCode)
throw new Exception("Result was not success!");
var responseContent = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<T>(responseContent);
}
protected async Task<string> GetRaw(HttpClient client, string pluginType, string endpoint)
{
client.DefaultRequestHeaders.Add("PluginType", pluginType);
var response = await client.GetAsync(endpoint);
if (!response.IsSuccessStatusCode)
throw new Exception("Result was not success!");
return await response.Content.ReadAsStringAsync();
}
}
}

View File

@ -1,329 +0,0 @@
using System.Net.Http;
using System.Threading.Tasks;
using Prise.IntegrationTestsHost.Models;
using Microsoft.AspNetCore.Mvc.Testing;
using Xunit;
namespace Prise.IntegrationTests
{
public class CalculationTests : CalculationPluginTestsBase
{
public CalculationTests() : base(AppHostWebApplicationFactory.Default()) { }
[Fact]
public async Task PluginA_Works()
{
// Arrange
var payload = new CalculationRequestModel
{
A = 100,
B = 150
};
//Act
var result = await Post<CalculationResponseModel>(_client, "PluginA", "/calculation", payload);
// Assert 100 + 150
Assert.Equal(250, result.Result);
}
[Fact]
public async Task PluginB_Works()
{
// Arrange
var payload = new CalculationRequestModel
{
A = 150,
B = 50
};
//Act
var result = await Post<CalculationResponseModel>(_client, "PluginB", "/calculation", payload);
// Assert 150 - 50
Assert.Equal(100, result.Result);
}
[Fact]
public async Task PluginC_Works()
{
// Arrange
var payload = new CalculationRequestModel
{
A = 50,
B = 2
};
//Act
var result = await Post<CalculationResponseModel>(_client, "PluginC", "/calculation", payload);
// Assert 50 * 2 + 10% discount
Assert.Equal(110, result.Result);
}
[Fact]
public async Task PluginA_int_Works()
{
// Arrange
var payload = new CalculationRequestModel
{
A = 100,
B = 150
};
//Act
var result = await Post<CalculationResponseModel>(_client, "PluginA", "/calculation/int", payload);
// Assert 100 + 150
Assert.Equal(250, result.Result);
}
[Fact]
public async Task PluginB_int_Works()
{
// Arrange
var payload = new CalculationRequestModel
{
A = 150,
B = 50
};
//Act
var result = await Post<CalculationResponseModel>(_client, "PluginB", "/calculation/int", payload);
// Assert 150 - 50
Assert.Equal(100, result.Result);
}
[Fact]
public async Task PluginC_int_Works()
{
// Arrange
var payload = new CalculationRequestModel
{
A = 50,
B = 2
};
//Act
var result = await Post<CalculationResponseModel>(_client, "PluginC", "/calculation/int", payload);
// Assert 50 * 2 + 10% discount
Assert.Equal(110, result.Result);
}
[Fact]
public async Task PluginA_complex_input_Works()
{
// Arrange
var payload = new CalculationRequestModel
{
A = 100,
B = 150
};
//Act
var result = await Post<CalculationResponseModel>(_client, "PluginA", "/calculation/complex-input", payload);
// Assert 100 + 150
Assert.Equal(250, result.Result);
}
[Fact]
public async Task PluginB_complex_input_Works()
{
// Arrange
var payload = new CalculationRequestModel
{
A = 150,
B = 50
};
//Act
var result = await Post<CalculationResponseModel>(_client, "PluginB", "/calculation/complex-input", payload);
// Assert 150 - 50
Assert.Equal(100, result.Result);
}
[Fact]
public async Task PluginC_complex_input_Works()
{
// Arrange
var payload = new CalculationRequestModel
{
A = 50,
B = 2
};
//Act
var result = await Post<CalculationResponseModel>(_client, "PluginC", "/calculation/complex-input", payload);
// Assert 50 * 2 + 10% discount
Assert.Equal(110, result.Result);
}
[Fact]
public async Task PluginA_complex_output_Works()
{
// Arrange
var payload = new CalculationRequestModel
{
A = 100,
B = 150
};
//Act
var result = await Post<CalculationResponseModel>(_client, "PluginA", "/calculation/complex-output", payload);
// Assert 100 + 150
Assert.Equal(250, result.Result);
}
[Fact]
public async Task PluginB_complex_output_Works()
{
// Arrange
var payload = new CalculationRequestModel
{
A = 150,
B = 50
};
//Act
var result = await Post<CalculationResponseModel>(_client, "PluginB", "/calculation/complex-output", payload);
// Assert 150 - 50
Assert.Equal(100, result.Result);
}
[Fact]
public async Task PluginC_complex_output_Works()
{
// Arrange
var payload = new CalculationRequestModel
{
A = 50,
B = 2
};
//Act
var result = await Post<CalculationResponseModel>(_client, "PluginC", "/calculation/complex-output", payload);
// Assert 50 * 2 + 10% discount
Assert.Equal(110, result.Result);
}
[Fact]
public async Task PluginA_multi_Works()
{
// Arrange
var payload = new CalculationRequestMultiModel
{
Calculations = new[]
{
new CalculationRequestModel
{
A = 100,
B = 150
},
new CalculationRequestModel
{
A = 100,
B = 150
}
}
};
//Act
var result = await Post<CalculationResponseModel>(_client, "PluginA", "/calculation/multi", payload);
// Assert 100 + 150 + 100 + 150
Assert.Equal(500, result.Result);
}
[Fact]
public async Task PluginB_multi_Works()
{
// Arrange
var payload = new CalculationRequestMultiModel
{
Calculations = new[]
{
new CalculationRequestModel
{
A = 50,
B = 5
},
new CalculationRequestModel
{
A = 40,
B = 5
}
}
};
//Act
var result = await Post<CalculationResponseModel>(_client, "PluginB", "/calculation/multi", payload);
// Assert (50 - 5) + (40 - 5)
Assert.Equal(80, result.Result);
}
[Fact]
public async Task PluginC_multi_Works()
{
// Arrange
var payload = new CalculationRequestMultiModel
{
Calculations = new[]
{
new CalculationRequestModel
{
A = 50,
B = 2
},
new CalculationRequestModel
{
A = 40,
B = 2
}
}
};
//Act
var result = await Post<CalculationResponseModel>(_client, "PluginC", "/calculation/multi", payload);
// Assert (50 * 2 + 10% discount) + (40 * 2 + 10% discount)
Assert.Equal(198, result.Result);
}
[Fact]
public async Task PluginC_multi_async_Works()
{
// Arrange
var payload = new CalculationRequestMultiModel
{
Calculations = new[]
{
new CalculationRequestModel
{
A = 50,
B = 2
},
new CalculationRequestModel
{
A = 40,
B = 2
}
}
};
//Act
var result = await Post<CalculationResponseModel>(_client, "PluginC", "/calculation/multi-async", payload);
// Assert (50 * 2 + 10% discount) + (40 * 2 + 10% discount)
Assert.Equal(198, result.Result);
}
}
}

View File

@ -1,61 +0,0 @@
using System.Threading.Tasks;
using Xunit;
namespace Prise.IntegrationTests
{
public class DiscoTests : CalculationPluginTestsBase
{
public DiscoTests() : base(AppHostWebApplicationFactory.Default()) { }
[Fact]
public async Task PluginA_Works()
{
// Arrange, Act
var result = await GetRaw(_client, "PluginA", "/disco");
// Assert
Assert.Equal("AdditionCalculationPlugin,ZAdditionPlusOneCalculationPlugin", result);
}
[Fact]
public async Task PluginA_Description_Works()
{
// Arrange, Act
var result = await GetRaw(_client, "PluginA", "/disco/description");
// Assert
Assert.Equal("This plugin performs addition,This plugin performs addition +1", result);
}
[Fact]
public async Task PluginB_Works()
{
// Arrange, Act
var result = await GetRaw(_client, "PluginB", "/disco");
// Assert
Assert.Equal("SubtractionCalculationPlugin", result);
}
[Fact]
public async Task PluginC_Works()
{
// Arrange, Act
var result = await GetRaw(_client, "PluginC", "/disco");
// Assert
Assert.Equal("DivideOrMultiplyCalculationPlugin", result);
}
[Fact]
public async Task PluginC_Description_Works()
{
// Arrange, Act
var result = await GetRaw(_client, "PluginC", "/disco/description");
// Assert
Assert.Equal("This plugin performs division OR multiplication, check out DivideOrMultiplyCalculationBootstrapper for more details", result);
}
}
}

View File

@ -1,64 +0,0 @@
using System.Net.Http;
using System.Threading.Tasks;
using Prise.IntegrationTestsHost.Models;
using Microsoft.AspNetCore.Mvc.Testing;
using Xunit;
namespace Prise.IntegrationTests
{
public class MultipleTests : CalculationPluginTestsBase
{
public MultipleTests() : base(AppHostWebApplicationFactory.Default()) { }
[Fact]
public async Task PluginA_Works()
{
// Arrange
var payload = new CalculationRequestModel
{
A = 100,
B = 150
};
//Act
var result = await Post<CalculationResponseModel>(_client, "PluginA", "/multiple", payload);
// Assert (100 + 150) + (100 + 150 + 1)
Assert.Equal(501, result.Result);
}
[Fact]
public async Task PluginB_Works()
{
// Arrange
var payload = new CalculationRequestModel
{
A = 150,
B = 50
};
//Act
var result = await Post<CalculationResponseModel>(_client, "PluginB", "/multiple", payload);
// Assert 150 - 50
Assert.Equal(100, result.Result);
}
[Fact]
public async Task PluginC_Works()
{
// Arrange
var payload = new CalculationRequestModel
{
A = 50,
B = 2
};
//Act
var result = await Post<CalculationResponseModel>(_client, "PluginC", "/multiple", payload);
// Assert 50 * 2 + 10% discount
Assert.Equal(110, result.Result);
}
}
}

View File

@ -1,37 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Testing;
using Newtonsoft.Json;
using Prise.IntegrationTestsContract;
namespace Prise.IntegrationTests
{
public abstract class PluginTestBase
{
protected readonly HttpClient _client;
protected readonly AppHostWebApplicationFactory _factory;
protected PluginTestBase(
AppHostWebApplicationFactory factory)
{
_factory = factory;
var local = Environment.GetEnvironmentVariable("LOCAL") == "true";
if (local)
{
_client = new HttpClient();
_client.BaseAddress = new Uri("https://localhost:5001");
}
else
_client = factory.CreateClient(new WebApplicationFactoryClientOptions
{
AllowAutoRedirect = false,
BaseAddress = new Uri("https://localhost:5001")
});
_client.Timeout = new TimeSpan(0, 5, 0);
}
}
}

View File

@ -1,25 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<PropertyGroup>
<DefineConstants>NETCORE3_1</DefineConstants>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="3.0.0" />
<PackageReference Include="xunit" Version="2.4.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
<PackageReference Include="Xunit.SkippableFact" Version="1.3.12" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Prise.IntegrationTestsHost\Prise.IntegrationTestsHost.csproj" />
</ItemGroup>
</Project>

View File

@ -1,10 +0,0 @@
{
"profiles": {
"Prise.IntegrationTests": {
"commandName": "Project",
"environmentVariables": {
"LOCAL": "true"
}
}
}
}

View File

@ -1,45 +0,0 @@
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Prise.IntegrationTestsHost.Models;
using Microsoft.AspNetCore.Mvc.Testing;
using Xunit;
namespace Prise.IntegrationTests
{
public class SadPathTests : CalculationPluginTestsBase
{
public SadPathTests() : base(AppHostWebApplicationFactory.Default()) { }
[Fact]
public async Task PluginZ_DoesNotExists()
{
// Arrange
var payload = new CalculationRequestModel
{
A = 100,
B = 150
};
//Act
#if NETCORE3_1
await Assert.ThrowsAsync<System.IO.DirectoryNotFoundException>(async () => await Post<CalculationResponseModel>(_client, "PluginZ", "/calculation", payload));
#endif
#if NETCORE2_1
await Assert.ThrowsAsync<System.Exception>(async () => await Post<CalculationResponseModel>(_client, "PluginZ", "/calculation", payload));
#endif
}
[Fact]
public async Task PluginB_Description_Does_Not_Work()
{
// Arrange, Act
#if NETCORE3_1
await Assert.ThrowsAsync<Prise.Proxy.PriseProxyException>(async () => await GetRaw(_client, "PluginB", "/disco/description"));
#endif
#if NETCORE2_1
await Assert.ThrowsAsync<System.Exception>(async () => await GetRaw(_client, "PluginB", "/disco/description"));
#endif
}
}
}

Some files were not shown because too many files have changed in this diff Show More