├── global.json
├── docs
├── logo.pdn
├── logo_256.png
├── Adafy_logo_256.png
├── logo_orange_white.png
├── logo_transparent_color.pdn
├── logo_transparent_color.png
├── logo_transparent_white.png
└── logo_transparent_color_256.png
├── tests
├── integration
│ ├── Weikio.PluginFramework.AspNetCore.IntegrationTests
│ │ ├── xunit.runner.json
│ │ ├── Weikio.PluginFramework.AspNetCore.IntegrationTests.csproj
│ │ ├── TestBase.cs
│ │ └── DefaultPluginTypeTests.cs
│ ├── WebSites
│ │ └── PluginFrameworkTestBed
│ │ │ ├── PluginFrameworkTestBed.csproj
│ │ │ ├── appsettings.Development.json
│ │ │ ├── appsettings.json
│ │ │ ├── WeatherForecast.cs
│ │ │ ├── Program.cs
│ │ │ ├── Controllers
│ │ │ └── WeatherForecastController.cs
│ │ │ └── Startup.cs
│ └── Weikio.PluginFramework.Catalogs.NuGet.Tests
│ │ ├── NuGet.Config
│ │ ├── NotThreadSafeResourceCollection.cs
│ │ └── Weikio.PluginFramework.Catalogs.NuGet.Tests.csproj
├── Assemblies
│ ├── TestAssembly1
│ │ ├── NotAPlugin.cs
│ │ ├── INotPluginInterface.cs
│ │ ├── FirstPlugin.cs
│ │ └── TestAssembly1.csproj
│ ├── TestIntefaces
│ │ ├── ICommand.cs
│ │ ├── IJsonVersionResolver.cs
│ │ └── TestIntefaces.csproj
│ ├── TestAssembly3
│ │ ├── ThirdAddon.cs
│ │ └── TestAssembly3.csproj
│ ├── TestAssembly2
│ │ ├── SecondPlugin.cs
│ │ └── TestAssembly2.csproj
│ ├── JsonNetNew
│ │ ├── NewJsonResolver.cs
│ │ └── JsonNetNew.csproj
│ └── JsonNetOld
│ │ ├── JsonNetOld.csproj
│ │ └── OldJsonResolver.cs
└── unit
│ ├── Weikio.PluginFramework.Tests
│ ├── Plugins
│ │ ├── TypePlugin.cs
│ │ ├── PluginWithAttribute.cs
│ │ ├── AnotherPluginWithAttribute.cs
│ │ ├── AbstractPluginWithAttribute.cs
│ │ ├── TypePluginWithName.cs
│ │ └── MyPluginAttribute.cs
│ ├── NotThreadSafeResourceCollection.cs
│ ├── Weikio.PluginFramework.Tests.csproj
│ ├── TypeFinderTests.cs
│ ├── DefaultOptionsTests.cs
│ └── TypePluginCatalogTests.cs
│ └── Weikio.PluginFramework.Catalogs.Roslyn.Tests
│ ├── Weikio.PluginFramework.Catalogs.Roslyn.Tests.csproj
│ ├── TestHelpers.cs
│ └── RegularInitializerTests.cs
├── samples
├── BlazorApp
│ ├── wwwroot
│ │ ├── favicon.ico
│ │ └── css
│ │ │ ├── open-iconic
│ │ │ ├── font
│ │ │ │ └── fonts
│ │ │ │ │ ├── open-iconic.eot
│ │ │ │ │ ├── open-iconic.otf
│ │ │ │ │ ├── open-iconic.ttf
│ │ │ │ │ └── open-iconic.woff
│ │ │ ├── ICON-LICENSE
│ │ │ ├── README.md
│ │ │ └── FONT-LICENSE
│ │ │ └── site.css
│ ├── appsettings.json
│ ├── appsettings.Development.json
│ ├── _Imports.razor
│ ├── Shared
│ │ ├── MainLayout.razor
│ │ ├── SurveyPrompt.razor
│ │ └── NavMenu.razor
│ ├── Data
│ │ ├── WeatherForecast.cs
│ │ └── WeatherForecastService.cs
│ ├── App.razor
│ ├── Properties
│ │ └── launchSettings.json
│ ├── Pages
│ │ ├── Counter.razor
│ │ ├── Error.razor
│ │ ├── Index.razor
│ │ ├── _Host.cshtml
│ │ └── FetchData.razor
│ ├── BlazorApp.csproj
│ ├── Program.cs
│ └── Startup.cs
├── WebAppPluginsLibrary
│ ├── CustomPlugin.cs
│ └── WebAppPluginsLibrary.csproj
├── Shared
│ ├── Weikio.PluginFramework.Samples.Shared
│ │ ├── IMyPlugin.cs
│ │ ├── IOperator.cs
│ │ ├── RemainderOperator.cs
│ │ ├── IPlugin.cs
│ │ └── Weikio.PluginFramework.Samples.Shared.csproj
│ └── Weikio.PluginFramework.Samples.SharedPlugins
│ │ ├── SumOperator.cs
│ │ ├── MinusOperator.cs
│ │ ├── SecondSharedPlugin.cs
│ │ ├── MultiplyOperator.cs
│ │ └── Weikio.PluginFramework.Samples.SharedPlugins.csproj
├── WebApp
│ ├── appsettings.Development.json
│ ├── appsettings.json
│ ├── Properties
│ │ └── launchSettings.json
│ ├── Program.cs
│ ├── WebApp.csproj
│ ├── Controllers
│ │ └── CalculatorController.cs
│ └── Startup.cs
├── WebAppWithNuget
│ ├── appsettings.Development.json
│ ├── appsettings.json
│ ├── Properties
│ │ └── launchSettings.json
│ ├── WebAppWithNuget.csproj
│ ├── Program.cs
│ ├── Controllers
│ │ └── CalculatorController.cs
│ ├── NugetLogger.cs
│ └── Startup.cs
├── WebAppWithRoslyn
│ ├── appsettings.Development.json
│ ├── ExternalService.cs
│ ├── appsettings.json
│ ├── Properties
│ │ └── launchSettings.json
│ ├── Program.cs
│ ├── WebAppWithRoslyn.csproj
│ ├── Controllers
│ │ └── RoslynController.cs
│ └── Startup.cs
├── WebAppWithAppSettings
│ ├── appsettings.Development.json
│ ├── appsettings.json
│ ├── Properties
│ │ └── launchSettings.json
│ ├── Program.cs
│ ├── WebAppWithAppSettings.csproj
│ ├── Startup.cs
│ └── Controllers
│ │ └── CalculatorController.cs
├── WebAppWithDelegate
│ ├── appsettings.Development.json
│ ├── ExternalService.cs
│ ├── appsettings.json
│ ├── Properties
│ │ └── launchSettings.json
│ ├── Program.cs
│ ├── WebAppWithDelegate.csproj
│ ├── Controllers
│ │ └── DelegateController.cs
│ └── Startup.cs
├── WpfApp
│ ├── DivideOperator.cs
│ ├── App.xaml
│ ├── App.xaml.cs
│ ├── AssemblyInfo.cs
│ ├── WpfApp.csproj
│ ├── MainWindow.xaml
│ └── MainWindow.xaml.cs
├── WinFormsApp
│ ├── DivideOperator.cs
│ ├── WinFormsApp.csproj
│ └── Program.cs
├── ConsoleApp
│ ├── FirstPlugin.cs
│ ├── SecondPlugin.cs
│ ├── MyPlugin.cs
│ ├── ConsoleApp.csproj
│ └── Program.cs
└── WinFormsPluginsLibrary
│ ├── LabelPlugin.cs
│ ├── TestPlugin.cs
│ ├── WinFormsPluginsLibrary.csproj
│ ├── TestPlugin.Designer.cs
│ └── LabelPlugin.Designer.cs
├── src
├── Weikio.PluginFramework
│ ├── TypeFinding
│ │ ├── ITypeFindingContext.cs
│ │ ├── TypeFinderCriteria.cs
│ │ ├── TypeFinderOptions.cs
│ │ └── TypeFinderCriteriaBuilder.cs
│ ├── Catalogs
│ │ ├── Delegates
│ │ │ ├── ParameterConversion.cs
│ │ │ ├── DelegatePluginCatalogOptions.cs
│ │ │ └── ConversionRule.cs
│ │ ├── EmptyPluginCatalog.cs
│ │ ├── AssemblyPluginCatalogOptions.cs
│ │ ├── TypePluginCatalogOptions.cs
│ │ ├── CompositePluginCatalog.cs
│ │ └── FolderPluginCatalogOptions.cs
│ ├── Context
│ │ ├── RuntimeAssemblyHint.cs
│ │ ├── UseHostApplicationAssembliesEnum.cs
│ │ ├── MetadataTypeFindingContext.cs
│ │ └── PluginLoadContextOptions.cs
│ └── Weikio.PluginFramework.csproj
├── Weikio.PluginFramework.Abstractions
│ ├── PluginFrameworkOptions.cs
│ ├── IPluginCatalog.cs
│ ├── Weikio.PluginFramework.Abstractions.csproj
│ ├── IPluginCatalogExtensions.cs
│ ├── Plugin.cs
│ └── PluginNameOptions.cs
├── Weikio.PluginFramework.Configuration
│ ├── CatalogConfiguration.cs
│ ├── Converters
│ │ ├── AssemblyCatalogConfigurationCoverter.cs
│ │ ├── IConfigurationToCatalogConverter.cs
│ │ └── FolderCatalogConfigurationConverter.cs
│ ├── Providers
│ │ ├── IPluginCatalogConfigurationLoader.cs
│ │ └── PluginCatalogConfigurationLoader.cs
│ └── Weikio.PluginFramework.Configuration.csproj
├── Weikio.PluginFramework.AspNetCore
│ ├── DefaultPluginOption.cs
│ ├── PluginExtensions.cs
│ ├── ServiceProviderExtensions.cs
│ ├── Weikio.PluginFramework.AspNetCore.csproj
│ ├── PluginProvider.cs
│ └── PluginFrameworkInitializer.cs
├── Weikio.PluginFramework.Catalogs.Roslyn
│ ├── InvalidCodeException.cs
│ ├── Weikio.PluginFramework.Catalogs.Roslyn.csproj
│ ├── RoslynPluginCatalogOptions.cs
│ ├── RegularInitializer.cs
│ └── RoslynPluginCatalog.cs
└── Weikio.PluginFramework.Catalogs.NuGet
│ ├── Weikio.PluginFramework.Catalogs.NuGet.csproj
│ ├── NugetFeedPluginCatalogOptions.cs
│ ├── NugetPluginCatalogOptions.cs
│ └── NugetFeedPluginCatalog.cs
└── LICENSE
/global.json:
--------------------------------------------------------------------------------
1 | {
2 | "sdk": {
3 | "version": "6.0.420"
4 | }
5 | }
--------------------------------------------------------------------------------
/docs/logo.pdn:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikio/PluginFramework/HEAD/docs/logo.pdn
--------------------------------------------------------------------------------
/docs/logo_256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikio/PluginFramework/HEAD/docs/logo_256.png
--------------------------------------------------------------------------------
/docs/Adafy_logo_256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikio/PluginFramework/HEAD/docs/Adafy_logo_256.png
--------------------------------------------------------------------------------
/docs/logo_orange_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikio/PluginFramework/HEAD/docs/logo_orange_white.png
--------------------------------------------------------------------------------
/docs/logo_transparent_color.pdn:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikio/PluginFramework/HEAD/docs/logo_transparent_color.pdn
--------------------------------------------------------------------------------
/docs/logo_transparent_color.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikio/PluginFramework/HEAD/docs/logo_transparent_color.png
--------------------------------------------------------------------------------
/docs/logo_transparent_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikio/PluginFramework/HEAD/docs/logo_transparent_white.png
--------------------------------------------------------------------------------
/docs/logo_transparent_color_256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikio/PluginFramework/HEAD/docs/logo_transparent_color_256.png
--------------------------------------------------------------------------------
/tests/integration/Weikio.PluginFramework.AspNetCore.IntegrationTests/xunit.runner.json:
--------------------------------------------------------------------------------
1 | {
2 | "shadowCopy": false
3 | }
4 |
--------------------------------------------------------------------------------
/samples/BlazorApp/wwwroot/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikio/PluginFramework/HEAD/samples/BlazorApp/wwwroot/favicon.ico
--------------------------------------------------------------------------------
/tests/Assemblies/TestAssembly1/NotAPlugin.cs:
--------------------------------------------------------------------------------
1 | namespace TestAssembly1
2 | {
3 | public abstract class NotAPlugin
4 | {
5 |
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/tests/Assemblies/TestIntefaces/ICommand.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace TestIntefaces
4 | {
5 | public interface ICommand
6 | {
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/samples/WebAppPluginsLibrary/CustomPlugin.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace WebAppPluginsLibrary
4 | {
5 | public class CustomPlugin
6 | {
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/tests/Assemblies/TestAssembly1/INotPluginInterface.cs:
--------------------------------------------------------------------------------
1 | namespace TestAssembly1
2 | {
3 | public interface INotPluginInterface
4 | {
5 |
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/tests/Assemblies/TestAssembly3/ThirdAddon.cs:
--------------------------------------------------------------------------------
1 | using TestIntefaces;
2 |
3 | namespace TestAssembly3
4 | {
5 | public class ThirdAddon : ICommand
6 | {
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/tests/unit/Weikio.PluginFramework.Tests/Plugins/TypePlugin.cs:
--------------------------------------------------------------------------------
1 | namespace Weikio.PluginFramework.Tests.Plugins
2 | {
3 | public class TypePlugin
4 | {
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/tests/Assemblies/TestAssembly2/SecondPlugin.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace TestAssembly2
4 | {
5 | public class SecondPlugin
6 | {
7 |
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/tests/Assemblies/TestIntefaces/IJsonVersionResolver.cs:
--------------------------------------------------------------------------------
1 | namespace TestIntefaces
2 | {
3 | public interface IJsonVersionResolver
4 | {
5 | string GetVersion();
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/samples/BlazorApp/wwwroot/css/open-iconic/font/fonts/open-iconic.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikio/PluginFramework/HEAD/samples/BlazorApp/wwwroot/css/open-iconic/font/fonts/open-iconic.eot
--------------------------------------------------------------------------------
/samples/BlazorApp/wwwroot/css/open-iconic/font/fonts/open-iconic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikio/PluginFramework/HEAD/samples/BlazorApp/wwwroot/css/open-iconic/font/fonts/open-iconic.otf
--------------------------------------------------------------------------------
/samples/BlazorApp/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikio/PluginFramework/HEAD/samples/BlazorApp/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf
--------------------------------------------------------------------------------
/samples/BlazorApp/wwwroot/css/open-iconic/font/fonts/open-iconic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weikio/PluginFramework/HEAD/samples/BlazorApp/wwwroot/css/open-iconic/font/fonts/open-iconic.woff
--------------------------------------------------------------------------------
/samples/Shared/Weikio.PluginFramework.Samples.Shared/IMyPlugin.cs:
--------------------------------------------------------------------------------
1 | namespace Weikio.PluginFramework.Samples.Shared
2 | {
3 | public interface IMyPlugin
4 | {
5 | void Run();
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/tests/unit/Weikio.PluginFramework.Tests/Plugins/PluginWithAttribute.cs:
--------------------------------------------------------------------------------
1 | namespace Weikio.PluginFramework.Tests.Plugins
2 | {
3 | [MyPlugin]
4 | public class PluginWithAttribute
5 | {
6 |
7 | }
8 | }
--------------------------------------------------------------------------------
/samples/Shared/Weikio.PluginFramework.Samples.Shared/IOperator.cs:
--------------------------------------------------------------------------------
1 | namespace Weikio.PluginFramework.Samples.Shared
2 | {
3 | public interface IOperator
4 | {
5 | int Calculate(int x, int y);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/samples/WebAppPluginsLibrary/WebAppPluginsLibrary.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/tests/unit/Weikio.PluginFramework.Tests/Plugins/AnotherPluginWithAttribute.cs:
--------------------------------------------------------------------------------
1 | namespace Weikio.PluginFramework.Tests.Plugins
2 | {
3 | [MyPlugin]
4 | public class AnotherPluginWithAttribute
5 | {
6 |
7 | }
8 | }
--------------------------------------------------------------------------------
/samples/WebApp/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/tests/unit/Weikio.PluginFramework.Tests/Plugins/AbstractPluginWithAttribute.cs:
--------------------------------------------------------------------------------
1 | namespace Weikio.PluginFramework.Tests.Plugins
2 | {
3 | [MyPlugin]
4 | public abstract class AbstractPluginWithAttribute
5 | {
6 |
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/samples/WebAppWithNuget/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/samples/WebAppWithRoslyn/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/samples/WebAppWithAppSettings/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/samples/WebAppWithDelegate/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/tests/integration/WebSites/PluginFrameworkTestBed/PluginFrameworkTestBed.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/samples/BlazorApp/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 | "AllowedHosts": "*"
10 | }
11 |
--------------------------------------------------------------------------------
/samples/WebApp/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 | "AllowedHosts": "*"
10 | }
11 |
--------------------------------------------------------------------------------
/samples/WebAppWithNuget/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 | "AllowedHosts": "*"
10 | }
11 |
--------------------------------------------------------------------------------
/samples/WebAppWithDelegate/ExternalService.cs:
--------------------------------------------------------------------------------
1 | namespace WebAppWithDelegate
2 | {
3 | public class ExternalService
4 | {
5 | public string GetWords()
6 | {
7 | return "Hello from external service";
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/samples/WebAppWithDelegate/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 | "AllowedHosts": "*"
10 | }
11 |
--------------------------------------------------------------------------------
/samples/WebAppWithRoslyn/ExternalService.cs:
--------------------------------------------------------------------------------
1 | namespace WebAppWithRoslyn
2 | {
3 | public class ExternalService
4 | {
5 | public string DoWork()
6 | {
7 | return "External service did some work";
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/samples/WebAppWithRoslyn/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 | "AllowedHosts": "*"
10 | }
11 |
--------------------------------------------------------------------------------
/tests/unit/Weikio.PluginFramework.Tests/Plugins/TypePluginWithName.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 |
3 | namespace Weikio.PluginFramework.Tests.Plugins
4 | {
5 | [DisplayName("MyCustomName")]
6 | public class TypePluginWithName
7 | {
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/samples/BlazorApp/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "DetailedErrors": true,
3 | "Logging": {
4 | "LogLevel": {
5 | "Default": "Information",
6 | "Microsoft": "Warning",
7 | "Microsoft.Hosting.Lifetime": "Information"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/tests/integration/WebSites/PluginFrameworkTestBed/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/tests/Assemblies/TestAssembly1/FirstPlugin.cs:
--------------------------------------------------------------------------------
1 | using TestIntefaces;
2 |
3 | namespace TestAssembly1
4 | {
5 | public class FirstPlugin : ICommand
6 | {
7 | public string RunMe()
8 | {
9 | return "Hello from RunMe";
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/tests/unit/Weikio.PluginFramework.Tests/Plugins/MyPluginAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Weikio.PluginFramework.Tests.Plugins
4 | {
5 | [AttributeUsage(AttributeTargets.Class)]
6 | public class MyPluginAttribute : Attribute
7 | {
8 |
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/tests/integration/WebSites/PluginFrameworkTestBed/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 | "AllowedHosts": "*"
10 | }
11 |
--------------------------------------------------------------------------------
/tests/integration/Weikio.PluginFramework.Catalogs.NuGet.Tests/NuGet.Config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/samples/WpfApp/DivideOperator.cs:
--------------------------------------------------------------------------------
1 | using Weikio.PluginFramework.Samples.Shared;
2 |
3 | namespace WpfApp
4 | {
5 | public class DivideOperator : IOperator
6 | {
7 | public int Calculate(int x, int y)
8 | {
9 | return x / y;
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/samples/WinFormsApp/DivideOperator.cs:
--------------------------------------------------------------------------------
1 | using Weikio.PluginFramework.Samples.Shared;
2 |
3 | namespace WinFormsApp
4 | {
5 | public class DivideOperator : IOperator
6 | {
7 | public int Calculate(int x, int y)
8 | {
9 | return x / y;
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/samples/ConsoleApp/FirstPlugin.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Weikio.PluginFramework.Samples.Shared;
3 |
4 | namespace ConsoleApp
5 | {
6 | public class FirstPlugin : IPlugin
7 | {
8 | public void Run()
9 | {
10 | Console.WriteLine("First plugin");
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/tests/Assemblies/TestIntefaces/TestIntefaces.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 |
6 |
7 |
8 | ..\bin
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/samples/ConsoleApp/SecondPlugin.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Weikio.PluginFramework.Samples.Shared;
3 |
4 | namespace ConsoleApp
5 | {
6 | public class SecondPlugin : IPlugin
7 | {
8 | public void Run()
9 | {
10 | Console.WriteLine("Second plugin");
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/samples/Shared/Weikio.PluginFramework.Samples.Shared/RemainderOperator.cs:
--------------------------------------------------------------------------------
1 | namespace Weikio.PluginFramework.Samples.Shared
2 | {
3 | public class RemainderOperator : IOperator
4 | {
5 | public int Calculate(int x, int y)
6 | {
7 | return x % y;
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/tests/Assemblies/TestAssembly2/TestAssembly2.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 |
6 |
7 |
8 | ..\bin
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/tests/unit/Weikio.PluginFramework.Tests/NotThreadSafeResourceCollection.cs:
--------------------------------------------------------------------------------
1 | using Xunit;
2 |
3 | namespace Weikio.PluginFramework.Tests
4 | {
5 | [CollectionDefinition(nameof(NotThreadSafeResourceCollection), DisableParallelization = true)]
6 | public class NotThreadSafeResourceCollection
7 | {
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/samples/ConsoleApp/MyPlugin.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Weikio.PluginFramework.Samples.Shared;
3 |
4 | namespace ConsoleApp
5 | {
6 | public class MyPlugin : IMyPlugin
7 | {
8 | public void Run()
9 | {
10 | Console.WriteLine("My plugin which implements IMyPlugin");
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework/TypeFinding/ITypeFindingContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Reflection;
3 |
4 | namespace Weikio.PluginFramework.TypeFinding
5 | {
6 | public interface ITypeFindingContext
7 | {
8 | Assembly FindAssembly(string assemblyName);
9 | Type FindType(Type type);
10 | }
11 | }
--------------------------------------------------------------------------------
/tests/integration/Weikio.PluginFramework.Catalogs.NuGet.Tests/NotThreadSafeResourceCollection.cs:
--------------------------------------------------------------------------------
1 | using Xunit;
2 |
3 | namespace PluginFramework.Catalogs.NuGet.Tests
4 | {
5 | [CollectionDefinition(nameof(NotThreadSafeResourceCollection), DisableParallelization = true)]
6 | public class NotThreadSafeResourceCollection { }
7 | }
8 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework/Catalogs/Delegates/ParameterConversion.cs:
--------------------------------------------------------------------------------
1 | namespace Weikio.PluginFramework.Catalogs.Delegates
2 | {
3 | public class ParameterConversion
4 | {
5 | public bool ToConstructor { get; set; }
6 | public bool ToPublicProperty { get; set; }
7 | public string Name { get; set; }
8 | }
9 | }
--------------------------------------------------------------------------------
/samples/Shared/Weikio.PluginFramework.Samples.SharedPlugins/SumOperator.cs:
--------------------------------------------------------------------------------
1 | using Weikio.PluginFramework.Samples.Shared;
2 |
3 | namespace Weikio.PluginFramework.Samples.SharedPlugins
4 | {
5 | public class SumOperator : IOperator
6 | {
7 | public int Calculate(int x, int y)
8 | {
9 | return x + y;
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/samples/Shared/Weikio.PluginFramework.Samples.SharedPlugins/MinusOperator.cs:
--------------------------------------------------------------------------------
1 | using Weikio.PluginFramework.Samples.Shared;
2 |
3 | namespace Weikio.PluginFramework.Samples.SharedPlugins
4 | {
5 | public class MinusOperator : IOperator
6 | {
7 | public int Calculate(int x, int y)
8 | {
9 | return x - y;
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/samples/BlazorApp/_Imports.razor:
--------------------------------------------------------------------------------
1 | @using System.Net.Http
2 | @using Microsoft.AspNetCore.Authorization
3 | @using Microsoft.AspNetCore.Components.Authorization
4 | @using Microsoft.AspNetCore.Components.Forms
5 | @using Microsoft.AspNetCore.Components.Routing
6 | @using Microsoft.AspNetCore.Components.Web
7 | @using Microsoft.JSInterop
8 | @using BlazorApp
9 | @using BlazorApp.Shared
--------------------------------------------------------------------------------
/samples/BlazorApp/Shared/MainLayout.razor:
--------------------------------------------------------------------------------
1 | @inherits LayoutComponentBase
2 |
3 |
6 |
7 |
8 |
11 |
12 |
13 | @Body
14 |
15 |
--------------------------------------------------------------------------------
/samples/BlazorApp/Data/WeatherForecast.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace BlazorApp.Data
4 | {
5 | public class WeatherForecast
6 | {
7 | public DateTime Date { get; set; }
8 |
9 | public int TemperatureC { get; set; }
10 |
11 | public int TemperatureF => 32 + (int) (TemperatureC / 0.5556);
12 |
13 | public string Summary { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/samples/BlazorApp/App.razor:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Sorry, there's nothing at this address.
8 |
9 |
10 |
--------------------------------------------------------------------------------
/samples/Shared/Weikio.PluginFramework.Samples.SharedPlugins/SecondSharedPlugin.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Weikio.PluginFramework.Samples.Shared;
3 |
4 | namespace Weikio.PluginFramework.Samples.SharedPlugins
5 | {
6 | public class SecondSharedPlugin : IOutPlugin
7 | {
8 | public string Get()
9 | {
10 | return "Second shared plugin";
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/samples/WpfApp/App.xaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/tests/Assemblies/JsonNetNew/NewJsonResolver.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using TestIntefaces;
3 |
4 | namespace JsonNetNew
5 | {
6 | public class NewJsonResolver : IJsonVersionResolver
7 | {
8 | public string GetVersion()
9 | {
10 | var result = typeof(JsonConvert).Assembly.GetName().Version.ToString();
11 |
12 | return result;
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/samples/WpfApp/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.Data;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 | using System.Windows;
8 |
9 | namespace WpfApp
10 | {
11 | ///
12 | /// Interaction logic for App.xaml
13 | ///
14 | public partial class App : Application
15 | {
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/samples/WebAppWithAppSettings/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "PluginFramework": {
3 | "Catalogs": [
4 | {
5 | "Type": "Folder",
6 | "Path": "..\\Shared\\Weikio.PluginFramework.Samples.SharedPlugins\\bin\\debug\\netcoreapp3.1"
7 | },
8 | {
9 | "Type": "Assembly",
10 | "Path": ".\\bin\\Debug\\netcoreapp3.1\\WebAppPluginsLibrary.dll"
11 | }
12 | ]
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/tests/Assemblies/TestAssembly1/TestAssembly1.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 |
6 |
7 |
8 | ..\bin
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/tests/Assemblies/TestAssembly3/TestAssembly3.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 |
6 |
7 |
8 | ..\bin
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/tests/integration/WebSites/PluginFrameworkTestBed/WeatherForecast.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace PluginFrameworkTestBed
4 | {
5 | public class WeatherForecast
6 | {
7 | public DateTime Date { get; set; }
8 |
9 | public int TemperatureC { get; set; }
10 |
11 | public int TemperatureF => 32 + (int) (TemperatureC / 0.5556);
12 |
13 | public string Summary { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework.Abstractions/PluginFrameworkOptions.cs:
--------------------------------------------------------------------------------
1 | namespace Weikio.PluginFramework.Abstractions
2 | {
3 | ///
4 | /// Configures the options for Plugin Framework.
5 | ///
6 | public class PluginFrameworkOptions
7 | {
8 | public bool UseConfiguration { get; set; } = true;
9 | public string ConfigurationSection { get; set; } = "PluginFramework";
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/samples/BlazorApp/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json.schemastore.org/launchsettings.json",
3 | "profiles": {
4 | "BlazorApp": {
5 | "commandName": "Project",
6 | "launchBrowser": true,
7 | "launchUrl": "",
8 | "environmentVariables": {
9 | "ASPNETCORE_ENVIRONMENT": "Development"
10 | },
11 | "applicationUrl": "https://localhost:5001;http://localhost:5000"
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/samples/Shared/Weikio.PluginFramework.Samples.SharedPlugins/MultiplyOperator.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using Weikio.PluginFramework.Samples.Shared;
3 |
4 | namespace Weikio.PluginFramework.Samples.SharedPlugins
5 | {
6 | [DisplayName("The multiplier plugin")]
7 | public class MultiplyOperator : IOperator
8 | {
9 | public int Calculate(int x, int y)
10 | {
11 | return x * y;
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework.Configuration/CatalogConfiguration.cs:
--------------------------------------------------------------------------------
1 | namespace Weikio.PluginFramework.Configuration
2 | {
3 | ///
4 | /// Base configuration class for catalogs.
5 | ///
6 | public class CatalogConfiguration
7 | {
8 | ///
9 | /// The type of the catalog this configuration section represents.
10 | ///
11 | public string? Type { get; set; }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/samples/WebApp/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json.schemastore.org/launchsettings.json",
3 | "profiles": {
4 | "WebApp": {
5 | "commandName": "Project",
6 | "launchBrowser": true,
7 | "launchUrl": "Calculator",
8 | "environmentVariables": {
9 | "ASPNETCORE_ENVIRONMENT": "Development"
10 | },
11 | "applicationUrl": "https://localhost:5001;http://localhost:5000"
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework.AspNetCore/DefaultPluginOption.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace Weikio.PluginFramework.AspNetCore
7 | {
8 | public class DefaultPluginOption
9 | {
10 | public Func, Type> DefaultType { get; set; }
11 | = (serviceProvider, implementingTypes) => implementingTypes.FirstOrDefault();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework.Catalogs.Roslyn/InvalidCodeException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Weikio.PluginFramework.Catalogs.Roslyn
4 | {
5 | public class InvalidCodeException : Exception
6 | {
7 | public InvalidCodeException(Exception exception) : this("", exception)
8 | {
9 | }
10 |
11 | public InvalidCodeException(string message, Exception exception) : base(message, exception)
12 | {
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/samples/WebAppWithNuget/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json.schemastore.org/launchsettings.json",
3 | "profiles": {
4 | "WebAppWithNuget": {
5 | "commandName": "Project",
6 | "launchBrowser": true,
7 | "launchUrl": "Calculator",
8 | "environmentVariables": {
9 | "ASPNETCORE_ENVIRONMENT": "Development"
10 | },
11 | "applicationUrl": "https://localhost:5001;http://localhost:5000"
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/samples/WebAppWithRoslyn/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json.schemastore.org/launchsettings.json",
3 | "profiles": {
4 | "WebAppWithRoslyn": {
5 | "commandName": "Project",
6 | "launchBrowser": true,
7 | "launchUrl": "Roslyn",
8 | "environmentVariables": {
9 | "ASPNETCORE_ENVIRONMENT": "Development"
10 | },
11 | "applicationUrl": "https://localhost:5001;http://localhost:5000"
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/samples/WebAppWithDelegate/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json.schemastore.org/launchsettings.json",
3 | "profiles": {
4 | "WebAppWithDelegate": {
5 | "commandName": "Project",
6 | "launchBrowser": true,
7 | "launchUrl": "Delegate",
8 | "environmentVariables": {
9 | "ASPNETCORE_ENVIRONMENT": "Development"
10 | },
11 | "applicationUrl": "https://localhost:5001;http://localhost:5000"
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/samples/WebAppWithAppSettings/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json.schemastore.org/launchsettings.json",
3 | "profiles": {
4 | "WebAppWithAppSettings": {
5 | "commandName": "Project",
6 | "launchBrowser": true,
7 | "launchUrl": "Calculator",
8 | "environmentVariables": {
9 | "ASPNETCORE_ENVIRONMENT": "Development"
10 | },
11 | "applicationUrl": "https://localhost:5001;http://localhost:5000"
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/samples/BlazorApp/Pages/Counter.razor:
--------------------------------------------------------------------------------
1 | @page "/counter"
2 | @implements Weikio.PluginFramework.Samples.Shared.IWidget
3 |
4 | Current count: @currentCount
5 |
6 | Click me
7 |
8 | @code {
9 | private int currentCount = 0;
10 |
11 | private void IncrementCount()
12 | {
13 | currentCount++;
14 | }
15 |
16 | public string Title
17 | {
18 | get { return "Counter Widget"; }
19 | }
20 | }
--------------------------------------------------------------------------------
/samples/Shared/Weikio.PluginFramework.Samples.Shared/IPlugin.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Weikio.PluginFramework.Samples.Shared
4 | {
5 | public interface IPlugin
6 | {
7 | void Run();
8 | }
9 |
10 | public interface IOutPlugin
11 | {
12 | string Get();
13 | }
14 |
15 | public interface IWidget
16 | {
17 | string Title { get; }
18 | }
19 |
20 | public interface IDialog
21 | {
22 | void Show();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/samples/WpfApp/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | [assembly: ThemeInfo(
4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
5 | //(used if a resource is not found in the page,
6 | // or application resource dictionaries)
7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
8 | //(used if a resource is not found in the page,
9 | // app, or any theme specific resource dictionaries)
10 | )]
11 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework/Context/RuntimeAssemblyHint.cs:
--------------------------------------------------------------------------------
1 | namespace Weikio.PluginFramework.Context
2 | {
3 | public class RuntimeAssemblyHint
4 | {
5 | public string FileName { get; set; }
6 | public string Path { get; set; }
7 | public bool IsNative { get; set; }
8 |
9 | public RuntimeAssemblyHint(string fileName, string path, bool isNative)
10 | {
11 | FileName = fileName;
12 | Path = path;
13 | IsNative = isNative;
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/samples/BlazorApp/Shared/SurveyPrompt.razor:
--------------------------------------------------------------------------------
1 | @implements Weikio.PluginFramework.Samples.Shared.IWidget
2 |
3 |
4 |
5 | Please take our
6 | brief survey
7 |
8 | and tell us what you think.
9 |
10 |
11 | @code {
12 | public string Title { get; } = "Surveys";
13 | }
--------------------------------------------------------------------------------
/tests/Assemblies/JsonNetNew/JsonNetNew.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 |
6 |
7 |
8 | ..\bin\JsonNew
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/samples/WinFormsPluginsLibrary/LabelPlugin.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel;
3 | using System.Windows.Forms;
4 | using Weikio.PluginFramework.Samples.Shared;
5 |
6 | namespace WinFormsPluginsLibrary
7 | {
8 | public partial class LabelPlugin : Form, IDialog
9 | {
10 | public LabelPlugin()
11 | {
12 | InitializeComponent();
13 | }
14 |
15 | private void button1_Click(object sender, EventArgs e)
16 | {
17 | label1.Text = "Another simple example";
18 | }
19 | }
20 | }
21 |
22 |
--------------------------------------------------------------------------------
/samples/WinFormsApp/WinFormsApp.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | WinExe
5 | netcoreapp3.1
6 | true
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/samples/WinFormsPluginsLibrary/TestPlugin.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel;
3 | using System.Windows.Forms;
4 | using Weikio.PluginFramework.Samples.Shared;
5 |
6 | namespace WinFormsPluginsLibrary
7 | {
8 | [DisplayName("Hello World")]
9 | public partial class TestPlugin : Form, IDialog
10 | {
11 | public TestPlugin()
12 | {
13 | InitializeComponent();
14 | }
15 |
16 | private void button1_Click(object sender, EventArgs e)
17 | {
18 | MessageBox.Show("Hello Plugin Framework");
19 | }
20 | }
21 | }
22 |
23 |
--------------------------------------------------------------------------------
/tests/Assemblies/JsonNetOld/JsonNetOld.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 |
6 |
7 |
8 | ..\bin\JsonOld
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/samples/WebAppWithDelegate/Program.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Hosting;
2 | using Microsoft.Extensions.Hosting;
3 |
4 | namespace WebAppWithDelegate
5 | {
6 | public class Program
7 | {
8 | public static void Main(string[] args)
9 | {
10 | CreateHostBuilder(args).Build().Run();
11 | }
12 |
13 | public static IHostBuilder CreateHostBuilder(string[] args) =>
14 | Host.CreateDefaultBuilder(args)
15 | .ConfigureWebHostDefaults(webBuilder =>
16 | {
17 | webBuilder.UseStartup();
18 | });
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/samples/WebAppWithRoslyn/Program.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Hosting;
2 | using Microsoft.Extensions.Hosting;
3 |
4 | namespace WebAppWithRoslyn
5 | {
6 | public class Program
7 | {
8 | public static void Main(string[] args)
9 | {
10 | CreateHostBuilder(args).Build().Run();
11 | }
12 |
13 | public static IHostBuilder CreateHostBuilder(string[] args) =>
14 | Host.CreateDefaultBuilder(args)
15 | .ConfigureWebHostDefaults(webBuilder =>
16 | {
17 | webBuilder.UseStartup();
18 | });
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/samples/WebAppWithAppSettings/Program.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Hosting;
2 | using Microsoft.Extensions.Hosting;
3 |
4 | namespace WebAppWithAppSettings
5 | {
6 | public class Program
7 | {
8 | public static void Main(string[] args)
9 | {
10 | CreateHostBuilder(args).Build().Run();
11 | }
12 |
13 | public static IHostBuilder CreateHostBuilder(string[] args) =>
14 | Host.CreateDefaultBuilder(args)
15 | .ConfigureWebHostDefaults(webBuilder =>
16 | {
17 | webBuilder.UseStartup();
18 | });
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/samples/ConsoleApp/ConsoleApp.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp3.1
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/samples/WebAppWithNuget/WebAppWithNuget.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/samples/WebApp/Program.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Hosting;
2 | using Microsoft.Extensions.Configuration;
3 | using Microsoft.Extensions.Hosting;
4 |
5 | namespace WebApp
6 | {
7 | public class Program
8 | {
9 | public static void Main(string[] args)
10 | {
11 | CreateHostBuilder(args).Build().Run();
12 | }
13 |
14 | public static IHostBuilder CreateHostBuilder(string[] args) =>
15 | Host.CreateDefaultBuilder(args)
16 | .ConfigureWebHostDefaults(webBuilder =>
17 | {
18 | webBuilder.UseStartup();
19 | });
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/samples/WebAppWithDelegate/WebAppWithDelegate.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | Never
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/samples/WpfApp/WpfApp.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | WinExe
5 | netcoreapp3.1
6 | true
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/samples/BlazorApp/BlazorApp.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | Never
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/samples/WinFormsPluginsLibrary/WinFormsPluginsLibrary.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 | true
6 |
7 |
8 |
9 |
10 | Form
11 |
12 |
13 | Form
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework/TypeFinding/TypeFinderCriteria.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace Weikio.PluginFramework.TypeFinding
5 | {
6 | public class TypeFinderCriteria
7 | {
8 | public Type Inherits { get; set; }
9 | public Type Implements { get; set; }
10 | public Type AssignableTo { get; set; }
11 | public bool? IsAbstract { get; set; }
12 | public bool? IsInterface { get; set; }
13 | public string Name { get; set; }
14 | public Func Query { get; set; }
15 | public Type HasAttribute { get; set; }
16 | public List Tags { get; set; } = new List();
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/samples/WinFormsApp/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using System.Windows.Forms;
7 | using Weikio.PluginFramework.Context;
8 |
9 | namespace WinFormsApp
10 | {
11 | static class Program
12 | {
13 | ///
14 | /// The main entry point for the application.
15 | ///
16 | [STAThread]
17 | static void Main()
18 | {
19 | Application.SetHighDpiMode(HighDpiMode.SystemAware);
20 | Application.EnableVisualStyles();
21 | Application.SetCompatibleTextRenderingDefault(false);
22 | Application.Run(new Form1());
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/tests/unit/Weikio.PluginFramework.Catalogs.Roslyn.Tests/Weikio.PluginFramework.Catalogs.Roslyn.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/samples/BlazorApp/Pages/Error.razor:
--------------------------------------------------------------------------------
1 | @page "/error"
2 |
3 |
4 | Error.
5 | An error occurred while processing your request.
6 |
7 | Development Mode
8 |
9 | Swapping to Development environment will display more detailed information about the error that occurred.
10 |
11 |
12 | The Development environment shouldn't be enabled for deployed applications.
13 | It can result in displaying sensitive information from exceptions to end users.
14 | For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development
15 | and restarting the app.
16 |
--------------------------------------------------------------------------------
/samples/WebAppWithRoslyn/WebAppWithRoslyn.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | Never
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework.AspNetCore/PluginExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Weikio.PluginFramework.Abstractions;
3 |
4 | // ReSharper disable once CheckNamespace
5 | namespace Microsoft.Extensions.DependencyInjection
6 | {
7 | public static class PluginExtensions
8 | {
9 | public static object Create(this Plugin plugin, IServiceProvider serviceProvider, params object[] parameters)
10 | {
11 | return ActivatorUtilities.CreateInstance(serviceProvider, plugin, parameters);
12 | }
13 |
14 | public static T Create(this Plugin plugin, IServiceProvider serviceProvider, params object[] parameters) where T : class
15 | {
16 | return ActivatorUtilities.CreateInstance(serviceProvider, plugin, parameters) as T;
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework.AspNetCore/ServiceProviderExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using Weikio.PluginFramework.Abstractions;
5 |
6 | // ReSharper disable once CheckNamespace
7 | namespace Microsoft.Extensions.DependencyInjection
8 | {
9 | public static class ServiceProviderExtensions
10 | {
11 | public static object Create(this IServiceProvider serviceProvider, Plugin plugin)
12 | {
13 | return ActivatorUtilities.CreateInstance(serviceProvider, plugin);
14 | }
15 |
16 | public static T Create(this IServiceProvider serviceProvider, Plugin plugin) where T : class
17 | {
18 | return ActivatorUtilities.CreateInstance(serviceProvider, plugin) as T;
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework/Context/UseHostApplicationAssembliesEnum.cs:
--------------------------------------------------------------------------------
1 | namespace Weikio.PluginFramework.Context
2 | {
3 | public enum UseHostApplicationAssembliesEnum
4 | {
5 | ///
6 | /// Never use user host application's assemblies
7 | ///
8 | Never,
9 |
10 | ///
11 | /// Only use the listed hosted application assemblies
12 | ///
13 | Selected,
14 |
15 | ///
16 | /// Always try to use host application's assemblies
17 | ///
18 | Always,
19 |
20 | ///
21 | /// Prefer plugin's referenced assemblies, fallback to host application's assemblies
22 | ///
23 | PreferPlugin
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/tests/Assemblies/JsonNetOld/OldJsonResolver.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Newtonsoft.Json;
3 | using TestIntefaces;
4 |
5 | namespace JsonNetOld
6 | {
7 | public class OldJsonResolver : IJsonVersionResolver
8 | {
9 | public string GetVersion()
10 | {
11 | var result = typeof(JsonConvert).Assembly.GetName().Version.ToString();
12 |
13 | return result;
14 | }
15 |
16 | public string GetLoggingVersion()
17 | {
18 | var logging = new Microsoft.Extensions.Logging.LoggerFactory();
19 | Console.WriteLine(logging.ToString());
20 |
21 | var result = typeof(Microsoft.Extensions.Logging.LoggerFactory).Assembly.GetName().Version.ToString();
22 |
23 | return result;
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/samples/BlazorApp/Pages/Index.razor:
--------------------------------------------------------------------------------
1 | @page "/"
2 | @using Weikio.PluginFramework.Samples.Shared
3 |
4 |
5 | Widget dashboard
6 |
7 |
8 | @foreach (var widget in Widgets)
9 | {
10 |
11 |
12 |
@widget.Title
13 |
14 | @RenderWidget(widget)
15 |
16 |
17 | }
18 |
19 |
20 | @code{
21 |
22 | [Inject]
23 | public IEnumerable Widgets { get; set; }
24 |
25 | private RenderFragment RenderWidget(IWidget widget)
26 | {
27 | return new RenderFragment(builder =>
28 | {
29 | builder.OpenComponent(0, widget.GetType());
30 | builder.CloseComponent();
31 | });
32 | }
33 |
34 | }
--------------------------------------------------------------------------------
/samples/Shared/Weikio.PluginFramework.Samples.Shared/Weikio.PluginFramework.Samples.Shared.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 | true
6 | true
7 | Plugin Framework shared sample
8 | Plugin Framework shared sample
9 | Plugin Framework shared sample
10 | Weikio.PluginFramework.Samples.Shared
11 | Weikio.PluginFramework.Samples.Shared
12 | Weikio.PluginFramework.Samples.Shared
13 | plugins;addons;plugin framework;samples
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/samples/WebAppWithNuget/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Hosting;
6 | using Microsoft.Extensions.Configuration;
7 | using Microsoft.Extensions.Hosting;
8 | using Microsoft.Extensions.Logging;
9 |
10 | namespace WebAppWithNuget
11 | {
12 | public class Program
13 | {
14 | public static void Main(string[] args)
15 | {
16 | CreateHostBuilder(args).Build().Run();
17 | }
18 |
19 | public static IHostBuilder CreateHostBuilder(string[] args) =>
20 | Host.CreateDefaultBuilder(args)
21 | .ConfigureWebHostDefaults(webBuilder =>
22 | {
23 | webBuilder.UseStartup();
24 | });
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/samples/WebApp/WebApp.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | Never
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/tests/integration/WebSites/PluginFrameworkTestBed/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Hosting;
6 | using Microsoft.Extensions.Configuration;
7 | using Microsoft.Extensions.Hosting;
8 | using Microsoft.Extensions.Logging;
9 |
10 | namespace PluginFrameworkTestBed
11 | {
12 | public class Program
13 | {
14 | public static void Main(string[] args)
15 | {
16 | CreateHostBuilder(args).Build().Run();
17 | }
18 |
19 | public static IHostBuilder CreateHostBuilder(string[] args) =>
20 | Host.CreateDefaultBuilder(args)
21 | .ConfigureWebHostDefaults(webBuilder =>
22 | {
23 | webBuilder.UseStartup();
24 | });
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/samples/BlazorApp/Data/WeatherForecastService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Threading.Tasks;
4 |
5 | namespace BlazorApp.Data
6 | {
7 | public class WeatherForecastService
8 | {
9 | private static readonly string[] Summaries = new[]
10 | {
11 | "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
12 | };
13 |
14 | public Task GetForecastAsync(DateTime startDate)
15 | {
16 | var rng = new Random();
17 |
18 | return Task.FromResult(Enumerable.Range(1, 5).Select(index => new WeatherForecast
19 | {
20 | Date = startDate.AddDays(index), TemperatureC = rng.Next(-20, 55), Summary = Summaries[rng.Next(Summaries.Length)]
21 | }).ToArray());
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/samples/BlazorApp/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore;
7 | using Microsoft.AspNetCore.Hosting;
8 | using Microsoft.Extensions.Configuration;
9 | using Microsoft.Extensions.Hosting;
10 | using Microsoft.Extensions.Logging;
11 |
12 | namespace BlazorApp
13 | {
14 | public class Program
15 | {
16 | public static void Main(string[] args)
17 | {
18 | CreateHostBuilder(args).Build().Run();
19 | }
20 |
21 | public static IHostBuilder CreateHostBuilder(string[] args) =>
22 | Host.CreateDefaultBuilder(args)
23 | .ConfigureWebHostDefaults(webBuilder =>
24 | {
25 | webBuilder.UseStartup();
26 | });
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/tests/integration/Weikio.PluginFramework.Catalogs.NuGet.Tests/Weikio.PluginFramework.Catalogs.NuGet.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 |
7 |
8 |
9 |
10 |
11 | all
12 | runtime; build; native; contentfiles; analyzers; buildtransitive
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/tests/unit/Weikio.PluginFramework.Tests/Weikio.PluginFramework.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/samples/BlazorApp/Shared/NavMenu.razor:
--------------------------------------------------------------------------------
1 |
7 |
8 |
17 |
18 | @code {
19 | private bool collapseNavMenu = true;
20 |
21 | private string NavMenuCssClass => collapseNavMenu ? "collapse" : null;
22 |
23 | private void ToggleNavMenu()
24 | {
25 | collapseNavMenu = !collapseNavMenu;
26 | }
27 |
28 | }
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework/TypeFinding/TypeFinderOptions.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Collections.ObjectModel;
3 |
4 | namespace Weikio.PluginFramework.TypeFinding
5 | {
6 | public class TypeFinderOptions
7 | {
8 | ///
9 | /// Gets or sets the
10 | ///
11 | public List TypeFinderCriterias { get; set; } = new List(Defaults.GetDefaultTypeFinderCriterias());
12 |
13 | public static class Defaults
14 | {
15 | public static List TypeFinderCriterias { get; set; } = new List();
16 |
17 | public static ReadOnlyCollection GetDefaultTypeFinderCriterias()
18 | {
19 | return TypeFinderCriterias.AsReadOnly();
20 | }
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/samples/WebAppWithAppSettings/WebAppWithAppSettings.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | Never
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/samples/WebAppWithNuget/Controllers/CalculatorController.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Microsoft.AspNetCore.Mvc;
3 | using Weikio.PluginFramework.Abstractions;
4 | using Weikio.PluginFramework.Samples.Shared;
5 |
6 | namespace WebAppWithNuget.Controllers
7 | {
8 | [ApiController]
9 | [Route("[controller]")]
10 | public class CalculatorController : ControllerBase
11 | {
12 | private readonly IEnumerable _operators;
13 | private readonly IEnumerable _plugins;
14 |
15 | public CalculatorController(IEnumerable operators, IEnumerable plugins, IOperator myOperator)
16 | {
17 | _operators = operators;
18 | _plugins = plugins;
19 | }
20 |
21 | [HttpGet]
22 | public string Get()
23 | {
24 | var pluginsList = string.Join(", ", _plugins);
25 |
26 | return pluginsList;
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework.Configuration/Converters/AssemblyCatalogConfigurationCoverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.Extensions.Configuration;
3 | using Weikio.PluginFramework.Abstractions;
4 | using Weikio.PluginFramework.Catalogs;
5 |
6 | namespace Weikio.PluginFramework.Configuration.Converters
7 | {
8 | ///
9 | /// Converter implementation for the .
10 | ///
11 | public class AssemblyCatalogConfigurationCoverter : IConfigurationToCatalogConverter
12 | {
13 | ///
14 | public bool CanConvert(string type)
15 | {
16 | return string.Equals(type, "Assembly", StringComparison.InvariantCultureIgnoreCase);
17 | }
18 |
19 | ///
20 | public IPluginCatalog Convert(IConfigurationSection section)
21 | {
22 | var path = section.GetValue("Path");
23 |
24 | return new AssemblyPluginCatalog(path);
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework.Configuration/Providers/IPluginCatalogConfigurationLoader.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Microsoft.Extensions.Configuration;
3 |
4 | namespace Weikio.PluginFramework.Configuration.Providers
5 | {
6 | ///
7 | /// Interface that specified the methods a PluginCatalogConfigurationProvider needs.
8 | ///
9 | public interface IPluginCatalogConfigurationLoader
10 | {
11 | ///
12 | /// The key of the catalogs section inside the parent configuration section ( ).
13 | ///
14 | string CatalogsKey { get; }
15 |
16 | ///
17 | /// Returns a list that contains catalog configurations.
18 | ///
19 | /// The configuration to use.
20 | /// A list that contains catalog configurations.
21 | List GetCatalogConfigurations(IConfiguration configuration);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework/Catalogs/EmptyPluginCatalog.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Reflection;
4 | using System.Threading.Tasks;
5 | using Weikio.PluginFramework.Abstractions;
6 |
7 | namespace Weikio.PluginFramework.Catalogs
8 | {
9 | ///
10 | /// Empty Plugin catalog. Doesn't contain anything, is automatically initialized when created.
11 | ///
12 | public class EmptyPluginCatalog : IPluginCatalog
13 | {
14 | ///
15 | public Task Initialize()
16 | {
17 | return Task.CompletedTask;
18 | }
19 |
20 | ///
21 | public bool IsInitialized { get; } = true;
22 |
23 | ///
24 | public List GetPlugins()
25 | {
26 | return new List();
27 | }
28 |
29 | ///
30 | public Plugin Get(string name, Version version)
31 | {
32 | return null;
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/samples/Shared/Weikio.PluginFramework.Samples.SharedPlugins/Weikio.PluginFramework.Samples.SharedPlugins.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 | true
6 | true
7 | Plugin Framework shared sample plugins
8 | Plugin Framework shared sample plugins
9 | Plugin Framework shared sample plugins
10 | Weikio.PluginFramework.Samples.SharedPlugins
11 | Weikio.PluginFramework.Samples.SharedPlugins
12 | Weikio.PluginFramework.Samples.SharedPlugins
13 | plugins;addons;plugin framework;samples
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Weik.io
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework.Abstractions/IPluginCatalog.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Reflection;
4 | using System.Threading.Tasks;
5 |
6 | namespace Weikio.PluginFramework.Abstractions
7 | {
8 | ///
9 | /// Represents a single Plugin Catalog. Can contain 0-n plugins.
10 | ///
11 | public interface IPluginCatalog
12 | {
13 | ///
14 | /// Initializes the catalog
15 | ///
16 | Task Initialize();
17 |
18 | ///
19 | /// Gets if the catalog is initialized
20 | ///
21 | bool IsInitialized { get; }
22 |
23 | ///
24 | /// Gets all the plugins
25 | ///
26 | /// List of
27 | List GetPlugins();
28 |
29 | ///
30 | /// Gets a single plugin based on its name and version
31 | ///
32 | /// The
33 | Plugin Get(string name, Version version);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/samples/BlazorApp/Pages/_Host.cshtml:
--------------------------------------------------------------------------------
1 | @page "/"
2 | @namespace BlazorApp.Pages
3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
4 | @{
5 | Layout = null;
6 | }
7 |
8 |
9 |
10 |
11 |
12 |
13 | BlazorApp
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | An error has occurred. This application may no longer respond until reloaded.
26 |
27 |
28 | An unhandled exception has occurred. See browser dev tools for details.
29 |
30 |
Reload
31 |
🗙
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework.Abstractions/Weikio.PluginFramework.Abstractions.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | true
6 | true
7 | Abstractions for Plugin Framework.
8 | Abstractions for Plugin Framework.
9 | Weikio.PluginFramework.Abstractions
10 | Weikio.PluginFramework.Abstractions
11 | Weikio.PluginFramework.Abstractions
12 | plugins;addons;extensions;plugin framework
13 | logo_transparent_color_256.png
14 | Plugin Framework Abstractions
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/samples/BlazorApp/wwwroot/css/open-iconic/ICON-LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Waybury
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework.Configuration/Converters/IConfigurationToCatalogConverter.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Configuration;
2 | using Weikio.PluginFramework.Abstractions;
3 |
4 | namespace Weikio.PluginFramework.Configuration.Converters
5 | {
6 | ///
7 | /// Interface that specifies the methods a ConfigurationConverter needs.
8 | ///
9 | public interface IConfigurationToCatalogConverter
10 | {
11 | ///
12 | /// Determines if the converter can convert the provided type.
13 | /// True if it can, false otherwise.
14 | ///
15 | ///
16 | /// True if the type can be converted.
17 | bool CanConvert(string type);
18 |
19 | ///
20 | /// Convert a Catalog Configuration to it's equivalent object.
21 | ///
22 | /// The section that contains the catalog configuration.
23 | /// An equivalent object.
24 | IPluginCatalog Convert(IConfigurationSection section);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework/Catalogs/Delegates/DelegatePluginCatalogOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Reflection;
4 | using Weikio.PluginFramework.Abstractions;
5 |
6 | namespace Weikio.PluginFramework.Catalogs.Delegates
7 | {
8 | public class DelegatePluginCatalogOptions
9 | {
10 | public PluginNameOptions NameOptions { get; set; } = new PluginNameOptions();
11 | public List ConversionRules { get; set; } = new List();
12 | public string MethodName { get; set; } = "Run";
13 | public string TypeName { get; set; } = "GeneratedType";
14 | public string NamespaceName { get; set; } = "GeneratedNamespace";
15 | public Func MethodNameGenerator { get; set; } = options => options.MethodName;
16 | public Func TypeNameGenerator { get; set; } = options => options.TypeName;
17 | public Func NamespaceNameGenerator { get; set; } = options => options.NamespaceName;
18 | public List Tags { get; set; } = new List();
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework/Catalogs/Delegates/ConversionRule.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Reflection;
3 |
4 | namespace Weikio.PluginFramework.Catalogs.Delegates
5 | {
6 | public class DelegateConversionRule
7 | {
8 | private readonly Predicate _canHandle;
9 | private readonly Func _handle;
10 |
11 | public DelegateConversionRule(Predicate canHandle, Func handle)
12 | {
13 | if (canHandle == null)
14 | {
15 | throw new ArgumentNullException(nameof(canHandle));
16 | }
17 |
18 | if (handle == null)
19 | {
20 | throw new ArgumentNullException(nameof(handle));
21 | }
22 |
23 | _canHandle = canHandle;
24 | _handle = handle;
25 | }
26 |
27 | public bool CanHandle(ParameterInfo parameterInfo)
28 | {
29 | return _canHandle(parameterInfo);
30 | }
31 |
32 | public ParameterConversion Handle(ParameterInfo parameterInfo)
33 | {
34 | return _handle(parameterInfo);
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/samples/WpfApp/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/samples/BlazorApp/Pages/FetchData.razor:
--------------------------------------------------------------------------------
1 | @page "/fetchdata"
2 | @implements Weikio.PluginFramework.Samples.Shared.IWidget
3 |
4 | @using BlazorApp.Data
5 | @inject WeatherForecastService ForecastService
6 |
7 | @if (forecasts == null)
8 | {
9 |
10 | Loading...
11 |
12 | }
13 | else
14 | {
15 |
16 |
17 |
18 | Date
19 | Temp. (C)
20 | Temp. (F)
21 | Summary
22 |
23 |
24 |
25 | @foreach (var forecast in forecasts)
26 | {
27 |
28 | @forecast.Date.ToShortDateString()
29 | @forecast.TemperatureC
30 | @forecast.TemperatureF
31 | @forecast.Summary
32 |
33 | }
34 |
35 |
36 | }
37 |
38 | @code {
39 | private WeatherForecast[] forecasts;
40 |
41 | protected override async Task OnInitializedAsync()
42 | {
43 | forecasts = await ForecastService.GetForecastAsync(DateTime.Now);
44 | }
45 |
46 | public string Title { get; } = "Weather forecasts";
47 | }
--------------------------------------------------------------------------------
/tests/unit/Weikio.PluginFramework.Tests/TypeFinderTests.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using Weikio.PluginFramework.Catalogs;
3 | using Weikio.PluginFramework.Tests.Plugins;
4 | using Xunit;
5 |
6 | namespace Weikio.PluginFramework.Tests
7 | {
8 | public class TypeFinderTests
9 | {
10 | [Fact]
11 | public async Task CanGetPluginsByAttribute()
12 | {
13 | var catalog = new AssemblyPluginCatalog(typeof(TypeFinderTests).Assembly, configure =>
14 | {
15 | configure.HasAttribute(typeof(MyPluginAttribute));
16 | });
17 |
18 | await catalog.Initialize();
19 |
20 | Assert.Equal(2, catalog.GetPlugins().Count);
21 | }
22 |
23 | [Fact]
24 | public async Task CanGetPluginsByMultipleCriteria()
25 | {
26 | var catalog = new AssemblyPluginCatalog(typeof(TypeFinderTests).Assembly, configure =>
27 | {
28 | configure.HasAttribute(typeof(MyPluginAttribute))
29 | .IsAbstract(true)
30 | .HasName(nameof(AbstractPluginWithAttribute));
31 | });
32 |
33 | await catalog.Initialize();
34 |
35 | Assert.Single(catalog.GetPlugins());
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/samples/WebApp/Controllers/CalculatorController.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using System.Text.Json;
4 | using Microsoft.AspNetCore.Mvc;
5 | using Weikio.PluginFramework.Samples.Shared;
6 | using Weikio.PluginFramework.Abstractions;
7 |
8 | namespace WebApp.Controllers
9 | {
10 | [ApiController]
11 | [Route("[controller]")]
12 | public class CalculatorController : ControllerBase
13 | {
14 | private readonly IEnumerable _operators;
15 | private readonly IEnumerable _plugins;
16 | private readonly IOperator _defaultOperator;
17 |
18 | public CalculatorController(IEnumerable operators, IEnumerable plugins, IOperator defaultOperator)
19 | {
20 | _operators = operators;
21 | _plugins = plugins;
22 | _defaultOperator = defaultOperator;
23 | }
24 |
25 | [HttpGet]
26 | public string Get()
27 | {
28 | return JsonSerializer.Serialize(new
29 | {
30 | allPlugins = _plugins.Select(p => p.ToString()),
31 | operators = _operators.Select(o => o.GetType().Name),
32 | defaultOperator = _defaultOperator.GetType().Name
33 | }, new JsonSerializerOptions { WriteIndented = true});
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework.Configuration/Providers/PluginCatalogConfigurationLoader.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Microsoft.Extensions.Configuration;
3 | using Microsoft.Extensions.Options;
4 | using Weikio.PluginFramework.Abstractions;
5 |
6 | namespace Weikio.PluginFramework.Configuration.Providers
7 | {
8 | ///
9 | /// Implementation of that
10 | /// loads a list of objects from the object.
11 | ///
12 | public class PluginCatalogConfigurationLoader : IPluginCatalogConfigurationLoader
13 | {
14 | private PluginFrameworkOptions _options;
15 |
16 | ///
17 | public virtual string CatalogsKey => "Catalogs";
18 |
19 | public PluginCatalogConfigurationLoader(IOptions options)
20 | {
21 | _options = options.Value;
22 | }
23 |
24 | ///
25 | public List GetCatalogConfigurations(IConfiguration configuration)
26 | {
27 | var catalogs = new List();
28 |
29 | configuration.Bind($"{_options.ConfigurationSection}:{CatalogsKey}", catalogs);
30 |
31 | return catalogs;
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/tests/integration/WebSites/PluginFrameworkTestBed/Controllers/WeatherForecastController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Mvc;
6 | using Microsoft.Extensions.Logging;
7 |
8 | namespace PluginFrameworkTestBed.Controllers
9 | {
10 | [ApiController]
11 | [Route("[controller]")]
12 | public class WeatherForecastController : ControllerBase
13 | {
14 | private static readonly string[] Summaries = new[]
15 | {
16 | "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
17 | };
18 |
19 | private readonly ILogger _logger;
20 |
21 | public WeatherForecastController(ILogger logger)
22 | {
23 | _logger = logger;
24 | }
25 |
26 | [HttpGet]
27 | public IEnumerable Get()
28 | {
29 | var rng = new Random();
30 |
31 | return Enumerable.Range(1, 5).Select(index => new WeatherForecast
32 | {
33 | Date = DateTime.Now.AddDays(index), TemperatureC = rng.Next(-20, 55), Summary = Summaries[rng.Next(Summaries.Length)]
34 | })
35 | .ToArray();
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/samples/WebAppWithAppSettings/Startup.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Builder;
2 | using Microsoft.AspNetCore.Hosting;
3 | using Microsoft.Extensions.DependencyInjection;
4 | using Microsoft.Extensions.Hosting;
5 | using Weikio.PluginFramework.Samples.Shared;
6 | using Weikio.PluginFramework.TypeFinding;
7 |
8 | namespace WebAppWithAppSettings
9 | {
10 | public class Startup
11 | {
12 | public void ConfigureServices(IServiceCollection services)
13 | {
14 | TypeFinderOptions.Defaults.TypeFinderCriterias.Add(TypeFinderCriteriaBuilder.Create().Implements().Tag("MathOperator"));
15 | TypeFinderOptions.Defaults.TypeFinderCriterias.Add(TypeFinderCriteriaBuilder.Create().Tag("All"));
16 | services.AddPluginFramework();
17 |
18 | services.AddControllers();
19 | }
20 |
21 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
22 | {
23 | if (env.IsDevelopment())
24 | {
25 | app.UseDeveloperExceptionPage();
26 | }
27 |
28 | app.UseHttpsRedirection();
29 |
30 | app.UseRouting();
31 |
32 | app.UseAuthorization();
33 |
34 | app.UseEndpoints(endpoints =>
35 | {
36 | endpoints.MapControllers();
37 | });
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework/Context/MetadataTypeFindingContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Reflection;
4 | using Weikio.PluginFramework.TypeFinding;
5 |
6 | namespace Weikio.PluginFramework.Context
7 | {
8 | public class MetadataTypeFindingContext : ITypeFindingContext
9 | {
10 | private readonly MetadataLoadContext _metadataLoadContext;
11 |
12 | public MetadataTypeFindingContext(MetadataLoadContext metadataLoadContext)
13 | {
14 | _metadataLoadContext = metadataLoadContext;
15 | }
16 |
17 | public Assembly FindAssembly(string assemblyName)
18 | {
19 | var result = _metadataLoadContext.LoadFromAssemblyName(assemblyName);
20 |
21 | return result;
22 | }
23 |
24 | public Type FindType(Type type)
25 | {
26 | var assemblyName = type.Assembly.GetName();
27 | var assemblies = _metadataLoadContext.GetAssemblies();
28 |
29 | var assembly = assemblies.FirstOrDefault(x => string.Equals(x.FullName, assemblyName.FullName));
30 |
31 | if (assembly == null)
32 | {
33 | assembly = _metadataLoadContext.LoadFromAssemblyName(assemblyName);
34 | }
35 |
36 | var result = assembly.GetType(type.FullName);
37 |
38 | return result;
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework.Configuration/Weikio.PluginFramework.Configuration.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1;net6.0
5 | enable
6 | true
7 | true
8 | IConfiguration support for Plugin Framework.
9 | IConfiguration support for Plugin Framework.
10 | Weikio.PluginFramework.Configuration
11 | Weikio.PluginFramework.Configuration
12 | Weikio.PluginFramework.Configuration
13 | plugins;addons;aspnetextensions;plugin framework;configuration
14 | logo_transparent_color_256.png
15 | IConfiguration support for Plugin Framework
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework/Catalogs/AssemblyPluginCatalogOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Weikio.PluginFramework.Abstractions;
4 | using Weikio.PluginFramework.Context;
5 | using Weikio.PluginFramework.TypeFinding;
6 |
7 | namespace Weikio.PluginFramework.Catalogs
8 | {
9 | public class AssemblyPluginCatalogOptions
10 | {
11 | ///
12 | /// Gets or sets the .
13 | ///
14 | public PluginLoadContextOptions PluginLoadContextOptions = new PluginLoadContextOptions();
15 |
16 | [Obsolete("Please use TypeFinderOptions. This will be removed in a future release.")]
17 | public Dictionary TypeFinderCriterias = new Dictionary();
18 |
19 | ///
20 | /// Gets or sets how the plugin names and version should be defined. .
21 | ///
22 | public PluginNameOptions PluginNameOptions { get; set; } = Defaults.PluginNameOptions;
23 |
24 | ///
25 | /// Gets or sets the .
26 | ///
27 | public TypeFinderOptions TypeFinderOptions { get; set; } = new TypeFinderOptions();
28 |
29 | public static class Defaults
30 | {
31 | public static PluginNameOptions PluginNameOptions { get; set; } = new PluginNameOptions();
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework/Catalogs/TypePluginCatalogOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Weikio.PluginFramework.Abstractions;
4 | using Weikio.PluginFramework.TypeFinding;
5 |
6 | namespace Weikio.PluginFramework.Catalogs
7 | {
8 | ///
9 | /// Options for configuring how the works.
10 | ///
11 | public class TypePluginCatalogOptions
12 | {
13 | ///
14 | /// Gets or sets how the plugin names and version should be defined. .
15 | ///
16 | public PluginNameOptions PluginNameOptions { get; set; } = Defaults.PluginNameOptions;
17 |
18 | [Obsolete("Please use TypeFinderOptions. This will be removed in a future release.")]
19 | public Dictionary TypeFinderCriterias = new Dictionary();
20 |
21 | ///
22 | /// Gets or sets the .
23 | ///
24 | public TypeFinderOptions TypeFinderOptions { get; set; } = new TypeFinderOptions();
25 |
26 | ///
27 | /// Gets or sets the .
28 | ///
29 | public ITypeFindingContext TypeFindingContext { get; set; } = null;
30 |
31 | public static class Defaults
32 | {
33 | public static PluginNameOptions PluginNameOptions { get; set; } = new PluginNameOptions();
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/samples/WebAppWithRoslyn/Controllers/RoslynController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore.Mvc;
7 | using Microsoft.Extensions.DependencyInjection;
8 | using Weikio.PluginFramework.Abstractions;
9 |
10 | namespace WebAppWithRoslyn.Controllers
11 | {
12 | [ApiController]
13 | [Route("[controller]")]
14 | public class RoslynController : ControllerBase
15 | {
16 | private readonly IPluginCatalog _pluginCatalog;
17 | private readonly IServiceProvider _sp;
18 |
19 | public RoslynController(IPluginCatalog pluginCatalog, IServiceProvider sp)
20 | {
21 | _pluginCatalog = pluginCatalog;
22 | _sp = sp;
23 | }
24 |
25 | [HttpGet]
26 | public async Task Get()
27 | {
28 | var scriptPlugin = _pluginCatalog.GetPlugins().First();
29 |
30 | dynamic scriptInstance = Activator.CreateInstance(scriptPlugin);
31 | var scriptResult = await scriptInstance.Run();
32 |
33 | var typePlugin = _pluginCatalog.Get("MyPlugin", Version.Parse("1.5.0.0"));
34 |
35 | dynamic typeInstance = typePlugin.Create(_sp);
36 |
37 | var typeResult = typeInstance.RunThings();
38 |
39 | var result = new StringBuilder();
40 | result.AppendLine(scriptResult);
41 | result.AppendLine(typeResult);
42 |
43 | return result.ToString();
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework.Catalogs.NuGet/Weikio.PluginFramework.Catalogs.NuGet.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1;net6.0
5 | true
6 | true
7 | NuGet catalog for Plugin Framework allows you to use NuGet packages as plugins with Plugin Framework.
8 | NuGet catalog for Plugin Framework allows you to use NuGet packages as plugins with Plugin Framework.
9 | Weikio.PluginFramework.Catalogs.NuGet
10 | Weikio.PluginFramework.Catalogs.NuGet
11 | Weikio.PluginFramework.Catalogs.NuGet
12 | nuget;plugins;addons;extensions;plugin framework
13 | logo_transparent_color_256.png
14 | NuGet Catalog for Plugin Framework
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/tests/integration/Weikio.PluginFramework.AspNetCore.IntegrationTests/Weikio.PluginFramework.AspNetCore.IntegrationTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | true
19 | PreserveNewest
20 | PreserveNewest
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/tests/integration/WebSites/PluginFrameworkTestBed/Startup.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Builder;
6 | using Microsoft.AspNetCore.Hosting;
7 | using Microsoft.AspNetCore.HttpsPolicy;
8 | using Microsoft.AspNetCore.Mvc;
9 | using Microsoft.Extensions.Configuration;
10 | using Microsoft.Extensions.DependencyInjection;
11 | using Microsoft.Extensions.Hosting;
12 | using Microsoft.Extensions.Logging;
13 |
14 | namespace PluginFrameworkTestBed
15 | {
16 | public class Startup
17 | {
18 | public Startup(IConfiguration configuration)
19 | {
20 | Configuration = configuration;
21 | }
22 |
23 | public IConfiguration Configuration { get; }
24 |
25 | // This method gets called by the runtime. Use this method to add services to the container.
26 | public void ConfigureServices(IServiceCollection services)
27 | {
28 | services.AddControllers();
29 | }
30 |
31 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
32 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
33 | {
34 | if (env.IsDevelopment())
35 | {
36 | app.UseDeveloperExceptionPage();
37 | }
38 |
39 | app.UseHttpsRedirection();
40 |
41 | app.UseRouting();
42 |
43 | app.UseAuthorization();
44 |
45 | app.UseEndpoints(endpoints =>
46 | {
47 | endpoints.MapControllers();
48 | });
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework.Abstractions/IPluginCatalogExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using System.Threading.Tasks;
4 |
5 | namespace Weikio.PluginFramework.Abstractions
6 | {
7 | public static class IPluginCatalogExtensions
8 | {
9 | ///
10 | /// Gets the only plugin inside the catalog. Throws if there is none or multiple.
11 | ///
12 | /// The catalog from which the plugin is retrieved.
13 | /// The plugin
14 | public static Plugin Single(this IPluginCatalog catalog)
15 | {
16 | var plugins = catalog.GetPlugins();
17 |
18 | return plugins.Single();
19 | }
20 |
21 | ///
22 | /// Gets the only plugin inside the catalog. Throws if there is none or multiple.
23 | ///
24 | /// The catalog from which the plugin is retrieved.
25 | /// The plugin
26 | public static Plugin Get(this IPluginCatalog catalog)
27 | {
28 | return catalog.Single();
29 | }
30 |
31 | ///
32 | /// Gets the plugins by tag.
33 | ///
34 | /// The catalog from which the plugin is retrieved.
35 | /// The tag.
36 | /// The plugin
37 | public static List GetByTag(this IPluginCatalog catalog, string tag)
38 | {
39 | return catalog.GetPlugins().Where(x => x.Tags.Contains(tag)).ToList();
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/tests/unit/Weikio.PluginFramework.Catalogs.Roslyn.Tests/TestHelpers.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reflection;
5 | using System.Runtime.CompilerServices;
6 | using System.Threading.Tasks;
7 | using Weikio.PluginFramework.Abstractions;
8 |
9 | namespace Weikio.PluginFramework.Catalogs.Roslyn.Tests
10 | {
11 | public static class TestHelpers
12 | {
13 | public static async Task> CompileScript(string code, RoslynPluginCatalogOptions options = null)
14 | {
15 | var catalog = new ScriptInitializer(code, options);
16 | var assembly = await catalog.CreateAssembly();
17 |
18 | var result = assembly.GetTypes().Where(x => x.GetCustomAttribute(typeof(CompilerGeneratedAttribute), true) == null).ToList();
19 |
20 | return result;
21 | }
22 |
23 | public static async Task> CompileRegular(string code, RoslynPluginCatalogOptions options = null)
24 | {
25 | var catalog = new RegularInitializer(code, options);
26 | var assembly = await catalog.CreateAssembly();
27 |
28 | var result = assembly.GetTypes().Where(x => x.GetCustomAttribute(typeof(CompilerGeneratedAttribute), true) == null).ToList();
29 |
30 | return result;
31 | }
32 |
33 | public static async Task> CreateCatalog(string code, RoslynPluginCatalogOptions options = null)
34 | {
35 | var catalog = new RoslynPluginCatalog(code, options);
36 | await catalog.Initialize();
37 |
38 | return catalog.GetPlugins().Select(x => x.Type).ToList();
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework.AspNetCore/Weikio.PluginFramework.AspNetCore.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1;net6.0
5 | true
6 | true
7 | Plugin Framework for ASP.NET Core.
8 | Plugin Framework for ASP.NET Core.
9 | Weikio.PluginFramework.AspNetCore
10 | Weikio.PluginFramework.AspNetCore
11 | Weikio.PluginFramework.AspNetCore
12 | plugins;addons;aspnetextensions;plugin framework
13 | logo_transparent_color_256.png
14 | Plugin Framework for ASP.NET Core
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework/Weikio.PluginFramework.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1;net6.0
5 | true
6 | true
7 | Plugin Framework is a powerful plugin platform for your .NET applications.
8 | Everything is a plugin! Use assemblies, NuGet packages and C# Scripts as plugins in your .NET Applications.
9 | Weikio.PluginFramework
10 | Weikio.PluginFramework
11 | Weikio.PluginFramework
12 | plugins;addons;extensions;plugin framework
13 | logo_transparent_color_256.png
14 | Plugin Framework
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework.Configuration/Converters/FolderCatalogConfigurationConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Microsoft.Extensions.Configuration;
4 | using Weikio.PluginFramework.Abstractions;
5 | using Weikio.PluginFramework.Catalogs;
6 |
7 | namespace Weikio.PluginFramework.Configuration.Converters
8 | {
9 | ///
10 | /// Converter implementation for the .
11 | ///
12 | public class FolderCatalogConfigurationConverter : IConfigurationToCatalogConverter
13 | {
14 | ///
15 | public bool CanConvert(string type)
16 | {
17 | return string.Equals(type, "Folder", StringComparison.InvariantCultureIgnoreCase);
18 | }
19 |
20 | ///
21 | public IPluginCatalog Convert(IConfigurationSection configuration)
22 | {
23 | var path = configuration.GetValue("Path")
24 | ?? throw new ArgumentException("Plugin Framework's FolderCatalog requires a Path.");
25 |
26 | var options = new CatalogFolderOptions();
27 | configuration.Bind($"Options", options);
28 |
29 | var folderOptions = new FolderPluginCatalogOptions();
30 |
31 | folderOptions.IncludeSubfolders = options.IncludeSubfolders ?? folderOptions.IncludeSubfolders;
32 | folderOptions.SearchPatterns = options.SearchPatterns ?? folderOptions.SearchPatterns;
33 |
34 | return new FolderPluginCatalog(path, folderOptions);
35 | }
36 |
37 | private class CatalogFolderOptions
38 | {
39 | public bool? IncludeSubfolders { get; set; }
40 |
41 | public List? SearchPatterns { get; set; }
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework.Catalogs.Roslyn/Weikio.PluginFramework.Catalogs.Roslyn.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1;net6.0
5 | true
6 | true
7 | Roslyn catalog for Plugin Framework allows you to use Roslyn scripts as plugins with Plugin Framework.
8 | Roslyn catalog for Plugin Framework allows you to use Roslyn scripts as plugins with Plugin Framework.
9 | Weikio.PluginFramework.Catalogs.Roslyn
10 | Weikio.PluginFramework.Catalogs.Roslyn
11 | Weikio.PluginFramework.Catalogs.Roslyn
12 | roslyn;plugins;addons;extensions;plugin framework
13 | logo_transparent_color_256.png
14 | Roslyn Catalog for Plugin Framework
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/samples/WebAppWithNuget/NugetLogger.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using Microsoft.Extensions.DependencyInjection;
3 | using Microsoft.Extensions.Logging;
4 | using NuGet.Common;
5 | using LogLevel = NuGet.Common.LogLevel;
6 |
7 | namespace WebAppWithNuget
8 | {
9 | public class NugetLogger : LoggerBase
10 | {
11 | private readonly ILogger _logger;
12 |
13 | public NugetLogger(IServiceCollection serviceCollection)
14 | {
15 | var provider = serviceCollection.BuildServiceProvider();
16 | _logger = (ILogger) provider.GetService(typeof(ILogger));
17 | }
18 |
19 | public override void Log(ILogMessage message)
20 | {
21 | switch (message.Level)
22 | {
23 | case LogLevel.Debug:
24 | _logger.LogDebug(message.ToString());
25 | break;
26 |
27 | case LogLevel.Verbose:
28 | _logger.LogTrace(message.ToString());
29 | break;
30 |
31 | case LogLevel.Information:
32 | _logger.LogInformation(message.ToString());
33 | break;
34 |
35 | case LogLevel.Minimal:
36 | _logger.LogTrace(message.ToString());
37 | break;
38 |
39 | case LogLevel.Warning:
40 | _logger.LogWarning(message.ToString());
41 | break;
42 |
43 | case LogLevel.Error:
44 | _logger.LogError(message.ToString());
45 | break;
46 | }
47 | }
48 |
49 | public override Task LogAsync(ILogMessage message)
50 | {
51 | Log(message);
52 |
53 | return Task.CompletedTask;
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/samples/WebAppWithDelegate/Controllers/DelegateController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore.Mvc;
7 | using Microsoft.Extensions.DependencyInjection;
8 | using Weikio.PluginFramework.Abstractions;
9 |
10 | namespace WebAppWithDelegate.Controllers
11 | {
12 | [ApiController]
13 | [Route("[controller]")]
14 | public class DelegateController : ControllerBase
15 | {
16 | private readonly IPluginCatalog _pluginCatalog;
17 | private readonly IServiceProvider _sp;
18 |
19 | public DelegateController(IPluginCatalog pluginCatalog, IServiceProvider serviceProvider)
20 | {
21 | _pluginCatalog = pluginCatalog;
22 | _sp = serviceProvider;
23 | }
24 |
25 | [HttpGet]
26 | public string Get()
27 | {
28 | var actionPlugin = _pluginCatalog.Get("MyActionPlugin", Version.Parse("1.0.0.0"));
29 | var funcPlugin = _pluginCatalog.Get("MyFuncPlugin", Version.Parse("1.0.0.0"));
30 | var funcExternalServicePlugin = _pluginCatalog.Get("MyExternalServicePlugin", Version.Parse("1.0.0.0"));
31 |
32 | dynamic action = _sp.Create(actionPlugin);
33 | dynamic func = _sp.Create(funcPlugin);
34 | dynamic external = _sp.Create(funcExternalServicePlugin);
35 |
36 | var s = new List() { "Hello from controller" };
37 | action.Run(s);
38 |
39 | var result = func.Run(s);
40 |
41 | // Conversion rules are used to convert the func's string parameter into a property and to convert the ExternalService into a constructor parameter.
42 | external.S = result;
43 | result = external.Run();
44 |
45 | return result;
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/samples/WpfApp/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.ObjectModel;
3 | using System.Windows;
4 | using Weikio.PluginFramework.Samples.Shared;
5 | using Weikio.PluginFramework.Abstractions;
6 | using Weikio.PluginFramework.Catalogs;
7 |
8 | namespace WpfApp
9 | {
10 | public partial class MainWindow : Window
11 | {
12 | private readonly ObservableCollection _plugins = new ObservableCollection();
13 |
14 | public MainWindow()
15 | {
16 | InitializeComponent();
17 | }
18 |
19 | private async void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
20 | {
21 | var folderPluginCatalog = new FolderPluginCatalog(@"..\..\..\..\Shared\Weikio.PluginFramework.Samples.SharedPlugins\bin\debug\netcoreapp3.1", type =>
22 | {
23 | type.Implements();
24 | });
25 |
26 | var assemblyPluginCatalog = new AssemblyPluginCatalog(typeof(MainWindow).Assembly, type => typeof(IOperator).IsAssignableFrom(type));
27 |
28 | var pluginCatalog = new CompositePluginCatalog(folderPluginCatalog, assemblyPluginCatalog);
29 | await pluginCatalog.Initialize();
30 |
31 | var allPlugins = pluginCatalog.GetPlugins();
32 |
33 | foreach (var plugin in allPlugins)
34 | {
35 | _plugins.Add(plugin);
36 | }
37 |
38 | PluginsList.ItemsSource = _plugins;
39 | }
40 |
41 | private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
42 | {
43 | if (PluginsList.SelectedItem == null)
44 | {
45 | return;
46 | }
47 |
48 | var selectedPlugin = (Plugin) PluginsList.SelectedItem;
49 |
50 | var instance = (IOperator) Activator.CreateInstance(selectedPlugin);
51 |
52 | var result = instance.Calculate(20, 10);
53 |
54 | PluginOutput.Text = result.ToString();
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/tests/unit/Weikio.PluginFramework.Tests/DefaultOptionsTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using Weikio.PluginFramework.Abstractions;
4 | using Weikio.PluginFramework.Catalogs;
5 | using Weikio.PluginFramework.Context;
6 | using Weikio.PluginFramework.TypeFinding;
7 | using Xunit;
8 |
9 | namespace Weikio.PluginFramework.Tests
10 | {
11 | public class DefaultOptionsTests
12 | {
13 | [Fact]
14 | public async Task CanConfigureDefaultOptions()
15 | {
16 | // Make sure that the referenced version of JSON.NET is loaded into memory
17 | var json = Newtonsoft.Json.JsonConvert.SerializeObject(1);
18 | PluginLoadContextOptions.Defaults.UseHostApplicationAssemblies = UseHostApplicationAssembliesEnum.Always;
19 |
20 | Action configureFinder = configure =>
21 | {
22 | configure.HasName("*JsonResolver");
23 | };
24 |
25 | var assemblyPluginCatalog = new AssemblyPluginCatalog(@"..\..\..\..\..\Assemblies\bin\JsonNew\netstandard2.0\JsonNetNew.dll", configureFinder);
26 | var folderPluginCatalog = new FolderPluginCatalog(@"..\..\..\..\..\Assemblies\bin\JsonOld\netstandard2.0", configureFinder);
27 |
28 | await assemblyPluginCatalog.Initialize();
29 | await folderPluginCatalog.Initialize();
30 |
31 | var newPlugin = assemblyPluginCatalog.Single();
32 | var oldPlugin = folderPluginCatalog.Single();
33 |
34 | dynamic newPluginJsonResolver = Activator.CreateInstance(newPlugin);
35 | var newPluginVersion = newPluginJsonResolver.GetVersion();
36 |
37 | dynamic oldPluginJsonResolver = Activator.CreateInstance(oldPlugin);
38 | var oldPluginVersion = oldPluginJsonResolver.GetVersion();
39 |
40 | Assert.Equal("12.0.0.0", newPluginVersion);
41 | Assert.Equal("12.0.0.0", oldPluginVersion);
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/samples/WebAppWithAppSettings/Controllers/CalculatorController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using Microsoft.AspNetCore.Mvc;
5 | using Microsoft.Extensions.DependencyInjection;
6 | using Weikio.PluginFramework.Abstractions;
7 | using Weikio.PluginFramework.AspNetCore;
8 | using Weikio.PluginFramework.Samples.Shared;
9 |
10 | namespace WebAppWithAppSettings.Controllers
11 | {
12 | [ApiController]
13 | [Route("[controller]")]
14 | public class CalculatorController : ControllerBase
15 | {
16 | private readonly IEnumerable _plugins;
17 | private readonly IServiceProvider _serviceProvider;
18 | private readonly PluginProvider _pluginProvider;
19 |
20 | public CalculatorController(IEnumerable plugins, IServiceProvider serviceProvider, PluginProvider pluginProvider)
21 | {
22 | _plugins = plugins;
23 | _serviceProvider = serviceProvider;
24 | _pluginProvider = pluginProvider;
25 | }
26 |
27 | [HttpGet]
28 | public string Get()
29 | {
30 | var result = new StringBuilder();
31 |
32 | result.AppendLine("All:");
33 | foreach (var plugin in _plugins)
34 | {
35 | result.AppendLine($"{plugin.Name}: {plugin.Version}, Tags: {string.Join(", ", plugin.Tags)}");
36 | }
37 |
38 | var mathPlugins = _pluginProvider.GetByTag("MathOperator");
39 | var value1 = 10;
40 | var value2 = 20;
41 |
42 | result.AppendLine($"Math operations with values {value1} and {value2}");
43 |
44 | foreach (var mathPlugin in mathPlugins)
45 | {
46 | var mathPluginInstance = _serviceProvider.Create(mathPlugin);
47 |
48 | var mathResult = mathPluginInstance.Calculate(value1, value2);
49 | result.AppendLine($"{mathPlugin.Name}: {mathResult}");
50 | }
51 |
52 | return result.ToString();
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/tests/integration/Weikio.PluginFramework.AspNetCore.IntegrationTests/TestBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.AspNetCore.Hosting;
3 | using Microsoft.AspNetCore.Mvc.Testing;
4 | using Microsoft.Extensions.DependencyInjection;
5 | using Microsoft.Extensions.Logging;
6 | using PluginFrameworkTestBed;
7 | using Weikio.PluginFramework.Catalogs;
8 | using Weikio.PluginFramework.Samples.Shared;
9 | using Xunit;
10 | using Xunit.Abstractions;
11 |
12 | namespace Weikio.PluginFramework.AspNetCore.IntegrationTests
13 | {
14 | public class TestBase : IClassFixture>
15 | {
16 | private readonly WebApplicationFactory _factory;
17 | public ITestOutputHelper Output { get; set; }
18 |
19 | protected TestBase(WebApplicationFactory factory, ITestOutputHelper output)
20 | {
21 | Output = output;
22 | _factory = factory;
23 | }
24 |
25 | protected IServiceProvider Init(Action action = null)
26 | {
27 | var folderPluginCatalog = new FolderPluginCatalog(@"..\..\..\..\..\..\Samples\Shared\Weikio.PluginFramework.Samples.SharedPlugins\bin\debug\netcoreapp3.1", type =>
28 | {
29 | type.Implements();
30 | });
31 |
32 | var server = _factory.WithWebHostBuilder(builder =>
33 | {
34 | builder.ConfigureServices(services =>
35 | {
36 | services.AddPluginFramework()
37 | .AddPluginCatalog(folderPluginCatalog);
38 |
39 | action?.Invoke(services);
40 | });
41 |
42 | builder.ConfigureLogging(logging =>
43 | {
44 | logging.ClearProviders(); // Remove other loggers
45 | XUnitLoggerExtensions.AddXUnit((ILoggingBuilder) logging, Output); // Use the ITestOutputHelper instance
46 | });
47 |
48 | });
49 |
50 | return server.Services;
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework.Catalogs.Roslyn/RoslynPluginCatalogOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Reflection;
4 | using Weikio.PluginFramework.Abstractions;
5 |
6 | namespace Weikio.PluginFramework.Catalogs.Roslyn
7 | {
8 | public class RoslynPluginCatalogOptions
9 | {
10 | private string _pluginName = "RoslynCode";
11 | private Version _pluginVersion = new Version(1, 0, 0);
12 |
13 | public string PluginName
14 | {
15 | get => _pluginName;
16 | set
17 | {
18 | _pluginName = value;
19 |
20 | PluginNameOptions.PluginNameGenerator = (options, type) => _pluginName;
21 | }
22 | }
23 |
24 | public Version PluginVersion
25 | {
26 | get => _pluginVersion;
27 | set
28 | {
29 | _pluginVersion = value;
30 |
31 | PluginNameOptions.PluginVersionGenerator = (options, type) => _pluginVersion;
32 | }
33 | }
34 |
35 | public string TypeName { get; set; } = "GeneratedType";
36 | public string NamespaceName { get; set; } = "GeneratedNamespace";
37 | public string MethodName { get; set; } = "Run";
38 | public bool ReturnsTask { get; set; } = true;
39 | public Func TypeNameGenerator { get; set; } = options => options.TypeName;
40 | public Func NamespaceNameGenerator { get; set; } = options => options.NamespaceName;
41 | public Func MethodNameGenerator { get; set; } = options => options.MethodName;
42 | public List AdditionalReferences { get; set; } = new List();
43 | public List AdditionalNamespaces { get; set; } = new List();
44 | public PluginNameOptions PluginNameOptions { get; set; } = new PluginNameOptions();
45 |
46 | ///
47 | /// Gets or sets the tags assigned to plugin
48 | ///
49 | public List Tags { get; set; } = new List();
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework/Catalogs/CompositePluginCatalog.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Weikio.PluginFramework.Abstractions;
6 |
7 | namespace Weikio.PluginFramework.Catalogs
8 | {
9 | ///
10 | /// Composite Plugin Catalog combines 1-n other Plugin Catalogs.
11 | ///
12 | public class CompositePluginCatalog : IPluginCatalog
13 | {
14 | private readonly List _catalogs;
15 |
16 | ///
17 | public bool IsInitialized { get; private set; }
18 |
19 | ///
20 | public List GetPlugins()
21 | {
22 | var result = new List();
23 |
24 | foreach (var pluginCatalog in _catalogs)
25 | {
26 | var pluginsInCatalog = pluginCatalog.GetPlugins();
27 | result.AddRange(pluginsInCatalog);
28 | }
29 |
30 | return result;
31 | }
32 |
33 | ///
34 | public Plugin Get(string name, Version version)
35 | {
36 | foreach (var pluginCatalog in _catalogs)
37 | {
38 | var plugin = pluginCatalog.Get(name, version);
39 |
40 | if (plugin == null)
41 | {
42 | continue;
43 | }
44 |
45 | return plugin;
46 | }
47 |
48 | return null;
49 | }
50 |
51 | public CompositePluginCatalog(params IPluginCatalog[] catalogs)
52 | {
53 | _catalogs = catalogs.ToList();
54 | }
55 |
56 | public void AddCatalog(IPluginCatalog catalog)
57 | {
58 | _catalogs.Add(catalog);
59 | }
60 |
61 | ///
62 | public async Task Initialize()
63 | {
64 | if (_catalogs?.Any() != true)
65 | {
66 | IsInitialized = true;
67 |
68 | return;
69 | }
70 |
71 | foreach (var pluginCatalog in _catalogs)
72 | {
73 | await pluginCatalog.Initialize();
74 | }
75 |
76 | IsInitialized = true;
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/samples/BlazorApp/Startup.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reflection;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore.Builder;
7 | using Microsoft.AspNetCore.Components;
8 | using Microsoft.AspNetCore.Hosting;
9 | using Microsoft.AspNetCore.HttpsPolicy;
10 | using Microsoft.Extensions.Configuration;
11 | using Microsoft.Extensions.DependencyInjection;
12 | using Microsoft.Extensions.Hosting;
13 | using BlazorApp.Data;
14 | using Microsoft.CodeAnalysis;
15 | using Weikio.PluginFramework.Samples.Shared;
16 |
17 | namespace BlazorApp
18 | {
19 | public class Startup
20 | {
21 | public Startup(IConfiguration configuration)
22 | {
23 | Configuration = configuration;
24 | }
25 |
26 | public IConfiguration Configuration { get; }
27 |
28 | // This method gets called by the runtime. Use this method to add services to the container.
29 | // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
30 | public void ConfigureServices(IServiceCollection services)
31 | {
32 | services.AddRazorPages();
33 | services.AddServerSideBlazor();
34 | services.AddSingleton();
35 |
36 | services.AddPluginFramework();
37 | }
38 |
39 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
40 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
41 | {
42 | if (env.IsDevelopment())
43 | {
44 | app.UseDeveloperExceptionPage();
45 | }
46 | else
47 | {
48 | app.UseExceptionHandler("/Error");
49 |
50 | // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
51 | app.UseHsts();
52 | }
53 |
54 | app.UseHttpsRedirection();
55 | app.UseStaticFiles();
56 |
57 | app.UseRouting();
58 |
59 | app.UseEndpoints(endpoints =>
60 | {
61 | endpoints.MapBlazorHub();
62 | endpoints.MapFallbackToPage("/_Host");
63 | });
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/samples/WinFormsPluginsLibrary/TestPlugin.Designer.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 |
3 | namespace WinFormsPluginsLibrary
4 | {
5 | partial class TestPlugin
6 | {
7 | ///
8 | /// Required designer variable.
9 | ///
10 | private IContainer components = null;
11 |
12 | ///
13 | /// Clean up any resources being used.
14 | ///
15 | /// true if managed resources should be disposed; otherwise, false.
16 | protected override void Dispose(bool disposing)
17 | {
18 | if (disposing && (components != null))
19 | {
20 | components.Dispose();
21 | }
22 |
23 | base.Dispose(disposing);
24 | }
25 |
26 | #region Windows Form Designer generated code
27 |
28 | ///
29 | /// Required method for Designer support - do not modify
30 | /// the contents of this method with the code editor.
31 | ///
32 | private void InitializeComponent()
33 | {
34 | this.button1 = new System.Windows.Forms.Button();
35 | this.SuspendLayout();
36 |
37 | //
38 | // button1
39 | //
40 | this.button1.Location = new System.Drawing.Point(118, 86);
41 | this.button1.Name = "button1";
42 | this.button1.Size = new System.Drawing.Size(202, 42);
43 | this.button1.TabIndex = 0;
44 | this.button1.Text = "Say Hello";
45 | this.button1.UseVisualStyleBackColor = true;
46 | this.button1.Click += new System.EventHandler(this.button1_Click);
47 |
48 | //
49 | // TestPlugin
50 | //
51 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
52 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
53 | this.ClientSize = new System.Drawing.Size(433, 233);
54 | this.Controls.Add(this.button1);
55 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
56 | this.Name = "TestPlugin";
57 | this.Text = "TestPlugin";
58 | this.ResumeLayout(false);
59 | }
60 |
61 | private System.Windows.Forms.Button button1;
62 |
63 | #endregion
64 | }
65 | }
66 |
67 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework.Catalogs.NuGet/NugetFeedPluginCatalogOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using NuGet.Common;
3 | using Weikio.NugetDownloader;
4 | using Weikio.PluginFramework.Abstractions;
5 | using Weikio.PluginFramework.Catalogs.NuGet;
6 | using Weikio.PluginFramework.TypeFinding;
7 |
8 | namespace Weikio.PluginFramework.Catalogs.NuGet
9 | {
10 | public class NugetFeedPluginCatalogOptions
11 | {
12 | ///
13 | /// Gets or sets the function which is used to create the logger for Nuget activities
14 | ///
15 | public Func LoggerFactory { get; set; } = Defaults.LoggerFactory;
16 |
17 | ///
18 | /// Gets or sets the .
19 | ///
20 | public TypeFinderOptions TypeFinderOptions { get; set; } = new TypeFinderOptions();
21 |
22 | ///
23 | /// Gets or sets how the plugin names and version should be defined. .
24 | ///
25 | public PluginNameOptions PluginNameOptions { get; set; } = Defaults.PluginNameOptions;
26 |
27 | ///
28 | /// Gets or sets if Plugin Framework should take care of package caching. In some cases Nuget will download already downloaded package. This flag
29 | /// tries to make sure that the package is downloaded only once. Note: Requires that PackagesFolder is set
30 | ///
31 | public bool ForcePackageCaching { get; set; } = false;
32 |
33 | ///
34 | /// Gets or sets if Plugin Framework should try to retry package download if it fails for the first time. If true and the download fails,
35 | /// Plugin Framework will clear the Nuget cache and then tries again.
36 | ///
37 | public bool AutoRetryPackageDownload { get; set; } = false;
38 |
39 | public static class Defaults
40 | {
41 | ///
42 | /// Gets or sets the default function which is used to create the logger for PluginLoadContextOptions
43 | ///
44 | public static Func LoggerFactory { get; set; } = () => new ConsoleLogger();
45 |
46 | public static PluginNameOptions PluginNameOptions { get; set; } = new PluginNameOptions();
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/tests/integration/Weikio.PluginFramework.AspNetCore.IntegrationTests/DefaultPluginTypeTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using Microsoft.AspNetCore.Mvc.Testing;
4 | using Microsoft.Extensions.DependencyInjection;
5 | using PluginFrameworkTestBed;
6 | using Weikio.PluginFramework.Samples.Shared;
7 | using Weikio.PluginFramework.Samples.SharedPlugins;
8 | using Xunit;
9 | using Xunit.Abstractions;
10 |
11 | namespace Weikio.PluginFramework.AspNetCore.IntegrationTests
12 | {
13 | public class DefaultPluginTypeTests : TestBase
14 | {
15 | public DefaultPluginTypeTests(WebApplicationFactory factory, ITestOutputHelper output) : base(factory, output)
16 | {
17 | }
18 |
19 | [Fact]
20 | public void DefaultsToFirstPluginType()
21 | {
22 | var sp = Init(services =>
23 | {
24 | services.AddPluginType();
25 | });
26 |
27 | var operators = sp.GetRequiredService>();
28 | var defaultOperator = sp.GetRequiredService();
29 |
30 | Assert.Equal(operators.First().GetType(), defaultOperator.GetType());
31 | }
32 |
33 | [Fact]
34 | public void CanConfigureUsingAction()
35 | {
36 | var sp = Init(services =>
37 | {
38 | services.AddPluginType(configureDefault: option =>
39 | {
40 | option.DefaultType = (provider, types) => typeof(SumOperator);
41 | });
42 | });
43 |
44 | var defaultOperator = sp.GetRequiredService();
45 |
46 | Assert.Equal(typeof(SumOperator), defaultOperator.GetType());
47 | }
48 |
49 | [Fact]
50 | public void CanConfigureUsingOptions()
51 | {
52 | var sp = Init(services =>
53 | {
54 | services.AddPluginType();
55 |
56 | services.Configure(nameof(IOperator), option =>
57 | option.DefaultType = (serviceProvider, implementingTypes) => typeof(MultiplyOperator));
58 | });
59 |
60 | var defaultOperator = sp.GetRequiredService();
61 |
62 | Assert.Equal(typeof(MultiplyOperator), defaultOperator.GetType());
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework.AspNetCore/PluginProvider.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using Microsoft.Extensions.DependencyInjection;
5 | using Weikio.PluginFramework.Abstractions;
6 |
7 | namespace Weikio.PluginFramework.AspNetCore
8 | {
9 | public class PluginProvider
10 | {
11 | private readonly IEnumerable _catalogs;
12 | private readonly IServiceProvider _serviceProvider;
13 |
14 | public PluginProvider(IEnumerable catalogs, IServiceProvider serviceProvider)
15 | {
16 | _catalogs = catalogs;
17 | _serviceProvider = serviceProvider;
18 | }
19 |
20 | public List GetByTag(string tag)
21 | {
22 | var result = new List();
23 |
24 | foreach (var pluginCatalog in _catalogs)
25 | {
26 | var pluginsByTag = pluginCatalog.GetByTag(tag);
27 | result.AddRange(pluginsByTag);
28 | }
29 |
30 | return result;
31 | }
32 |
33 | public List GetPlugins()
34 | {
35 | var result = new List();
36 | foreach (var pluginCatalog in _catalogs)
37 | {
38 | result.AddRange(pluginCatalog.GetPlugins());
39 | }
40 |
41 | return result;
42 | }
43 |
44 | public Plugin Get(string name, Version version)
45 | {
46 | foreach (var pluginCatalog in _catalogs)
47 | {
48 | var result = pluginCatalog.Get(name, version);
49 |
50 | if (result != null)
51 | {
52 | return result;
53 | }
54 | }
55 |
56 | return null;
57 | }
58 |
59 | public List GetTypes() where T : class
60 | {
61 | var result = new List();
62 | var catalogs = _serviceProvider.GetServices();
63 |
64 | foreach (var catalog in catalogs)
65 | {
66 | var plugins = catalog.GetPlugins();
67 |
68 | foreach (var plugin in plugins.Where(x => typeof(T).IsAssignableFrom(x)))
69 | {
70 | var op = plugin.Create(_serviceProvider);
71 |
72 | result.Add(op);
73 | }
74 | }
75 |
76 | return result;
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework/Catalogs/FolderPluginCatalogOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Weikio.PluginFramework.Abstractions;
4 | using Weikio.PluginFramework.Context;
5 | using Weikio.PluginFramework.TypeFinding;
6 |
7 | namespace Weikio.PluginFramework.Catalogs
8 | {
9 | ///
10 | /// Options for configuring how the works.
11 | ///
12 | public class FolderPluginCatalogOptions
13 | {
14 | ///
15 | /// Gets or sets if subfolders should be included. Defaults to true.
16 | ///
17 | public bool IncludeSubfolders { get; set; } = true;
18 |
19 | ///
20 | /// Gets or sets the search patterns when locating plugins. By default only located dll-files.
21 | ///
22 | public List SearchPatterns { get; set; } = new List() { "*.dll" };
23 |
24 | ///
25 | /// Gets or sets the .
26 | ///
27 | public PluginLoadContextOptions PluginLoadContextOptions { get; set; } = new PluginLoadContextOptions();
28 |
29 | ///
30 | /// Gets or sets a single type finder criteria
31 | ///
32 | [Obsolete("Please use TypeFinderOptions. This will be removed in a future release.")]
33 | public TypeFinderCriteria TypeFinderCriteria { get; set; }
34 |
35 | ///
36 | /// Gets or sets a collection of type finder criteria. The key is used to "tag" found plugins.
37 | ///
38 | [Obsolete("Please use TypeFinderOptions. This will be removed in a future release.")]
39 | public Dictionary TypeFinderCriterias { get; set; } = new Dictionary();
40 |
41 | ///
42 | /// Gets or sets the .
43 | ///
44 | public TypeFinderOptions TypeFinderOptions { get; set; } = new TypeFinderOptions();
45 |
46 | ///
47 | /// Gets or sets how the plugin names and version should be defined.
48 | ///
49 | public PluginNameOptions PluginNameOptions { get; set; } = Defaults.PluginNameOptions;
50 |
51 | public static class Defaults
52 | {
53 | public static PluginNameOptions PluginNameOptions { get; set; } = new PluginNameOptions();
54 | }
55 |
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework.AspNetCore/PluginFrameworkInitializer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 | using Microsoft.Extensions.Hosting;
7 | using Microsoft.Extensions.Logging;
8 | using Weikio.PluginFramework.Abstractions;
9 |
10 | namespace Weikio.PluginFramework.AspNetCore
11 | {
12 | public class PluginFrameworkInitializer : IHostedService
13 | {
14 | private readonly IEnumerable _pluginCatalogs;
15 | private readonly ILogger _logger;
16 |
17 | public PluginFrameworkInitializer(IEnumerable pluginCatalogs, ILogger logger)
18 | {
19 | _pluginCatalogs = pluginCatalogs;
20 | _logger = logger;
21 | }
22 |
23 | public async Task StartAsync(CancellationToken cancellationToken)
24 | {
25 | try
26 | {
27 | _logger.LogInformation("Initializing {PluginCatalogCount} plugin catalogs", _pluginCatalogs.Count());
28 |
29 | foreach (var pluginCatalog in _pluginCatalogs)
30 | {
31 | try
32 | {
33 | _logger.LogDebug("Initializing {PluginCatalog}", pluginCatalog);
34 |
35 | await pluginCatalog.Initialize();
36 |
37 | _logger.LogDebug("Initialized {PluginCatalog}", pluginCatalog);
38 | _logger.LogTrace("Found the following plugins from {PluginCatalog}:", pluginCatalog);
39 |
40 | foreach (var plugin in pluginCatalog.GetPlugins())
41 | {
42 | _logger.LogTrace(plugin.ToString());
43 | }
44 | }
45 | catch (Exception e)
46 | {
47 | _logger.LogError(e, "Failed to initialize {PluginCatalog}", pluginCatalog);
48 | }
49 | }
50 |
51 | _logger.LogInformation("Initialized {PluginCatalogCount} plugin catalogs", _pluginCatalogs.Count());
52 | }
53 | catch (Exception e)
54 | {
55 | _logger.LogError(e, "Failed to initialize plugin catalogs");
56 |
57 | throw;
58 | }
59 | }
60 |
61 | public Task StopAsync(CancellationToken cancellationToken)
62 | {
63 | return Task.CompletedTask;
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/samples/WebAppWithNuget/Startup.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore.Builder;
7 | using Microsoft.AspNetCore.Hosting;
8 | using Microsoft.AspNetCore.HttpsPolicy;
9 | using Microsoft.AspNetCore.Mvc;
10 | using Microsoft.Extensions.Configuration;
11 | using Microsoft.Extensions.DependencyInjection;
12 | using Microsoft.Extensions.Hosting;
13 | using Microsoft.Extensions.Logging;
14 | using Weikio.PluginFramework.Catalogs;
15 | using Weikio.PluginFramework.Catalogs.NuGet;
16 | using Weikio.PluginFramework.Samples.Shared;
17 |
18 | namespace WebAppWithNuget
19 | {
20 | public class Startup
21 | {
22 | public Startup(IConfiguration configuration)
23 | {
24 | Configuration = configuration;
25 | }
26 |
27 | public IConfiguration Configuration { get; }
28 |
29 | // This method gets called by the runtime. Use this method to add services to the container.
30 | public void ConfigureServices(IServiceCollection services)
31 | {
32 | NugetPluginCatalogOptions.Defaults.LoggerFactory = () => new NugetLogger(services);
33 |
34 | var options = new NugetPluginCatalogOptions
35 | {
36 | ForcePackageCaching = true,
37 | CustomPackagesFolder = Path.Combine(Path.GetTempPath(), "NugetPackagePluginCatalog", "Sample")
38 | };
39 |
40 | var nugetCatalog = new NugetPackagePluginCatalog("Weikio.PluginFramework.Samples.SharedPlugins", includePrerelease: true, configureFinder: finder =>
41 | {
42 | finder.Implements();
43 | }, options: options);
44 |
45 | services.AddPluginFramework()
46 | .AddPluginCatalog(nugetCatalog)
47 | .AddPluginType();
48 |
49 | services.AddControllers();
50 | }
51 |
52 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
53 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
54 | {
55 | if (env.IsDevelopment())
56 | {
57 | app.UseDeveloperExceptionPage();
58 | }
59 |
60 | app.UseHttpsRedirection();
61 |
62 | app.UseRouting();
63 |
64 | app.UseAuthorization();
65 |
66 | app.UseEndpoints(endpoints =>
67 | {
68 | endpoints.MapControllers();
69 | });
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework.Catalogs.Roslyn/RegularInitializer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Reflection;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Weikio.TypeGenerator;
7 |
8 | namespace Weikio.PluginFramework.Catalogs.Roslyn
9 | {
10 | ///
11 | /// Initializer which can handle regular C#
12 | ///
13 | public class RegularInitializer
14 | {
15 | private readonly string _code;
16 | private readonly RoslynPluginCatalogOptions _options;
17 |
18 | public RegularInitializer(string code, RoslynPluginCatalogOptions options)
19 | {
20 | if (string.IsNullOrWhiteSpace(code))
21 | {
22 | throw new ArgumentOutOfRangeException(nameof(code), code, "Script can not be null or empty");
23 | }
24 |
25 | _code = code;
26 | _options = options ?? new RoslynPluginCatalogOptions();
27 | }
28 |
29 | public Task CreateAssembly()
30 | {
31 | try
32 | {
33 | var generator = new CodeToAssemblyGenerator();
34 | generator.ReferenceAssemblyContainingType();
35 |
36 | if (_options.AdditionalReferences?.Any() == true)
37 | {
38 | foreach (var assembly in _options.AdditionalReferences)
39 | {
40 | generator.ReferenceAssembly(assembly);
41 | }
42 | }
43 |
44 | var code = new StringBuilder();
45 | code.AppendLine("using System;");
46 | code.AppendLine("using System.Diagnostics;");
47 | code.AppendLine("using System.Threading.Tasks;");
48 | code.AppendLine("using System.Text;");
49 | code.AppendLine("using System.Collections;");
50 | code.AppendLine("using System.Collections.Generic;");
51 |
52 | if (_options.AdditionalNamespaces?.Any() == true)
53 | {
54 | foreach (var ns in _options.AdditionalNamespaces)
55 | {
56 | code.AppendLine($"using {ns};");
57 | }
58 | }
59 |
60 | code.AppendLine(_code);
61 | var assemblySourceCode = code.ToString();
62 |
63 | var result = generator.GenerateAssembly(assemblySourceCode);
64 |
65 | return Task.FromResult(result);
66 | }
67 | catch (Exception e)
68 | {
69 | throw new InvalidCodeException("Failed to create assembly from regular code. Code: " + _code, e);
70 | }
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/samples/WinFormsPluginsLibrary/LabelPlugin.Designer.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using System.Drawing;
3 |
4 | namespace WinFormsPluginsLibrary
5 | {
6 | partial class LabelPlugin
7 | {
8 | ///
9 | /// Required designer variable.
10 | ///
11 | private IContainer components = null;
12 |
13 | ///
14 | /// Clean up any resources being used.
15 | ///
16 | /// true if managed resources should be disposed; otherwise, false.
17 | protected override void Dispose(bool disposing)
18 | {
19 | if (disposing && (components != null))
20 | {
21 | components.Dispose();
22 | }
23 |
24 | base.Dispose(disposing);
25 | }
26 |
27 | #region Windows Form Designer generated code
28 |
29 | ///
30 | /// Required method for Designer support - do not modify
31 | /// the contents of this method with the code editor.
32 | ///
33 | private void InitializeComponent()
34 | {
35 | this.button1 = new System.Windows.Forms.Button();
36 | this.label1 = new System.Windows.Forms.Label();
37 | this.SuspendLayout();
38 |
39 | //
40 | // button1
41 | //
42 | this.button1.Location = new System.Drawing.Point(105, 12);
43 | this.button1.Name = "button1";
44 | this.button1.Size = new System.Drawing.Size(110, 50);
45 | this.button1.TabIndex = 0;
46 | this.button1.Text = "Update Label";
47 | this.button1.UseVisualStyleBackColor = true;
48 | this.button1.Click += new System.EventHandler(this.button1_Click);
49 |
50 | //
51 | // label1
52 | //
53 | this.label1.Location = new System.Drawing.Point(90, 88);
54 | this.label1.Name = "label1";
55 | this.label1.Size = new System.Drawing.Size(125, 36);
56 | this.label1.TabIndex = 1;
57 |
58 | //
59 | // LabelPlugin
60 | //
61 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
62 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
63 | this.ClientSize = new System.Drawing.Size(313, 184);
64 | this.Controls.Add(this.label1);
65 | this.Controls.Add(this.button1);
66 | this.Name = "LabelPlugin";
67 | this.Text = "LabelPlugin";
68 | this.ResumeLayout(false);
69 | }
70 |
71 | private System.Windows.Forms.Label label1;
72 |
73 | private System.Windows.Forms.Button button1;
74 |
75 | #endregion
76 | }
77 | }
78 |
79 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework.Abstractions/Plugin.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reflection;
5 |
6 | namespace Weikio.PluginFramework.Abstractions
7 | {
8 | ///
9 | /// Represents a single Plugin. Each plugin has a name, version and .NET Type.
10 | ///
11 | public class Plugin
12 | {
13 | ///
14 | /// Gets the name of the plugin
15 | ///
16 | public string Name { get; }
17 |
18 | ///
19 | /// Gets the plugin version
20 | ///
21 | public Version Version { get; }
22 |
23 | ///
24 | /// Gets the .NET Type which is the plugin
25 | ///
26 | public Type Type { get; }
27 |
28 | ///
29 | /// Gets the plugin type's assembly
30 | ///
31 | public Assembly Assembly { get; }
32 |
33 | ///
34 | /// Gets the catalog which contains the plugins
35 | ///
36 | public IPluginCatalog Source { get; }
37 |
38 | ///
39 | /// Gets the description of the plugin
40 | ///
41 | public string Description { get; }
42 |
43 | ///
44 | /// Gets the description of the plugin
45 | ///
46 | public string ProductVersion { get; }
47 |
48 | ///
49 | /// Gets the tag of the plugin
50 | ///
51 | public string Tag
52 | {
53 | get
54 | {
55 | return Tags.FirstOrDefault();
56 | }
57 | }
58 |
59 | ///
60 | /// Gets the tags of the plugin
61 | ///
62 | public List Tags { get; }
63 |
64 | public Plugin(Assembly assembly, Type type, string name, Version version, IPluginCatalog source, string description = "", string productVersion = "",
65 | string tag = "", List tags = null)
66 | {
67 | Assembly = assembly;
68 | Type = type;
69 | Name = name;
70 | Version = version;
71 | Source = source;
72 | Description = description;
73 | ProductVersion = productVersion;
74 | Tags = tags;
75 |
76 | if (Tags == null)
77 | {
78 | Tags = new List();
79 | }
80 |
81 | if (!string.IsNullOrWhiteSpace(tag))
82 | {
83 | Tags.Add(tag);
84 | }
85 | }
86 |
87 | public static implicit operator Type(Plugin plugin)
88 | {
89 | return plugin.Type;
90 | }
91 |
92 | public override string ToString()
93 | {
94 | return $"{Name}: {Version}";
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/samples/WebApp/Startup.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Microsoft.AspNetCore.Builder;
3 | using Microsoft.AspNetCore.Hosting;
4 | using Microsoft.Extensions.Configuration;
5 | using Microsoft.Extensions.DependencyInjection;
6 | using Microsoft.Extensions.Hosting;
7 | using Weikio.PluginFramework.Samples.Shared;
8 | using Weikio.PluginFramework.Abstractions;
9 | using Weikio.PluginFramework.AspNetCore;
10 | using Weikio.PluginFramework.Catalogs;
11 | using Weikio.PluginFramework.Samples.SharedPlugins;
12 |
13 | namespace WebApp
14 | {
15 | public class Startup
16 | {
17 | public Startup(IConfiguration configuration)
18 | {
19 | Configuration = configuration;
20 | }
21 |
22 | public IConfiguration Configuration { get; }
23 |
24 | // This method gets called by the runtime. Use this method to add services to the container.
25 | public void ConfigureServices(IServiceCollection services)
26 | {
27 | var folderPluginCatalog = new FolderPluginCatalog(@"..\Shared\Weikio.PluginFramework.Samples.SharedPlugins\bin\debug\netcoreapp3.1", type =>
28 | {
29 | type.Implements();
30 | });
31 |
32 | services.AddPluginFramework()
33 | .AddPluginCatalog(folderPluginCatalog)
34 | .AddPluginType(configureDefault: option =>
35 | {
36 | option.DefaultType = (provider, types) => typeof(SumOperator);
37 | });
38 |
39 | // Alternatively
40 | // services.AddPluginFramework(@"..\Shared\Weikio.PluginFramework.Samples.SharedPlugins\bin\debug\netcoreapp3.1");
41 |
42 | // Default plugin type returned can be optionally configured with DefaultType function
43 | //services.AddPluginFramework()
44 | // .AddPluginCatalog(folderPluginCatalog)
45 | // .AddPluginType(configureDefault: option =>
46 | // {
47 | // option.DefaultType = (serviceProvider, implementingTypes) => typeof(MultiplyOperator);
48 | // });
49 |
50 | // Alternatively default plugin type can be also configured with Configure and provided with the same DefaultType function
51 | //services.Configure(nameof(IOperator), option =>
52 | // option.DefaultType = (serviceProvider, implementingTypes) => typeof(MultiplyOperator));
53 |
54 | services.AddControllers();
55 | }
56 |
57 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
58 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
59 | {
60 | if (env.IsDevelopment())
61 | {
62 | app.UseDeveloperExceptionPage();
63 | }
64 |
65 | app.UseHttpsRedirection();
66 |
67 | app.UseRouting();
68 |
69 | app.UseAuthorization();
70 |
71 | app.UseEndpoints(endpoints =>
72 | {
73 | endpoints.MapControllers();
74 | });
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/samples/ConsoleApp/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using Weikio.PluginFramework.Samples.Shared;
4 | using Weikio.PluginFramework.Abstractions;
5 | using Weikio.PluginFramework.Catalogs;
6 |
7 | namespace ConsoleApp
8 | {
9 | class Program
10 | {
11 | static async Task Main(string[] args)
12 | {
13 | await AssemblyCatalogSample();
14 | await TypeCatalogSample();
15 | await CompositeCatalogSample();
16 | }
17 |
18 | private static async Task AssemblyCatalogSample()
19 | {
20 | Console.WriteLine("Assembly catalog sample");
21 |
22 | // 1. Create a new plugin catalog from the current assembly
23 | var assemblyPluginCatalog = new AssemblyPluginCatalog(typeof(Program).Assembly, type => typeof(IPlugin).IsAssignableFrom(type));
24 |
25 | // 2. Initialize the catalog
26 | await assemblyPluginCatalog.Initialize();
27 |
28 | // 3. Get the plugins from the catalog
29 | var assemplyPlugins = assemblyPluginCatalog.GetPlugins();
30 |
31 | foreach (var plugin in assemplyPlugins)
32 | {
33 | var inst = (IPlugin) Activator.CreateInstance(plugin);
34 | inst.Run();
35 | }
36 | }
37 |
38 | private static async Task TypeCatalogSample()
39 | {
40 | Console.WriteLine("Type catalog sample");
41 |
42 | var typePluginCatalog = new TypePluginCatalog(typeof(FirstPlugin));
43 | await typePluginCatalog.Initialize();
44 |
45 | var typePlugin = typePluginCatalog.Get();
46 |
47 | var pluginInstance = (IPlugin) Activator.CreateInstance(typePlugin);
48 | pluginInstance.Run();
49 | }
50 |
51 | private static async Task CompositeCatalogSample()
52 | {
53 | Console.WriteLine("Composite catalog sample");
54 |
55 | // 1. Create a new plugin catalog from the current assembly
56 | var assemblyPluginCatalog = new AssemblyPluginCatalog(typeof(Program).Assembly, type => typeof(IPlugin).IsAssignableFrom(type));
57 |
58 | // 2. Also create a new plugin catalog from a type
59 | var typePluginCatalog = new TypePluginCatalog(typeof(MyPlugin));
60 |
61 | // 3. Then combine the catalogs into a composite catalog
62 | var compositeCatalog = new CompositePluginCatalog(assemblyPluginCatalog, typePluginCatalog);
63 |
64 | // 4. Initialize the composite catalog
65 | await compositeCatalog.Initialize();
66 |
67 | // 5. Get the plugins from the catalog
68 | var assemplyPlugins = compositeCatalog.GetPlugins();
69 |
70 | foreach (var plugin in assemplyPlugins)
71 | {
72 | if (plugin.Type.Name == "MyPlugin")
73 | {
74 | var inst = (IMyPlugin) Activator.CreateInstance(plugin);
75 | inst.Run();
76 | }
77 | else
78 | {
79 | var inst = (IPlugin) Activator.CreateInstance(plugin);
80 | inst.Run();
81 | }
82 | }
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/samples/WebAppWithRoslyn/Startup.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Reflection;
4 | using Microsoft.AspNetCore.Builder;
5 | using Microsoft.AspNetCore.Hosting;
6 | using Microsoft.Extensions.Configuration;
7 | using Microsoft.Extensions.DependencyInjection;
8 | using Microsoft.Extensions.Hosting;
9 | using Weikio.PluginFramework.Catalogs;
10 | using Weikio.PluginFramework.Catalogs.Roslyn;
11 |
12 | namespace WebAppWithRoslyn
13 | {
14 | public class Startup
15 | {
16 | public Startup(IConfiguration configuration)
17 | {
18 | Configuration = configuration;
19 | }
20 |
21 | public IConfiguration Configuration { get; }
22 |
23 | // This method gets called by the runtime. Use this method to add services to the container.
24 | public void ConfigureServices(IServiceCollection services)
25 | {
26 | // First we create a Roslyn Plugin Catalog which uses the scripting version of C#/Roslyn
27 | var script = "var x = \"Hello from Roslyn Plugin\"; return x;";
28 | var roslynScriptCatalog = new RoslynPluginCatalog(script);
29 |
30 | // We also create an another Roslyn Plugin Catalog to show how to create a plugin from a class.
31 | // This catalog also uses dependency injection, external references and additional namespaces.
32 | var code = @"public class MyClass
33 | {
34 | private ExternalService _service;
35 | public MyClass(ExternalService service)
36 | {
37 | _service = service;
38 | }
39 |
40 | public string RunThings()
41 | {
42 | var result = JsonConvert.SerializeObject(15);
43 | result += _service.DoWork();
44 | return result;
45 | }
46 | }";
47 |
48 | var options = new RoslynPluginCatalogOptions()
49 | {
50 | PluginName = "MyPlugin",
51 | PluginVersion = new Version("1.5.0.0"),
52 | AdditionalReferences = new List() { typeof(Newtonsoft.Json.JsonConvert).Assembly, typeof(ExternalService).Assembly },
53 | AdditionalNamespaces = new List() { "Newtonsoft.Json", "WebAppWithRoslyn" }
54 | };
55 |
56 | var roslynCodeCatalog = new RoslynPluginCatalog(code, options);
57 |
58 | services.AddPluginFramework()
59 | .AddPluginCatalog(new CompositePluginCatalog(roslynScriptCatalog, roslynCodeCatalog));
60 |
61 | services.AddSingleton();
62 | services.AddControllers();
63 | }
64 |
65 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
66 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
67 | {
68 | if (env.IsDevelopment())
69 | {
70 | app.UseDeveloperExceptionPage();
71 | }
72 |
73 | app.UseHttpsRedirection();
74 |
75 | app.UseRouting();
76 |
77 | app.UseAuthorization();
78 |
79 | app.UseEndpoints(endpoints =>
80 | {
81 | endpoints.MapControllers();
82 | });
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/samples/WebAppWithDelegate/Startup.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Reflection;
4 | using Microsoft.AspNetCore.Builder;
5 | using Microsoft.AspNetCore.Hosting;
6 | using Microsoft.Extensions.DependencyInjection;
7 | using Microsoft.Extensions.Hosting;
8 | using Weikio.PluginFramework.Catalogs;
9 | using Weikio.PluginFramework.Catalogs.Delegates;
10 |
11 | namespace WebAppWithDelegate
12 | {
13 | public class Startup
14 | {
15 | // This method gets called by the runtime. Use this method to add services to the container.
16 | public void ConfigureServices(IServiceCollection services)
17 | {
18 | // 1. Create a Plugin Catalog from an Action
19 | var actionDelegate = new Action>(s =>
20 | {
21 | s.Add("Hello from action");
22 | });
23 | var actionCatalog = new DelegatePluginCatalog(actionDelegate, "MyActionPlugin");
24 |
25 | // 2. Create an another catalog from a Func
26 | var funcDelegate = new Func, string>(s =>
27 | {
28 | s.Add("Hello from func");
29 |
30 | return string.Join(Environment.NewLine, s);
31 | });
32 | var funcCatalog = new DelegatePluginCatalog(funcDelegate, "MyFuncPlugin");
33 |
34 | // 3. Create a third catalog to show how constructor injection and parameters can be used
35 | var funcWithExternalService = new Func((s, service) =>
36 | {
37 | var words = service.GetWords();
38 |
39 | s = s + Environment.NewLine + words;
40 |
41 | return s;
42 | });
43 |
44 | var funcWithExternalServiceCatalog = new DelegatePluginCatalog(funcWithExternalService, pluginName: "MyExternalServicePlugin",
45 | // 4. Use conversion rules to indicate that ExternalService should be a constructor parameter and the string should be a property
46 | conversionRules: new List()
47 | {
48 | // Rules can target parameter types
49 | new DelegateConversionRule(info => info.ParameterType == typeof(ExternalService), nfo => new ParameterConversion() { ToConstructor = true }),
50 | // Conversions based on the parameter names also work
51 | new DelegateConversionRule(info => info.Name == "s", nfo => new ParameterConversion() { ToPublicProperty = true }),
52 | });
53 |
54 | services.AddPluginFramework()
55 | .AddPluginCatalog(new CompositePluginCatalog(actionCatalog, funcCatalog, funcWithExternalServiceCatalog));
56 |
57 | services.AddSingleton();
58 | services.AddControllers();
59 | }
60 |
61 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
62 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
63 | {
64 | if (env.IsDevelopment())
65 | {
66 | app.UseDeveloperExceptionPage();
67 | }
68 |
69 | app.UseHttpsRedirection();
70 |
71 | app.UseRouting();
72 |
73 | app.UseAuthorization();
74 |
75 | app.UseEndpoints(endpoints =>
76 | {
77 | endpoints.MapControllers();
78 | });
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/tests/unit/Weikio.PluginFramework.Catalogs.Roslyn.Tests/RegularInitializerTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Reflection;
4 | using System.Threading.Tasks;
5 | using Xunit;
6 |
7 | namespace Weikio.PluginFramework.Catalogs.Roslyn.Tests
8 | {
9 | public class RegularInitializerTests
10 | {
11 | [Fact]
12 | public async Task ThrowsWithInvalidCode()
13 | {
14 | // Arrange
15 | var invalidCode = @"public class MyClass
16 | {
17 | public void RunThings // <- missing parentheses
18 | {
19 | var y = 0;
20 | var a = 1;
21 |
22 | a = y + 10;
23 |
24 | Debug.WriteLine(y + a);
25 | }
26 | }";
27 |
28 | // Assert
29 | await Assert.ThrowsAsync(async () => await TestHelpers.CompileRegular(invalidCode));
30 | }
31 |
32 | [Fact]
33 | public async Task ThrowsWithEmptyScript()
34 | {
35 | // Arrange
36 | var invalidCode = "";
37 |
38 | // Assert: Throws
39 | await Assert.ThrowsAsync(async () => await TestHelpers.CompileRegular(invalidCode));
40 | }
41 |
42 | [Fact]
43 | public async Task CanCompileCode()
44 | {
45 | // Arrange
46 | var code = @"public class MyClass
47 | {
48 | public void RunThings()
49 | {
50 | var y = 0;
51 | var a = 1;
52 |
53 | a = y + 10;
54 |
55 | Debug.WriteLine(y + a);
56 | }
57 | }";
58 |
59 | // Assert: Does not throw
60 | await TestHelpers.CompileRegular(code);
61 | }
62 |
63 | [Fact]
64 | public async Task CanAddReference()
65 | {
66 | // Arrange
67 | var code = @"public class MyClass
68 | {
69 | public void RunThings()
70 | {
71 | Newtonsoft.Json.JsonConvert.SerializeObject(15);
72 | }
73 | }";
74 |
75 | var options = new RoslynPluginCatalogOptions() { AdditionalReferences = new List() { typeof(Newtonsoft.Json.JsonConvert).Assembly } };
76 |
77 | await TestHelpers.CompileRegular(code, options);
78 | }
79 |
80 | [Fact]
81 | public async Task CanAddNamespace()
82 | {
83 | // Arrange
84 | var code = @"public class MyClass
85 | {
86 | public void RunThings()
87 | {
88 | JsonConvert.SerializeObject(15);
89 | }
90 | }";
91 |
92 | var options = new RoslynPluginCatalogOptions()
93 | {
94 | AdditionalReferences = new List() { typeof(Newtonsoft.Json.JsonConvert).Assembly },
95 | AdditionalNamespaces = new List() { "Newtonsoft.Json" }
96 | };
97 |
98 | await TestHelpers.CompileRegular(code, options);
99 | }
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework/TypeFinding/TypeFinderCriteriaBuilder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace Weikio.PluginFramework.TypeFinding
5 | {
6 | public class TypeFinderCriteriaBuilder
7 | {
8 | private Type _inherits;
9 | private Type _implements;
10 | private Type _assignable;
11 | private bool? _isAbstract = false;
12 | private bool? _isInterface = false;
13 | private string _name;
14 | private Type _attribute;
15 | private List _tags = new List();
16 |
17 | public TypeFinderCriteria Build()
18 | {
19 | var res = new TypeFinderCriteria
20 | {
21 | IsInterface = _isInterface,
22 | Implements = _implements,
23 | Inherits = _inherits,
24 | AssignableTo = _assignable,
25 | Name = _name,
26 | IsAbstract = _isAbstract,
27 | HasAttribute = _attribute,
28 | Tags = _tags
29 | };
30 |
31 | return res;
32 | }
33 |
34 | public static implicit operator TypeFinderCriteria(TypeFinderCriteriaBuilder criteriaBuilder)
35 | {
36 | return criteriaBuilder.Build();
37 | }
38 |
39 | public static TypeFinderCriteriaBuilder Create()
40 | {
41 | return new TypeFinderCriteriaBuilder();
42 | }
43 |
44 | public TypeFinderCriteriaBuilder HasName(string name)
45 | {
46 | _name = name;
47 |
48 | return this;
49 | }
50 |
51 | public TypeFinderCriteriaBuilder Implements()
52 | {
53 | return Implements(typeof(T));
54 | }
55 |
56 | public TypeFinderCriteriaBuilder Implements(Type t)
57 | {
58 | _implements = t;
59 |
60 | return this;
61 | }
62 |
63 | public TypeFinderCriteriaBuilder Inherits()
64 | {
65 | return Inherits(typeof(T));
66 | }
67 |
68 | public TypeFinderCriteriaBuilder Inherits(Type t)
69 | {
70 | _inherits = t;
71 |
72 | return this;
73 | }
74 |
75 | public TypeFinderCriteriaBuilder IsAbstract(bool? isAbstract)
76 | {
77 | _isAbstract = isAbstract;
78 |
79 | return this;
80 | }
81 |
82 | public TypeFinderCriteriaBuilder IsInterface(bool? isInterface)
83 | {
84 | _isInterface = isInterface;
85 |
86 | return this;
87 | }
88 |
89 | public TypeFinderCriteriaBuilder AssignableTo(Type assignableTo)
90 | {
91 | _assignable = assignableTo;
92 |
93 | return this;
94 | }
95 |
96 | public TypeFinderCriteriaBuilder HasAttribute(Type attribute)
97 | {
98 | _attribute = attribute;
99 |
100 | return this;
101 | }
102 |
103 | public TypeFinderCriteriaBuilder Tag(string tag)
104 | {
105 | if (_tags == null)
106 | {
107 | _tags = new List();
108 | }
109 |
110 | if (_tags.Contains(tag))
111 | {
112 | return this;
113 | }
114 |
115 | _tags.Add(tag);
116 |
117 | return this;
118 | }
119 |
120 | public TypeFinderCriteriaBuilder Tag(params string[] tags)
121 | {
122 | if (_tags == null)
123 | {
124 | _tags = new List();
125 | }
126 |
127 | foreach (var tag in tags)
128 | {
129 | if (_tags.Contains(tag))
130 | {
131 | continue;
132 | }
133 |
134 | _tags.Add(tag);
135 | }
136 |
137 |
138 | return this;
139 | }
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/samples/BlazorApp/wwwroot/css/open-iconic/README.md:
--------------------------------------------------------------------------------
1 | [Open Iconic v1.1.1](http://useiconic.com/open)
2 | ===========
3 |
4 | ### Open Iconic is the open source sibling of [Iconic](http://useiconic.com). It is a hyper-legible collection of 223 icons with a tiny footprint—ready to use with Bootstrap and Foundation. [View the collection](http://useiconic.com/open#icons)
5 |
6 |
7 |
8 | ## What's in Open Iconic?
9 |
10 | * 223 icons designed to be legible down to 8 pixels
11 | * Super-light SVG files - 61.8 for the entire set
12 | * SVG sprite—the modern replacement for icon fonts
13 | * Webfont (EOT, OTF, SVG, TTF, WOFF), PNG and WebP formats
14 | * Webfont stylesheets (including versions for Bootstrap and Foundation) in CSS, LESS, SCSS and Stylus formats
15 | * PNG and WebP raster images in 8px, 16px, 24px, 32px, 48px and 64px.
16 |
17 |
18 | ## Getting Started
19 |
20 | #### For code samples and everything else you need to get started with Open Iconic, check out our [Icons](http://useiconic.com/open#icons) and [Reference](http://useiconic.com/open#reference) sections.
21 |
22 | ### General Usage
23 |
24 | #### Using Open Iconic's SVGs
25 |
26 | We like SVGs and we think they're the way to display icons on the web. Since Open Iconic are just basic SVGs, we suggest you display them like you would any other image (don't forget the `alt` attribute).
27 |
28 | ```
29 |
30 | ```
31 |
32 | #### Using Open Iconic's SVG Sprite
33 |
34 | Open Iconic also comes in a SVG sprite which allows you to display all the icons in the set with a single request. It's like an icon font, without being a hack.
35 |
36 | Adding an icon from an SVG sprite is a little different than what you're used to, but it's still a piece of cake. *Tip: To make your icons easily style able, we suggest adding a general class to the* `` *tag and a unique class name for each different icon in the* `` *tag.*
37 |
38 | ```
39 |
40 |
41 |
42 | ```
43 |
44 | Sizing icons only needs basic CSS. All the icons are in a square format, so just set the `` tag with equal width and height dimensions.
45 |
46 | ```
47 | .icon {
48 | width: 16px;
49 | height: 16px;
50 | }
51 | ```
52 |
53 | Coloring icons is even easier. All you need to do is set the `fill` rule on the `` tag.
54 |
55 | ```
56 | .icon-account-login {
57 | fill: #f00;
58 | }
59 | ```
60 |
61 | To learn more about SVG Sprites, read [Chris Coyier's guide](http://css-tricks.com/svg-sprites-use-better-icon-fonts/).
62 |
63 | #### Using Open Iconic's Icon Font...
64 |
65 |
66 | ##### …with Bootstrap
67 |
68 | You can find our Bootstrap stylesheets in `font/css/open-iconic-bootstrap.{css, less, scss, styl}`
69 |
70 |
71 | ```
72 |
73 | ```
74 |
75 |
76 | ```
77 |
78 | ```
79 |
80 | ##### …with Foundation
81 |
82 | You can find our Foundation stylesheets in `font/css/open-iconic-foundation.{css, less, scss, styl}`
83 |
84 | ```
85 |
86 | ```
87 |
88 |
89 | ```
90 |
91 | ```
92 |
93 | ##### …on its own
94 |
95 | You can find our default stylesheets in `font/css/open-iconic.{css, less, scss, styl}`
96 |
97 | ```
98 |
99 | ```
100 |
101 | ```
102 |
103 | ```
104 |
105 |
106 | ## License
107 |
108 | ### Icons
109 |
110 | All code (including SVG markup) is under the [MIT License](http://opensource.org/licenses/MIT).
111 |
112 | ### Fonts
113 |
114 | All fonts are under the [SIL Licensed](http://scripts.sil.org/cms/scripts/page.php?item_id=OFL_web).
115 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework.Catalogs.NuGet/NugetPluginCatalogOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using NuGet.Common;
3 | using Weikio.PluginFramework.Abstractions;
4 | using Weikio.PluginFramework.Catalogs.NuGet;
5 | using Weikio.NugetDownloader;
6 | using Weikio.PluginFramework.TypeFinding;
7 |
8 | namespace Weikio.PluginFramework.Catalogs.NuGet
9 | {
10 | public class NugetPluginCatalogOptions
11 | {
12 | ///
13 | /// Gets or sets the function which is used to create the logger for Nuget activities
14 | ///
15 | public Func LoggerFactory { get; set; } = Defaults.LoggerFactory;
16 |
17 | ///
18 | /// Gets or sets the .
19 | ///
20 | public TypeFinderOptions TypeFinderOptions { get; set; } = new TypeFinderOptions();
21 |
22 | ///
23 | /// Gets or sets how the plugin names and version should be defined. .
24 | ///
25 | public PluginNameOptions PluginNameOptions { get; set; } = Defaults.PluginNameOptions;
26 |
27 | ///
28 | /// Gets or sets if system feeds should be used as secondary feeds for finding packages when feed url is defined.
29 | ///
30 | public bool IncludeSystemFeedsAsSecondary { get; set; } = false;
31 |
32 | ///
33 | /// Gets or sets the target platform. If not set, EntryAssembly's target framework is used.
34 | ///
35 | public string TargetFramework { get; set; } = Defaults.TargetFramework;
36 |
37 | ///
38 | /// Gets or sets if Plugin Framework should take care of package caching. In some cases Nuget will download already downloaded package. This flag
39 | /// tries to make sure that the package is downloaded only once. Note: Requires that PackagesFolder is set
40 | ///
41 | public bool ForcePackageCaching { get; set; } = false;
42 |
43 | ///
44 | /// Gets or sets the folder where package is installed. Defaults to unique random temp path.
45 | ///
46 | public string CustomPackagesFolder { get; set; } = string.Empty;
47 |
48 | ///
49 | /// Gets or sets if Plugin Framework should try to retry package download if it fails for the first time. If true and the download fails,
50 | /// Plugin Framework will clear the Nuget cache and then tries again.
51 | ///
52 | public bool AutoRetryPackageDownload { get; set; } = false;
53 |
54 | ///
55 | /// Gets or sets the target rid. If not set, RuntimeInformation.RuntimeIdentifier is used.
56 | ///
57 | public string TargetRid { get; set; } = Defaults.TargetRid;
58 |
59 | public static class Defaults
60 | {
61 | ///
62 | /// Gets or sets the default function which is used to create the logger for PluginLoadContextOptions
63 | ///
64 | public static Func LoggerFactory { get; set; } = () => new ConsoleLogger();
65 |
66 | ///
67 | /// Gets or sets the default of how the plugin names and version should be defined. .
68 | ///
69 | public static PluginNameOptions PluginNameOptions { get; set; } = new PluginNameOptions();
70 |
71 | ///
72 | /// Gets or sets the default target platform. If not set, EntryAssembly's target framework is used.
73 | ///
74 | public static string TargetFramework { get; set; } = string.Empty;
75 |
76 | ///
77 | /// Gets or sets the default target rid. If not set, RuntimeInformation.RuntimeIdentifier is used.
78 | ///
79 | public static string TargetRid { get; set; } = string.Empty;
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework.Abstractions/PluginNameOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel;
3 | using System.Diagnostics;
4 | using System.Reflection;
5 |
6 | namespace Weikio.PluginFramework.Abstractions
7 | {
8 | ///
9 | /// Configuration options for defining how the plugin name and plugin version are generated.
10 | ///
11 | public class PluginNameOptions
12 | {
13 | ///
14 | /// Gets or sets the func which defines how the plugin's name is deducted. By default tries to find the plugin's name from .
15 | /// If that is missing, type's full name is used.
16 | ///
17 | public Func PluginNameGenerator { get; set; } = (options, type) =>
18 | {
19 | var displayNameAttribute = type.GetCustomAttribute(typeof(DisplayNameAttribute), true) as DisplayNameAttribute;
20 |
21 | if (displayNameAttribute == null)
22 | {
23 | return type.FullName;
24 | }
25 |
26 | if (string.IsNullOrWhiteSpace(displayNameAttribute.DisplayName))
27 | {
28 | return type.FullName;
29 | }
30 |
31 | return displayNameAttribute.DisplayName;
32 | };
33 |
34 | ///
35 | /// Gets or sets the func which defines how the plugin's version is deducted. By default tries to find the plugin's assembly and its FileVersion.
36 | ///
37 | public Func PluginVersionGenerator { get; set; } = (options, type) =>
38 | {
39 | var assemblyLocation = type.Assembly.Location;
40 | Version version;
41 |
42 | if (!string.IsNullOrWhiteSpace(assemblyLocation))
43 | {
44 | var versionInfo = FileVersionInfo.GetVersionInfo(assemblyLocation);
45 |
46 | if (string.IsNullOrWhiteSpace(versionInfo.FileVersion))
47 | {
48 | version = new Version(1, 0, 0, 0);
49 | }
50 | else if (string.Equals(versionInfo.FileVersion, "0.0.0.0"))
51 | {
52 | version = new Version(1, 0, 0, 0);
53 | }
54 | else
55 | {
56 | version = Version.Parse(versionInfo.FileVersion);
57 | }
58 | }
59 | else
60 | {
61 | version = new Version(1, 0, 0, 0);
62 | }
63 |
64 | return version;
65 | };
66 |
67 | ///
68 | /// Gets or sets the func which defines how the plugin's description is deducted. By default tries to find the plugin's assembly and its Comments.
69 | ///
70 | public Func PluginDescriptionGenerator { get; set; } = (options, type) =>
71 | {
72 | var assemblyLocation = type.Assembly.Location;
73 |
74 | if (string.IsNullOrWhiteSpace(assemblyLocation))
75 | {
76 | return string.Empty;
77 | }
78 |
79 | var versionInfo = FileVersionInfo.GetVersionInfo(assemblyLocation);
80 |
81 | return versionInfo.Comments;
82 | };
83 |
84 | ///
85 | /// Gets or sets the func which defines how the plugin's product version is deducted. By default tries to find the plugin's assembly and its ProductVersion.
86 | ///
87 | public Func PluginProductVersionGenerator { get; set; } = (options, type) =>
88 | {
89 | var assemblyLocation = type.Assembly.Location;
90 |
91 | if (string.IsNullOrWhiteSpace(assemblyLocation))
92 | {
93 | return string.Empty;
94 | }
95 |
96 | var versionInfo = FileVersionInfo.GetVersionInfo(assemblyLocation);
97 |
98 | return versionInfo.ProductVersion;
99 | };
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework/Context/PluginLoadContextOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Reflection;
4 | using Microsoft.Extensions.Logging;
5 | using Microsoft.Extensions.Logging.Abstractions;
6 |
7 | namespace Weikio.PluginFramework.Context
8 | {
9 | ///
10 | /// Options for PluginLoadContext
11 | ///
12 | public class PluginLoadContextOptions
13 | {
14 | ///
15 | /// Gets or sets if the plugin should by default to use the assemblies referenced by the plugin or by the host application. Useful in situations where it is important that the host application
16 | /// and the plugin use the same version of the assembly, even if they reference different versions.
17 | ///
18 | public UseHostApplicationAssembliesEnum UseHostApplicationAssemblies { get; set; } = Defaults.UseHostApplicationAssemblies;
19 |
20 | ///
21 | /// Gets or sets the assemblies which the plugin should use if UseHostApplicationAssemblies is set to Selected. These assemblies are used
22 | /// even if the plugin itself references an another version of the same assembly.
23 | ///
24 | public List HostApplicationAssemblies { get; set; } = Defaults.HostApplicationAssemblies;
25 |
26 | ///
27 | /// Gets or sets the function which is used to create the logger for PluginLoadContextOptions
28 | ///
29 | public Func> LoggerFactory { get; set; } = Defaults.LoggerFactory;
30 |
31 | ///
32 | /// Gets or sets the additional runtime paths which are used when locating plugin assemblies
33 | ///
34 | public List AdditionalRuntimePaths { get; set; } = Defaults.AdditionalRuntimePaths;
35 |
36 | ///
37 | /// Gets or sets a list of assemblies and paths which can be used to override default assembly loading. Useful in situations where in runtime we want to load a DLL from a separate location.
38 | ///
39 | public List RuntimeAssemblyHints { get; set; } = Defaults.RuntimeAssemblyHints;
40 |
41 | public static class Defaults
42 | {
43 | ///
44 | /// Gets or sets if the plugin should by default to use the assemblies referenced by the plugin or by the host application. Default = Always. Useful in situations where it is important that the host application
45 | /// and the plugin use the same version of the assembly, even if they reference different versions.
46 | ///
47 | public static UseHostApplicationAssembliesEnum UseHostApplicationAssemblies { get; set; } = UseHostApplicationAssembliesEnum.Always;
48 |
49 | ///
50 | /// Gets or sets the assemblies which the plugin should use if UseHostApplicationAssemblies is set to Selected. These assemblies are used
51 | /// even if the plugin itself references an another version of the same assembly.
52 | ///
53 | public static List HostApplicationAssemblies { get; set; } = new List();
54 |
55 | ///
56 | /// Gets or sets the function which is used to create the logger for PluginLoadContextOptions
57 | ///
58 | public static Func> LoggerFactory { get; set; } = () => NullLogger.Instance;
59 |
60 | ///
61 | /// Gets or sets the additional runtime paths which are used when locating plugin assemblies
62 | ///
63 | public static List AdditionalRuntimePaths { get; set; } = new List();
64 |
65 | ///
66 | /// Gets or sets a list of assemblies and paths which can be used to override default assembly loading. Useful in situations where in runtime we want to load a DLL from a separate location.
67 | ///
68 | public static List RuntimeAssemblyHints { get; set; } = new List();
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/samples/BlazorApp/wwwroot/css/open-iconic/FONT-LICENSE:
--------------------------------------------------------------------------------
1 | SIL OPEN FONT LICENSE Version 1.1
2 |
3 | Copyright (c) 2014 Waybury
4 |
5 | PREAMBLE
6 | The goals of the Open Font License (OFL) are to stimulate worldwide
7 | development of collaborative font projects, to support the font creation
8 | efforts of academic and linguistic communities, and to provide a free and
9 | open framework in which fonts may be shared and improved in partnership
10 | with others.
11 |
12 | The OFL allows the licensed fonts to be used, studied, modified and
13 | redistributed freely as long as they are not sold by themselves. The
14 | fonts, including any derivative works, can be bundled, embedded,
15 | redistributed and/or sold with any software provided that any reserved
16 | names are not used by derivative works. The fonts and derivatives,
17 | however, cannot be released under any other type of license. The
18 | requirement for fonts to remain under this license does not apply
19 | to any document created using the fonts or their derivatives.
20 |
21 | DEFINITIONS
22 | "Font Software" refers to the set of files released by the Copyright
23 | Holder(s) under this license and clearly marked as such. This may
24 | include source files, build scripts and documentation.
25 |
26 | "Reserved Font Name" refers to any names specified as such after the
27 | copyright statement(s).
28 |
29 | "Original Version" refers to the collection of Font Software components as
30 | distributed by the Copyright Holder(s).
31 |
32 | "Modified Version" refers to any derivative made by adding to, deleting,
33 | or substituting -- in part or in whole -- any of the components of the
34 | Original Version, by changing formats or by porting the Font Software to a
35 | new environment.
36 |
37 | "Author" refers to any designer, engineer, programmer, technical
38 | writer or other person who contributed to the Font Software.
39 |
40 | PERMISSION & CONDITIONS
41 | Permission is hereby granted, free of charge, to any person obtaining
42 | a copy of the Font Software, to use, study, copy, merge, embed, modify,
43 | redistribute, and sell modified and unmodified copies of the Font
44 | Software, subject to the following conditions:
45 |
46 | 1) Neither the Font Software nor any of its individual components,
47 | in Original or Modified Versions, may be sold by itself.
48 |
49 | 2) Original or Modified Versions of the Font Software may be bundled,
50 | redistributed and/or sold with any software, provided that each copy
51 | contains the above copyright notice and this license. These can be
52 | included either as stand-alone text files, human-readable headers or
53 | in the appropriate machine-readable metadata fields within text or
54 | binary files as long as those fields can be easily viewed by the user.
55 |
56 | 3) No Modified Version of the Font Software may use the Reserved Font
57 | Name(s) unless explicit written permission is granted by the corresponding
58 | Copyright Holder. This restriction only applies to the primary font name as
59 | presented to the users.
60 |
61 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
62 | Software shall not be used to promote, endorse or advertise any
63 | Modified Version, except to acknowledge the contribution(s) of the
64 | Copyright Holder(s) and the Author(s) or with their explicit written
65 | permission.
66 |
67 | 5) The Font Software, modified or unmodified, in part or in whole,
68 | must be distributed entirely under this license, and must not be
69 | distributed under any other license. The requirement for fonts to
70 | remain under this license does not apply to any document created
71 | using the Font Software.
72 |
73 | TERMINATION
74 | This license becomes null and void if any of the above conditions are
75 | not met.
76 |
77 | DISCLAIMER
78 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
79 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
80 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
81 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
82 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
83 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
84 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
85 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
86 | OTHER DEALINGS IN THE FONT SOFTWARE.
87 |
--------------------------------------------------------------------------------
/tests/unit/Weikio.PluginFramework.Tests/TypePluginCatalogTests.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using Weikio.PluginFramework.Abstractions;
3 | using Weikio.PluginFramework.Catalogs;
4 | using Weikio.PluginFramework.Tests.Plugins;
5 | using Xunit;
6 |
7 | namespace Weikio.PluginFramework.Tests
8 | {
9 | public class TypePluginCatalogTests
10 | {
11 | [Fact]
12 | public async Task CanInitialize()
13 | {
14 | var catalog = new TypePluginCatalog(typeof(TypePlugin));
15 | await catalog.Initialize();
16 |
17 | var plugins = catalog.GetPlugins();
18 | Assert.Single(plugins);
19 | }
20 |
21 | [Fact]
22 | public async Task NameIsTypeFullName()
23 | {
24 | var catalog = new TypePluginCatalog(typeof(TypePlugin));
25 | await catalog.Initialize();
26 |
27 | var thePlugin = catalog.Single();
28 |
29 | Assert.Equal("Weikio.PluginFramework.Tests.Plugins.TypePlugin", thePlugin.Name);
30 | }
31 |
32 | [Fact]
33 | public async Task CanConfigureNameResolver()
34 | {
35 | var catalog = new TypePluginCatalog(typeof(TypePlugin), configure =>
36 | {
37 | configure.PluginNameGenerator = (opt, type) => "HelloOptions";
38 | });
39 |
40 | await catalog.Initialize();
41 |
42 | var thePlugin = catalog.Single();
43 |
44 | Assert.Equal("HelloOptions", thePlugin.Name);
45 | }
46 |
47 |
48 | [Fact]
49 | public async Task CanSetNameByAttribute()
50 | {
51 | var catalog = new TypePluginCatalog(typeof(TypePluginWithName));
52 | await catalog.Initialize();
53 |
54 | var thePlugin = catalog.Single();
55 |
56 | Assert.Equal("MyCustomName", thePlugin.Name);
57 | }
58 |
59 |
60 | [Fact]
61 | public async Task CanConfigureNamingOptions()
62 | {
63 | var options = new TypePluginCatalogOptions()
64 | {
65 | PluginNameOptions = new PluginNameOptions() { PluginNameGenerator = (opt, type) => "HelloOptions" }
66 | };
67 |
68 | var catalog = new TypePluginCatalog(typeof(TypePlugin), options);
69 |
70 | await catalog.Initialize();
71 |
72 | var thePlugin = catalog.Single();
73 |
74 | Assert.Equal("HelloOptions", thePlugin.Name);
75 | }
76 |
77 | [Fact]
78 | public async Task CanConfigureDefaultNamingOptions()
79 | {
80 | TypePluginCatalogOptions.Defaults.PluginNameOptions = new PluginNameOptions()
81 | {
82 | PluginNameGenerator = (nameOptions, type) => "HelloOptions"
83 | };
84 |
85 | var catalog = new TypePluginCatalog(typeof(TypePlugin));
86 |
87 | await catalog.Initialize();
88 |
89 | var thePlugin = catalog.Single();
90 |
91 | Assert.Equal("HelloOptions", thePlugin.Name);
92 | }
93 |
94 | [Fact]
95 | public async Task CanOverrideDefaultNamingOptions()
96 | {
97 | var options = new TypePluginCatalogOptions()
98 | {
99 | PluginNameOptions = new PluginNameOptions() { PluginNameGenerator = (opt, type) => "Overridden" }
100 | };
101 |
102 | TypePluginCatalogOptions.Defaults.PluginNameOptions = new PluginNameOptions()
103 | {
104 | PluginNameGenerator = (nameOptions, type) => "HelloOptions"
105 | };
106 |
107 | var catalog = new TypePluginCatalog(typeof(TypePlugin));
108 | var catalog2 = new TypePluginCatalog(typeof(TypePlugin), options);
109 |
110 | await catalog.Initialize();
111 | await catalog2.Initialize();
112 |
113 | var thePlugin = catalog.Single();
114 | Assert.Equal("HelloOptions", thePlugin.Name);
115 |
116 | var anotherPlugin = catalog2.Single();
117 | Assert.Equal("Overridden", anotherPlugin.Name);
118 | }
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/samples/BlazorApp/wwwroot/css/site.css:
--------------------------------------------------------------------------------
1 | @import url('open-iconic/font/css/open-iconic-bootstrap.min.css');
2 |
3 | html, body {
4 | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
5 | }
6 |
7 | a, .btn-link {
8 | color: #0366d6;
9 | }
10 |
11 | .btn-primary {
12 | color: #fff;
13 | background-color: #1b6ec2;
14 | border-color: #1861ac;
15 | }
16 |
17 | app {
18 | position: relative;
19 | display: flex;
20 | flex-direction: column;
21 | }
22 |
23 | .top-row {
24 | height: 3.5rem;
25 | display: flex;
26 | align-items: center;
27 | }
28 |
29 | .main {
30 | flex: 1;
31 | }
32 |
33 | .main .top-row {
34 | background-color: #f7f7f7;
35 | border-bottom: 1px solid #d6d5d5;
36 | justify-content: flex-end;
37 | }
38 |
39 | .main .top-row > a, .main .top-row .btn-link {
40 | white-space: nowrap;
41 | margin-left: 1.5rem;
42 | }
43 |
44 | .main .top-row a:first-child {
45 | overflow: hidden;
46 | text-overflow: ellipsis;
47 | }
48 |
49 | .sidebar {
50 | background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
51 | }
52 |
53 | .sidebar .top-row {
54 | background-color: rgba(0,0,0,0.4);
55 | }
56 |
57 | .sidebar .navbar-brand {
58 | font-size: 1.1rem;
59 | }
60 |
61 | .sidebar .oi {
62 | width: 2rem;
63 | font-size: 1.1rem;
64 | vertical-align: text-top;
65 | top: -2px;
66 | }
67 |
68 | .sidebar .nav-item {
69 | font-size: 0.9rem;
70 | padding-bottom: 0.5rem;
71 | }
72 |
73 | .sidebar .nav-item:first-of-type {
74 | padding-top: 1rem;
75 | }
76 |
77 | .sidebar .nav-item:last-of-type {
78 | padding-bottom: 1rem;
79 | }
80 |
81 | .sidebar .nav-item a {
82 | color: #d7d7d7;
83 | border-radius: 4px;
84 | height: 3rem;
85 | display: flex;
86 | align-items: center;
87 | line-height: 3rem;
88 | }
89 |
90 | .sidebar .nav-item a.active {
91 | background-color: rgba(255,255,255,0.25);
92 | color: white;
93 | }
94 |
95 | .sidebar .nav-item a:hover {
96 | background-color: rgba(255,255,255,0.1);
97 | color: white;
98 | }
99 |
100 | .content {
101 | padding-top: 1.1rem;
102 | }
103 |
104 | .navbar-toggler {
105 | background-color: rgba(255, 255, 255, 0.1);
106 | }
107 |
108 | .valid.modified:not([type=checkbox]) {
109 | outline: 1px solid #26b050;
110 | }
111 |
112 | .invalid {
113 | outline: 1px solid red;
114 | }
115 |
116 | .validation-message {
117 | color: red;
118 | }
119 |
120 | #blazor-error-ui {
121 | background: lightyellow;
122 | bottom: 0;
123 | box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
124 | display: none;
125 | left: 0;
126 | padding: 0.6rem 1.25rem 0.7rem 1.25rem;
127 | position: fixed;
128 | width: 100%;
129 | z-index: 1000;
130 | }
131 |
132 | #blazor-error-ui .dismiss {
133 | cursor: pointer;
134 | position: absolute;
135 | right: 0.75rem;
136 | top: 0.5rem;
137 | }
138 |
139 | @media (max-width: 767.98px) {
140 | .main .top-row:not(.auth) {
141 | display: none;
142 | }
143 |
144 | .main .top-row.auth {
145 | justify-content: space-between;
146 | }
147 |
148 | .main .top-row a, .main .top-row .btn-link {
149 | margin-left: 0;
150 | }
151 | }
152 |
153 | @media (min-width: 768px) {
154 | app {
155 | flex-direction: row;
156 | }
157 |
158 | .sidebar {
159 | width: 250px;
160 | height: 100vh;
161 | position: sticky;
162 | top: 0;
163 | }
164 |
165 | .main .top-row {
166 | position: sticky;
167 | top: 0;
168 | }
169 |
170 | .main > div {
171 | padding-left: 2rem !important;
172 | padding-right: 1.5rem !important;
173 | }
174 |
175 | .navbar-toggler {
176 | display: none;
177 | }
178 |
179 | .sidebar .collapse {
180 | /* Never collapse the sidebar for wide screens */
181 | display: block;
182 | }
183 | }
184 |
185 | .widget {
186 | border: 1px solid #ccc;
187 | margin: 10px;
188 | padding: 10px;
189 | }
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework.Catalogs.Roslyn/RoslynPluginCatalog.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reflection;
5 | using System.Threading.Tasks;
6 | using Microsoft.CodeAnalysis.CSharp.Scripting;
7 | using Microsoft.CodeAnalysis.CSharp.Syntax;
8 | using Microsoft.CodeAnalysis.Scripting;
9 | using Weikio.PluginFramework.Abstractions;
10 | using Weikio.PluginFramework.Catalogs.Roslyn;
11 | using Weikio.PluginFramework.TypeFinding;
12 |
13 | // ReSharper disable once CheckNamespace
14 | namespace Weikio.PluginFramework.Catalogs
15 | {
16 | public class RoslynPluginCatalog : IPluginCatalog
17 | {
18 | private readonly RoslynPluginCatalogOptions _options;
19 | private readonly string _code;
20 |
21 | private Assembly _assembly;
22 |
23 | // private Plugin _plugin;
24 | private AssemblyPluginCatalog _catalog;
25 |
26 | public RoslynPluginCatalog(string code, RoslynPluginCatalogOptions options = null, string description = null, string productVersion = null)
27 | {
28 | if (string.IsNullOrWhiteSpace(code))
29 | {
30 | throw new ArgumentOutOfRangeException(nameof(code), code, "Code can not be null or empty");
31 | }
32 |
33 | _code = code;
34 | _options = options ?? new RoslynPluginCatalogOptions();
35 |
36 | _options.PluginNameOptions.PluginDescriptionGenerator = (nameOptions, type) => description;
37 | _options.PluginNameOptions.PluginProductVersionGenerator = (nameOptions, type) => productVersion;
38 | }
39 |
40 | public Plugin Get(string name, Version version)
41 | {
42 | return _catalog.Get(name, version);
43 | }
44 |
45 | public bool IsInitialized { get; private set; }
46 |
47 | private async Task IsScript()
48 | {
49 | try
50 | {
51 | var csharScript = CSharpScript.Create(_code, ScriptOptions.Default);
52 |
53 | var compilation = csharScript.GetCompilation();
54 |
55 | var syntaxTree = compilation.SyntaxTrees.Single();
56 |
57 | var descendants = (await syntaxTree.GetRootAsync())
58 | .DescendantNodes().ToList();
59 |
60 | var classDeclarations = descendants.OfType().FirstOrDefault();
61 |
62 | if (classDeclarations == null)
63 | {
64 | return true;
65 | }
66 |
67 | return false;
68 | }
69 | catch (Exception e)
70 | {
71 | throw new InvalidCodeException("Failed to determine if code is script or regular. Code: " + _code, e);
72 | }
73 | }
74 |
75 | public async Task Initialize()
76 | {
77 | try
78 | {
79 | var isScript = await IsScript();
80 |
81 | if (isScript)
82 | {
83 | var scriptInitializer = new ScriptInitializer(_code, _options);
84 | _assembly = await scriptInitializer.CreateAssembly();
85 | }
86 | else
87 | {
88 | var regularInitializer = new RegularInitializer(_code, _options);
89 | _assembly = await regularInitializer.CreateAssembly();
90 | }
91 |
92 | var assemblyCatalogOptions = new AssemblyPluginCatalogOptions { PluginNameOptions = _options.PluginNameOptions};
93 |
94 | if (_options.Tags?.Any() == true)
95 | {
96 | assemblyCatalogOptions.TypeFinderOptions = new TypeFinderOptions() { TypeFinderCriterias = new List()
97 | {
98 | new TypeFinderCriteria()
99 | {
100 | Query = (context, type) => true,
101 | Tags = _options.Tags
102 | }
103 | } };
104 | }
105 |
106 | _catalog = new AssemblyPluginCatalog(_assembly, assemblyCatalogOptions);
107 | await _catalog.Initialize();
108 |
109 | IsInitialized = true;
110 | }
111 | catch (Exception e)
112 | {
113 | throw new InvalidCodeException($"Failed to initialize catalog with code: {Environment.NewLine}{_code}", e);
114 | }
115 | }
116 |
117 | public List GetPlugins()
118 | {
119 | return _catalog.GetPlugins();
120 | }
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/src/Weikio.PluginFramework.Catalogs.NuGet/NugetFeedPluginCatalog.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Weikio.NugetDownloader;
7 | using Weikio.PluginFramework.Abstractions;
8 | using Weikio.PluginFramework.Catalogs.NuGet;
9 | using Weikio.PluginFramework.TypeFinding;
10 |
11 | // ReSharper disable once CheckNamespace
12 | namespace Weikio.PluginFramework.Catalogs
13 | {
14 | public class NugetFeedPluginCatalog : IPluginCatalog
15 | {
16 | private readonly NuGetFeed _packageFeed;
17 | private readonly string _searchTerm;
18 | private readonly int _maxPackages;
19 | private readonly bool _includePrereleases;
20 |
21 | private readonly HashSet _pluginAssemblyNames = new HashSet();
22 |
23 | private List _pluginCatalogs = new List();
24 | private readonly NugetFeedPluginCatalogOptions _options;
25 |
26 | public string PackagesFolder { get; }
27 |
28 | public NugetFeedPluginCatalog(NuGetFeed packageFeed, string searchTerm = null,
29 | bool includePrereleases = false, int maxPackages = 128,
30 | string packagesFolder = null, Action configureFinder = null, Dictionary criterias = null,
31 | NugetFeedPluginCatalogOptions options = null)
32 | {
33 | _packageFeed = packageFeed;
34 | _searchTerm = searchTerm;
35 | _includePrereleases = includePrereleases;
36 | _maxPackages = maxPackages;
37 |
38 | PackagesFolder = packagesFolder ?? Path.Combine(Path.GetTempPath(), "NugetFeedPluginCatalog", Path.GetRandomFileName());
39 |
40 | if (!Directory.Exists(PackagesFolder))
41 | {
42 | Directory.CreateDirectory(PackagesFolder);
43 | }
44 |
45 | if (criterias == null)
46 | {
47 | criterias = new Dictionary();
48 | }
49 |
50 | _options = options ?? new NugetFeedPluginCatalogOptions();
51 |
52 | if (configureFinder != null)
53 | {
54 | var builder = new TypeFinderCriteriaBuilder();
55 | configureFinder(builder);
56 |
57 | var criteria = builder.Build();
58 |
59 | _options.TypeFinderOptions.TypeFinderCriterias.Add(criteria);
60 | }
61 |
62 | foreach (var finderCriteria in criterias)
63 | {
64 | finderCriteria.Value.Tags = new List() { finderCriteria.Key };
65 |
66 | _options.TypeFinderOptions.TypeFinderCriterias.Add(finderCriteria.Value);
67 | }
68 | }
69 |
70 | Plugin IPluginCatalog.Get(string name, Version version)
71 | {
72 | foreach (var pluginCatalog in _pluginCatalogs)
73 | {
74 | var result = pluginCatalog.Get(name, version);
75 |
76 | if (result == null)
77 | {
78 | continue;
79 | }
80 |
81 | return result;
82 | }
83 |
84 | return null;
85 | }
86 |
87 | public bool IsInitialized { get; private set; }
88 |
89 | public async Task Initialize()
90 | {
91 | var nuGetDownloader = new NuGetDownloader(_options.LoggerFactory());
92 |
93 | var packages = await nuGetDownloader.SearchPackagesAsync(_packageFeed, _searchTerm, maxResults: _maxPackages);
94 |
95 | foreach (var packageAndRepo in packages)
96 | {
97 | var options = new NugetPluginCatalogOptions()
98 | {
99 | TypeFinderOptions = _options.TypeFinderOptions,
100 | PluginNameOptions = _options.PluginNameOptions,
101 | ForcePackageCaching = _options.ForcePackageCaching,
102 | AutoRetryPackageDownload = _options.AutoRetryPackageDownload
103 | };
104 |
105 | var packageCatalog = new NugetPackagePluginCatalog(packageAndRepo.Package.Identity.Id, packageAndRepo.Package.Identity.Version.ToString(),
106 | _includePrereleases, _packageFeed, PackagesFolder, options: options);
107 |
108 | await packageCatalog.Initialize();
109 |
110 | _pluginCatalogs.Add(packageCatalog);
111 | }
112 |
113 | IsInitialized = true;
114 | }
115 |
116 | public List GetPlugins()
117 | {
118 | return _pluginCatalogs.SelectMany(x => x.GetPlugins()).ToList();
119 | }
120 | }
121 | }
122 |
--------------------------------------------------------------------------------