[
  {
    "path": ".editorconfig",
    "content": "root=true\n# EditorConfig is awesome:http://EditorConfig.org\n\n# top-most EditorConfig file\nroot = true\n# Don't use tabs for indentation.\n[*]\nindent_style=space\ncharset=utf-8\nend_of_line=crlf\ntrim_trailing_whitespace=false\ninsert_final_newline=false\nindent_size=4\n\n# Microsoft .NET properties\ncsharp_preferred_modifier_order=public, private, protected, internal, new, abstract, virtual, sealed, override, static, readonly, extern, unsafe, volatile, async:suggestion\ndotnet_style_require_accessibility_modifiers=for_non_interface_members:hint\n\n# ReSharper properties\nresharper_autodetect_indent_settings=true\nresharper_blank_lines_after_control_transfer_statements=1\nresharper_blank_lines_around_block_case_section=1\nresharper_blank_lines_around_single_line_local_method=1\nresharper_blank_lines_before_block_statements=1\nresharper_blank_lines_before_control_transfer_statements=1\nresharper_blank_lines_before_multiline_statements=1\nresharper_blank_lines_before_single_line_comment=1\nresharper_braces_for_for=required\nresharper_braces_for_foreach=required\nresharper_braces_for_ifelse=required\nresharper_braces_for_while=required\nresharper_csharp_keep_blank_lines_in_code=1\nresharper_csharp_keep_blank_lines_in_declarations=1\nresharper_csharp_max_line_length=160\nresharper_enforce_line_ending_style=true\nresharper_keep_existing_embedded_arrangement=false\nresharper_place_simple_embedded_statement_on_same_line=False\nresharper_use_indent_from_vs=false\nresharper_space_within_single_line_array_initializer_braces=true\nresharper_accessor_owner_body=accessors_with_block_body\n\n# ReSharper inspection severities\nresharper_convert_to_null_coalescing_compound_assignment_highlighting=hint\nresharper_enforce_foreach_statement_braces_highlighting=error\nresharper_enforce_for_statement_braces_highlighting=error\nresharper_enforce_if_statement_braces_highlighting=error\nresharper_enforce_while_statement_braces_highlighting=error\nresharper_identifier_typo_highlighting=none\nresharper_redundant_base_qualifier_highlighting=warning\nresharper_web_config_module_not_resolved_highlighting=warning\nresharper_web_config_type_not_resolved_highlighting=warning\nresharper_web_config_wrong_module_highlighting=warning\n# (Please don't specify an indent_size here; that has too many unintended consequences.)\n\n# Code files\n[*.{cs,csx,vb,vbx}]\nindent_size=4\ninsert_final_newline=true\n\n# Xml project files\n[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]\nindent_size=2\n\n# Xml config files\n[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]\nindent_size=2\n\n# JSON files\n[*.json]\nindent_size=2\n\n# Dotnet code style settings:\n[*.{cs,vb}]\n# Sort using and Import directives with System.* appearing first\ndotnet_sort_system_directives_first=true\n# Avoid \"this.\" and \"Me.\" if not necessary\ndotnet_style_qualification_for_field=false:error\ndotnet_style_qualification_for_property=false:error\ndotnet_style_qualification_for_method=false:error\ndotnet_style_qualification_for_event=false:error\n\n# Use language keywords instead of framework type names for type references\ndotnet_style_predefined_type_for_locals_parameters_members=true:suggestion\ndotnet_style_predefined_type_for_member_access=true:suggestion\n\n# Suggest more modern language features when available\ndotnet_style_object_initializer=true:suggestion\ndotnet_style_collection_initializer=true:suggestion\ndotnet_style_coalesce_expression=true:suggestion\ndotnet_style_null_propagation=true:suggestion\ndotnet_style_explicit_tuple_names=true:suggestion\n\ndotnet_naming_rule.private_members_with_underscore.symbols=private_fields\ndotnet_naming_rule.private_members_with_underscore.style=prefix_underscore\ndotnet_naming_rule.private_members_with_underscore.severity=suggestion\n\ndotnet_naming_symbols.private_fields.applicable_kinds=field\ndotnet_naming_symbols.private_fields.applicable_accessibilities=private\n\ndotnet_naming_style.prefix_underscore.capitalization=camel_case\ndotnet_naming_style.prefix_underscore.required_prefix=_\n\n# CSharp code style settings:\n[*.cs]\n# Prefer \"var\" everywhere\ncsharp_style_var_for_built_in_types=true:error\ncsharp_style_var_when_type_is_apparent=true:error\ncsharp_style_var_elsewhere=true:error\n\n# Prefer method-like constructs to have a block body\ncsharp_style_expression_bodied_methods=false:none\ncsharp_style_expression_bodied_constructors=false:none\ncsharp_style_expression_bodied_operators=false:none\n\n# Prefer property-like constructs to have an expression-body\ncsharp_style_expression_bodied_properties=true:none\ncsharp_style_expression_bodied_indexers=true:none\ncsharp_style_expression_bodied_accessors=true:none\n\n# Suggest more modern language features when available\ncsharp_style_pattern_matching_over_is_with_cast_check=true:suggestion\ncsharp_style_pattern_matching_over_as_with_null_check=true:suggestion\ncsharp_style_inlined_variable_declaration=true:suggestion\ncsharp_style_throw_expression=true:suggestion\ncsharp_style_conditional_delegate_call=true:suggestion\n\n# Newline settings\ncsharp_new_line_before_open_brace=all\ncsharp_new_line_before_else=true\ncsharp_new_line_before_catch=true\ncsharp_new_line_before_finally=true\ncsharp_new_line_before_members_in_object_initializers=true\ncsharp_new_line_before_members_in_anonymous_types=true\ncsharp_new_line_between_query_expression_clauses=true\n\ncsharp_preserve_single_line_statements=false\ncsharp_preserve_single_line_blocks=true\n\n[{.eslintrc,.babelrc,.stylelintrc,jest.config,*.uproject,*.bowerrc,*.jsb3,*.jsb2,*.json}]\nindent_style=space\nindent_size=2\n\n[*.{appxmanifest,asax,ascx,aspx,build,cs,cshtml,dtd,master,nuspec,razor,resw,resx,skin,vb,xaml,xamlx,xoml,xsd}]\nindent_style=space\nindent_size=4\ntab_width=4\n"
  },
  {
    "path": ".gitignore",
    "content": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n##\n## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore\n\n# User-specific files\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# User-specific files (MonoDevelop/Xamarin Studio)\n*.userprefs\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\n[Rr]eleases/\nx64/\nx86/\nbld/\n[Bb]in/\n[Oo]bj/\n[Ll]og/\n\n# Visual Studio 2015/2017 cache/options directory\n.vs/\n# Uncomment if you have tasks that create the project's static files in wwwroot\n#wwwroot/\n\n# Visual Studio 2017 auto generated files\nGenerated\\ Files/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n# NUNIT\n*.VisualState.xml\nTestResult.xml\n\n# Build Results of an ATL Project\n[Dd]ebugPS/\n[Rr]eleasePS/\ndlldata.c\n\n# Benchmark Results\nBenchmarkDotNet.Artifacts/\n\n# .NET Core\nproject.lock.json\nproject.fragment.lock.json\nartifacts/\n**/Properties/launchSettings.json\n\n# StyleCop\nStyleCopReport.xml\n\n# Files built by Visual Studio\n*_i.c\n*_p.c\n*_i.h\n*.ilk\n*.meta\n*.obj\n*.iobj\n*.pch\n*.pdb\n*.ipdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*.log\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.svclog\n*.scc\n\n# Chutzpah Test files\n_Chutzpah*\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opendb\n*.opensdf\n*.sdf\n*.cachefile\n*.VC.db\n*.VC.VC.opendb\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n*.sap\n\n# Visual Studio Trace Files\n*.e2e\n\n# TFS 2012 Local Workspace\n$tf/\n\n# Guidance Automation Toolkit\n*.gpState\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n*.DotSettings.user\n\n# JustCode is a .NET coding add-in\n.JustCode\n\n# TeamCity is a build add-in\n_TeamCity*\n\n# DotCover is a Code Coverage Tool\n*.dotCover\n\n# AxoCover is a Code Coverage Tool\n.axoCover/*\n!.axoCover/settings.json\n\n# Visual Studio code coverage results\n*.coverage\n*.coveragexml\n\n# NCrunch\n_NCrunch_*\n.*crunch*.local.xml\nnCrunchTemp_*\n\n# MightyMoose\n*.mm.*\nAutoTest.Net/\n\n# Web workbench (sass)\n.sass-cache/\n\n# Installshield output folder\n[Ee]xpress/\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish/\n\n# Publish Web Output\n*.[Pp]ublish.xml\n*.azurePubxml\n# Note: Comment the next line if you want to checkin your web deploy settings,\n# but database connection strings (with potential passwords) will be unencrypted\n*.pubxml\n*.publishproj\n\n# Microsoft Azure Web App publish settings. Comment the next line if you want to\n# checkin your Azure Web App publish settings, but sensitive information contained\n# in these scripts will be unencrypted\nPublishScripts/\n\n# NuGet Packages\n*.nupkg\n# The packages folder can be ignored because of Package Restore\n**/[Pp]ackages/*\n# except build/, which is used as an MSBuild target.\n!**/[Pp]ackages/build/\n# Uncomment if necessary however generally it will be regenerated when needed\n#!**/[Pp]ackages/repositories.config\n# NuGet v3's project.json files produces more ignorable files\n*.nuget.props\n*.nuget.targets\n\n# Microsoft Azure Build Output\ncsx/\n*.build.csdef\n\n# Microsoft Azure Emulator\necf/\nrcf/\n\n# Windows Store app package directories and files\nAppPackages/\nBundleArtifacts/\nPackage.StoreAssociation.xml\n_pkginfo.txt\n*.appx\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!*.[Cc]ache/\n\n# Others\nClientBin/\n~$*\n*~\n*.dbmdl\n*.dbproj.schemaview\n*.jfm\n*.pfx\n*.publishsettings\norleans.codegen.cs\n\n# Including strong name files can present a security risk \n# (https://github.com/github/gitignore/pull/2483#issue-259490424)\n#*.snk\n\n# Since there are multiple workflows, uncomment next line to ignore bower_components\n# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)\n#bower_components/\n\n# RIA/Silverlight projects\nGenerated_Code/\n\n# Backup & report files from converting an old project file\n# to a newer Visual Studio version. Backup files are not needed,\n# because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\nUpgradeLog*.htm\nServiceFabricBackup/\n*.rptproj.bak\n\n# SQL Server files\n*.mdf\n*.ldf\n*.ndf\n\n# Business Intelligence projects\n*.rdl.data\n*.bim.layout\n*.bim_*.settings\n*.rptproj.rsuser\n\n# Microsoft Fakes\nFakesAssemblies/\n\n# GhostDoc plugin setting file\n*.GhostDoc.xml\n\n# Node.js Tools for Visual Studio\n.ntvs_analysis.dat\nnode_modules/\n\n# Visual Studio 6 build log\n*.plg\n\n# Visual Studio 6 workspace options file\n*.opt\n\n# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)\n*.vbw\n\n# Visual Studio LightSwitch build output\n**/*.HTMLClient/GeneratedArtifacts\n**/*.DesktopClient/GeneratedArtifacts\n**/*.DesktopClient/ModelManifest.xml\n**/*.Server/GeneratedArtifacts\n**/*.Server/ModelManifest.xml\n_Pvt_Extensions\n\n# Paket dependency manager\n.paket/paket.exe\npaket-files/\n\n# FAKE - F# Make\n.fake/\n\n# JetBrains Rider\n.idea/\n*.sln.iml\n\n# CodeRush\n.cr/\n\n# Python Tools for Visual Studio (PTVS)\n__pycache__/\n*.pyc\n\n# Cake - Uncomment if you are using it\n# tools/**\n# !tools/packages.config\n\n# Tabs Studio\n*.tss\n\n# Telerik's JustMock configuration file\n*.jmconfig\n\n# BizTalk build output\n*.btp.cs\n*.btm.cs\n*.odx.cs\n*.xsd.cs\n\n# OpenCover UI analysis results\nOpenCover/\n\n# Azure Stream Analytics local run output \nASALocalRun/\n\n# MSBuild Binary and Structured Log\n*.binlog\n\n# NVidia Nsight GPU debugger configuration file\n*.nvuser\n\n# MFractors (Xamarin productivity tool) working folder \n.mfractor/\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2019 Weik.io\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<img align=\"right\" alt=\"Plugin Framework Logo\" src=\"docs/logo_transparent_color_256.png\">\n\n# Plugin Framework for .NET Core [![NuGet Version](https://img.shields.io/nuget/v/Weikio.PluginFramework.svg?style=flat&label=Weikio.PluginFramework)](https://www.nuget.org/packages/Weikio.PluginFramework/)\n\nWith Plugin Framework for .NET Core, everything is a plugin! Plugin Framework is a **plugin platform** for .NET Core applications, including **ASP.NET Core, Blazor, WPF, Windows Forms and Console apps**. It is light-weight and easy to integrate and supports multiple different plugin catalogs, including .NET assemblies, **Nuget packages** and **Roslyn scripts**.\n\n### Main Features \n\nHere are some of the main features of Plugin Framework: \n\n* Everything is a plugin! Deliver plugins as Nuget-packages, .NET assemblies, Roslyn scripts and more.\n* Easy integration into a new or an existing .NET Core application.\n* Automatic dependency management.\n* Handles platform specific runtime DLLs and native DLLs when using Nuget-packages.\n* MIT-licensed, commercial support available.\n\n## Quickstart: Plugin Framework & ASP.NET Core\n\nPlugin Framework is available from Nuget as a .NET Core 3.1 package. There's a separate package which makes it easier to work with plugins in an ASP.NET Core app:\n\n[![NuGet Version](https://img.shields.io/nuget/v/Weikio.PluginFramework.AspNetCore.svg?style=flat&label=Weikio.PluginFramework.AspNetCore)](https://www.nuget.org/packages/Weikio.PluginFramework.AspNetCore/)\n\n```\nInstall-Package Weikio.PluginFramework.AspNetCore\n```\n\nUsing Plugin Framework can be as easy as adding a single new line into ConfigureServices:\n\n```\nservices.AddPluginFramework<IOperator>(@\".\\myplugins\");\n```\n\nThe code finds all the plugins (types that implement the custom IOperator-interface) from the myplugins-folder. The plugins can be used in a controller using constructor injection:\n\n```\npublic CalculatorController(IEnumerable<IOperator> operator)\n{\n\t_operators = operators;\n}\n```\n\nAlternatively, you can provide multiple plugin locations using catalogs:\n\n```\nvar folderPluginCatalog = new FolderPluginCatalog(@\".\\myplugins\", type =>\n{\n    type.Implements<IOperator>();\n});\n\nvar anotherPluginCatalog = new FolderPluginCatalog(@\".\\morePlugins\", type =>\n{\n    type.Implements<IOperator>();\n});\n\nservices.AddPluginFramework()\n    .AddPluginCatalog(folderPluginCatalog)\n    .AddPluginCatalog(anotherPluginCatalog)\n    .AddPluginType<IOperator>();\n```\n\n## Samples\n\nThe following Plugin Framework samples are available from GitHub:\n\n#### [Plugin Framework & .NET Console Application](https://github.com/weikio/PluginFramework/tree/master/samples/ConsoleApp)\n\n#### [Plugin Framework & ASP.NET Core](https://github.com/weikio/PluginFramework/tree/master/samples/WebApp)\n\n#### [Plugin Framework & Blazor](https://github.com/weikio/PluginFramework/tree/master/samples/BlazorApp)\n\n#### [Plugin Framework & WPF App](https://github.com/weikio/PluginFramework/tree/master/samples/WpfApp)\n\n#### [Plugin Framework & WinForms App](https://github.com/weikio/PluginFramework/tree/master/samples/WinFormsApp)\n\n#### [Nuget & Plugin Framework & ASP.NET Core](https://github.com/weikio/PluginFramework/tree/master/samples/WebAppWithNuget)\n\n#### [Roslyn & Plugin Framework & ASP.NET Core](https://github.com/weikio/PluginFramework/tree/master/samples/WebAppWithRoslyn)\n\n#### [Delegates & Plugin Framework & ASP.NET Core](https://github.com/weikio/PluginFramework/tree/master/samples/WebAppWithDelegate)\n\n#### [Tagging & WinForms App](https://github.com/weikio/PluginFramework/tree/master/samples/WinFormsApp)\n\n#### [AppSettings.json & ASP.NET Core](https://github.com/weikio/PluginFramework/tree/master/samples/WebAppWithAppSettings)\n\n## Background and introduction\n\nFor more details related to Plugin Framework's background, please see the following [introduction article from InfoQ](https://www.infoq.com/articles/Plugin-Framework-DotNet/).\n\n## Main concepts\n\nUsing Plugin Framework concentrates around two concepts: **Plugins** and **Plugin Catalogs**.\n\n### Plugin\n\nPlugins are software programs, which provide extensions to an application. Plugins are designed to work with a single application. This app is often called the **host application**. The host application is designed in such a way that it can locate and run plugins dynamically, runtime. **The application works without the plugins, the plugins can't work without the host application.**\n\nThe host application defines the specifications for the plugins. In some applications a plugin can add new functionality into the UI. In other apps, plugins are used to distribute logs into multiple different systems. The host application defines what kind of extensions it supports.\n\nPlugin-based software architecture can help in the following scenarios:\n\n* Adding new features to application after the release\n* Splitting large systems into smaller parts\n* Updating always-on software system without restarting it\n\nPlugins are dynamic, and they are often only loaded when the application needs them. Plugins are not usually compiled as part of the system but distributed as separate packages (assemblies, Nuget packages).\n\nIn the context of the Plugin Framework, **plugin is a single .NET Type**. What makes a plugin? As described previously, it depends on the host application. For some applications a plugin is a type which implements a specific interface. In some applications a plugin is a type which has a single public method called Run. Attributes are often used to indicate the plugins and that is also supported by Plugin Framework. From the Plugin Framework's point of view anything or everything can be a plugin. \n\nAs mentioned, in Plugin Framework a single plugin is a .NET Type. Even though Plugin Framework's ASP.NET Core support makes it easy to instantiate and use plugins in services and controllers through dependency injection (IServiceProvider), Plugin Framework itself doesn't provide any built-in mechanisms for creating instances (objects) from the plugins (types). In some cases Activator.CreateInstance is all that is needed and in some cases it is best to hook Plugin Framework with the app's DI-system. The requirements are host application specific.\n\nIn Plugin Framework, each Plugin is composed of the following information:\n* Type\n* Plugin name\n* Plugin version\n\n### Plugin Catalogs\n\nPlugin Framework contains a concept called \"Catalog\". A single assembly can be a catalog. A .NET type can be a catalog. Folders with dlls are often used as catalogs and Plugin Framework also supports Nuget packages, Nuget feeds and Roslyn scripts as Plugin catalogs. Multiple catalogs are often combined into a single Composite catalog.\n\nEach catalog contains 0-n plugins. \n\nPlugin Framework provides the following officially supported catalogs:\n\n* Type\n* Assembly\n* Folder\n* Delegate (Action or a Func) ([Documentation](https://github.com/weikio/PluginFramework/wiki/Delegate-Plugin-Catalog))\n* Roslyn script ([Nuget: Weikio.PluginFramework.Catalogs.Roslyn](https://www.nuget.org/packages/Weikio.PluginFramework.Catalogs.Roslyn/), [Documentation](https://github.com/weikio/PluginFramework/wiki/Roslyn-Plugin-Catalog))\n* Nuget package ([Nuget: Weikio.PluginFramework.Catalogs.Nuget](https://www.nuget.org/packages/Weikio.PluginFramework.Catalogs.Nuget/))\n* Nuget feed ([Nuget: Weikio.PluginFramework.Catalogs.Nuget](https://www.nuget.org/packages/Weikio.PluginFramework.Catalogs.Nuget/))\n\n## Source code\n\nSource code for Plugin Framework is available from [GitHub](https://github.com/weikio/PluginFramework).\n\n## Support & Build by\n\nPlugin Framework is build by [Adafy](https://adafy.com). Adafy also provides commercial support for the framework.\n\n![Adafy Logo](docs/Adafy_logo_256.png)\n\nAdafy is a Finnish software development house, focusing on Microsoft technologies.\n\n## Constributors\n\nThanks to the following contributors who have helped with the project:\n\n#### [@panoukos41](https://github.com/panoukos41)\n\n## License\n\nPlugin Framework is available as an open source, MIT-licensed project. "
  },
  {
    "path": "THIRD-PARTY-NOTICES.txt",
    "content": "Plugin Framework uses third-party libraries or other resources that may be\ndistributed under licenses different than the Plugin Framework software.\n\nIn the event that we accidentally failed to list a required notice, please\nbring it to our attention. Post an issue or email us:\n\n           info@weik.io\n\nLicense notice for Minver\n------------------------------------\n\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"{}\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright {yyyy} {name of copyright owner}\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\nLicense notice for ASP.NET Core\n------------------------------------\n\n  \n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License."
  },
  {
    "path": "global.json",
    "content": "{\n  \"sdk\": {\n    \"version\": \"6.0.420\"\n  }\n}"
  },
  {
    "path": "samples/BlazorApp/App.razor",
    "content": "﻿<Router AppAssembly=\"@typeof(Program).Assembly\">\n    <Found Context=\"routeData\">\n        <RouteView RouteData=\"@routeData\" DefaultLayout=\"@typeof(MainLayout)\"/>\n    </Found>\n    <NotFound>\n        <LayoutView Layout=\"@typeof(MainLayout)\">\n            <p>Sorry, there's nothing at this address.</p>\n        </LayoutView>\n    </NotFound>\n</Router>"
  },
  {
    "path": "samples/BlazorApp/BlazorApp.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n    <PropertyGroup>\n        <TargetFramework>netcoreapp3.1</TargetFramework>\n    </PropertyGroup>\n\n    <ItemGroup>\n      <ProjectReference Include=\"..\\..\\src\\Weikio.PluginFramework.AspNetCore\\Weikio.PluginFramework.AspNetCore.csproj\" />\n      <ProjectReference Include=\"..\\Shared\\Weikio.PluginFramework.Samples.Shared\\Weikio.PluginFramework.Samples.Shared.csproj\" />\n    </ItemGroup>\n\n    <ItemGroup>\n      <Content Update=\"Properties\\launchSettings.json\">\n        <CopyToPublishDirectory>Never</CopyToPublishDirectory>\n      </Content>\n    </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "samples/BlazorApp/Data/WeatherForecast.cs",
    "content": "using System;\n\nnamespace BlazorApp.Data\n{\n    public class WeatherForecast\n    {\n        public DateTime Date { get; set; }\n\n        public int TemperatureC { get; set; }\n\n        public int TemperatureF => 32 + (int) (TemperatureC / 0.5556);\n\n        public string Summary { get; set; }\n    }\n}\n"
  },
  {
    "path": "samples/BlazorApp/Data/WeatherForecastService.cs",
    "content": "using System;\nusing System.Linq;\nusing System.Threading.Tasks;\n\nnamespace BlazorApp.Data\n{\n    public class WeatherForecastService\n    {\n        private static readonly string[] Summaries = new[]\n        {\n            \"Freezing\", \"Bracing\", \"Chilly\", \"Cool\", \"Mild\", \"Warm\", \"Balmy\", \"Hot\", \"Sweltering\", \"Scorching\"\n        };\n\n        public Task<WeatherForecast[]> GetForecastAsync(DateTime startDate)\n        {\n            var rng = new Random();\n\n            return Task.FromResult(Enumerable.Range(1, 5).Select(index => new WeatherForecast\n            {\n                Date = startDate.AddDays(index), TemperatureC = rng.Next(-20, 55), Summary = Summaries[rng.Next(Summaries.Length)]\n            }).ToArray());\n        }\n    }\n}\n"
  },
  {
    "path": "samples/BlazorApp/Pages/Counter.razor",
    "content": "﻿@page \"/counter\"\n@implements Weikio.PluginFramework.Samples.Shared.IWidget\n\n<p>Current count: @currentCount</p>\n\n<button class=\"btn btn-primary\" @onclick=\"IncrementCount\">Click me</button>\n\n@code {\n    private int currentCount = 0;\n\n    private void IncrementCount()\n    {\n        currentCount++;\n    }\n\n    public string Title\n    {\n        get { return \"Counter Widget\"; }\n    }\n}"
  },
  {
    "path": "samples/BlazorApp/Pages/Error.razor",
    "content": "﻿@page \"/error\"\n\n\n<h1 class=\"text-danger\">Error.</h1>\n<h2 class=\"text-danger\">An error occurred while processing your request.</h2>\n\n<h3>Development Mode</h3>\n<p>\n    Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.\n</p>\n<p>\n    <strong>The Development environment shouldn't be enabled for deployed applications.</strong>\n    It can result in displaying sensitive information from exceptions to end users.\n    For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>\n    and restarting the app.\n</p>"
  },
  {
    "path": "samples/BlazorApp/Pages/FetchData.razor",
    "content": "﻿@page \"/fetchdata\"\n@implements Weikio.PluginFramework.Samples.Shared.IWidget\n\n@using BlazorApp.Data\n@inject WeatherForecastService ForecastService\n\n@if (forecasts == null)\n{\n    <p>\n        <em>Loading...</em>\n    </p>\n}\nelse\n{\n    <table class=\"table\">\n        <thead>\n        <tr>\n            <th>Date</th>\n            <th>Temp. (C)</th>\n            <th>Temp. (F)</th>\n            <th>Summary</th>\n        </tr>\n        </thead>\n        <tbody>\n        @foreach (var forecast in forecasts)\n        {\n            <tr>\n                <td>@forecast.Date.ToShortDateString()</td>\n                <td>@forecast.TemperatureC</td>\n                <td>@forecast.TemperatureF</td>\n                <td>@forecast.Summary</td>\n            </tr>\n        }\n        </tbody>\n    </table>\n}\n\n@code {\n    private WeatherForecast[] forecasts;\n\n    protected override async Task OnInitializedAsync()\n    {\n        forecasts = await ForecastService.GetForecastAsync(DateTime.Now);\n    }\n\n    public string Title { get; } = \"Weather forecasts\";\n}"
  },
  {
    "path": "samples/BlazorApp/Pages/Index.razor",
    "content": "﻿@page \"/\"\n@using Weikio.PluginFramework.Samples.Shared\n\n\n<h1>Widget dashboard</h1>\n<div class=\"row\">\n\n    @foreach (var widget in Widgets)\n    {\n        <div class=\"col-6\">\n            <div class=\"widget\">\n                <h1>@widget.Title</h1>\n                <hr/>\n                @RenderWidget(widget)\n            </div>\n        </div>\n    }\n</div>\n\n@code{\n\n    [Inject]\n    public IEnumerable<IWidget> Widgets { get; set; }\n\n    private RenderFragment RenderWidget(IWidget widget)\n    {\n        return new RenderFragment(builder =>\n        {\n            builder.OpenComponent(0, widget.GetType());\n            builder.CloseComponent();\n        });\n    }\n\n}"
  },
  {
    "path": "samples/BlazorApp/Pages/_Host.cshtml",
    "content": "﻿@page \"/\"\n@namespace BlazorApp.Pages\n@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers\n@{\n    Layout = null;\n}\n\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"utf-8\"/>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"/>\n    <title>BlazorApp</title>\n    <base href=\"~/\"/>\n    <link rel=\"stylesheet\" href=\"css/bootstrap/bootstrap.min.css\"/>\n    <link href=\"css/site.css\" rel=\"stylesheet\"/>\n</head>\n<body>\n<app>\n    <component type=\"typeof(App)\" render-mode=\"ServerPrerendered\"/>\n</app>\n\n<div id=\"blazor-error-ui\">\n    <environment include=\"Staging,Production\">\n        An error has occurred. This application may no longer respond until reloaded.\n    </environment>\n    <environment include=\"Development\">\n        An unhandled exception has occurred. See browser dev tools for details.\n    </environment>\n    <a href=\"\" class=\"reload\">Reload</a>\n    <a class=\"dismiss\">🗙</a>\n</div>\n\n<script src=\"_framework/blazor.server.js\"></script>\n</body>\n</html>"
  },
  {
    "path": "samples/BlazorApp/Program.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore;\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.Logging;\n\nnamespace BlazorApp\n{\n    public class Program\n    {\n        public static void Main(string[] args)\n        {\n            CreateHostBuilder(args).Build().Run();\n        }\n\n        public static IHostBuilder CreateHostBuilder(string[] args) =>\n            Host.CreateDefaultBuilder(args)\n                .ConfigureWebHostDefaults(webBuilder =>\n                {\n                    webBuilder.UseStartup<Startup>();\n                });\n    }\n}\n"
  },
  {
    "path": "samples/BlazorApp/Shared/MainLayout.razor",
    "content": "﻿@inherits LayoutComponentBase\n\n<div class=\"sidebar\">\n    <NavMenu/>\n</div>\n\n<div class=\"main\">\n    <div class=\"top-row px-4\">\n        <a href=\"https://docs.microsoft.com/aspnet/\" target=\"_blank\">About</a>\n    </div>\n\n    <div class=\"content px-4\">\n        @Body\n    </div>\n</div>"
  },
  {
    "path": "samples/BlazorApp/Shared/NavMenu.razor",
    "content": "﻿<div class=\"top-row pl-4 navbar navbar-dark\">\n    <a class=\"navbar-brand\" href=\"\">Plugin Framework</a>\n    <button class=\"navbar-toggler\" @onclick=\"ToggleNavMenu\">\n        <span class=\"navbar-toggler-icon\"></span>\n    </button>\n</div>\n\n<div class=\"@NavMenuCssClass\" @onclick=\"ToggleNavMenu\">\n    <ul class=\"nav flex-column\">\n        <li class=\"nav-item px-3\">\n            <NavLink class=\"nav-link\" href=\"\" Match=\"NavLinkMatch.All\">\n                <span class=\"oi oi-home\" aria-hidden=\"true\"></span> Dashboard\n            </NavLink>\n        </li>\n    </ul>\n</div>\n\n@code {\n    private bool collapseNavMenu = true;\n\n    private string NavMenuCssClass => collapseNavMenu ? \"collapse\" : null;\n\n    private void ToggleNavMenu()\n    {\n        collapseNavMenu = !collapseNavMenu;\n    }\n\n}"
  },
  {
    "path": "samples/BlazorApp/Shared/SurveyPrompt.razor",
    "content": "﻿@implements Weikio.PluginFramework.Samples.Shared.IWidget\n<div class=\"alert alert-secondary mt-4\" role=\"alert\">\n    <span class=\"oi oi-pencil mr-2\" aria-hidden=\"true\"></span>\n    <span class=\"text-nowrap\">\n        Please take our\n        <a target=\"_blank\" class=\"font-weight-bold\" href=\"https://go.microsoft.com/fwlink/?linkid=2112271\">brief survey</a>\n    </span>\n    and tell us what you think.\n</div>\n\n@code {\n    public string Title { get; } = \"Surveys\";\n}"
  },
  {
    "path": "samples/BlazorApp/Startup.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Components;\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.AspNetCore.HttpsPolicy;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing BlazorApp.Data;\nusing Microsoft.CodeAnalysis;\nusing Weikio.PluginFramework.Samples.Shared;\n\nnamespace BlazorApp\n{\n    public class Startup\n    {\n        public Startup(IConfiguration configuration)\n        {\n            Configuration = configuration;\n        }\n\n        public IConfiguration Configuration { get; }\n\n        // This method gets called by the runtime. Use this method to add services to the container.\n        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940\n        public void ConfigureServices(IServiceCollection services)\n        {\n            services.AddRazorPages();\n            services.AddServerSideBlazor();\n            services.AddSingleton<WeatherForecastService>();\n\n            services.AddPluginFramework<IWidget>();\n        }\n\n        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.\n        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)\n        {\n            if (env.IsDevelopment())\n            {\n                app.UseDeveloperExceptionPage();\n            }\n            else\n            {\n                app.UseExceptionHandler(\"/Error\");\n\n                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.\n                app.UseHsts();\n            }\n\n            app.UseHttpsRedirection();\n            app.UseStaticFiles();\n\n            app.UseRouting();\n\n            app.UseEndpoints(endpoints =>\n            {\n                endpoints.MapBlazorHub();\n                endpoints.MapFallbackToPage(\"/_Host\");\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "samples/BlazorApp/_Imports.razor",
    "content": "﻿@using System.Net.Http\n@using Microsoft.AspNetCore.Authorization\n@using Microsoft.AspNetCore.Components.Authorization\n@using Microsoft.AspNetCore.Components.Forms\n@using Microsoft.AspNetCore.Components.Routing\n@using Microsoft.AspNetCore.Components.Web\n@using Microsoft.JSInterop\n@using BlazorApp\n@using BlazorApp.Shared"
  },
  {
    "path": "samples/BlazorApp/appsettings.Development.json",
    "content": "{\n  \"DetailedErrors\": true,\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft\": \"Warning\",\n      \"Microsoft.Hosting.Lifetime\": \"Information\"\n    }\n  }\n}\n"
  },
  {
    "path": "samples/BlazorApp/appsettings.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft\": \"Warning\",\n      \"Microsoft.Hosting.Lifetime\": \"Information\"\n    }\n  },\n  \"AllowedHosts\": \"*\"\n}\n"
  },
  {
    "path": "samples/BlazorApp/wwwroot/css/open-iconic/FONT-LICENSE",
    "content": "SIL OPEN FONT LICENSE Version 1.1\n\nCopyright (c) 2014 Waybury\n\nPREAMBLE\nThe goals of the Open Font License (OFL) are to stimulate worldwide\ndevelopment of collaborative font projects, to support the font creation\nefforts of academic and linguistic communities, and to provide a free and\nopen framework in which fonts may be shared and improved in partnership\nwith others.\n\nThe OFL allows the licensed fonts to be used, studied, modified and\nredistributed freely as long as they are not sold by themselves. The\nfonts, including any derivative works, can be bundled, embedded,\nredistributed and/or sold with any software provided that any reserved\nnames are not used by derivative works. The fonts and derivatives,\nhowever, cannot be released under any other type of license. The\nrequirement for fonts to remain under this license does not apply\nto any document created using the fonts or their derivatives.\n\nDEFINITIONS\n\"Font Software\" refers to the set of files released by the Copyright\nHolder(s) under this license and clearly marked as such. This may\ninclude source files, build scripts and documentation.\n\n\"Reserved Font Name\" refers to any names specified as such after the\ncopyright statement(s).\n\n\"Original Version\" refers to the collection of Font Software components as\ndistributed by the Copyright Holder(s).\n\n\"Modified Version\" refers to any derivative made by adding to, deleting,\nor substituting -- in part or in whole -- any of the components of the\nOriginal Version, by changing formats or by porting the Font Software to a\nnew environment.\n\n\"Author\" refers to any designer, engineer, programmer, technical\nwriter or other person who contributed to the Font Software.\n\nPERMISSION & CONDITIONS\nPermission is hereby granted, free of charge, to any person obtaining\na copy of the Font Software, to use, study, copy, merge, embed, modify,\nredistribute, and sell modified and unmodified copies of the Font\nSoftware, subject to the following conditions:\n\n1) Neither the Font Software nor any of its individual components,\nin Original or Modified Versions, may be sold by itself.\n\n2) Original or Modified Versions of the Font Software may be bundled,\nredistributed and/or sold with any software, provided that each copy\ncontains the above copyright notice and this license. These can be\nincluded either as stand-alone text files, human-readable headers or\nin the appropriate machine-readable metadata fields within text or\nbinary files as long as those fields can be easily viewed by the user.\n\n3) No Modified Version of the Font Software may use the Reserved Font\nName(s) unless explicit written permission is granted by the corresponding\nCopyright Holder. This restriction only applies to the primary font name as\npresented to the users.\n\n4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font\nSoftware shall not be used to promote, endorse or advertise any\nModified Version, except to acknowledge the contribution(s) of the\nCopyright Holder(s) and the Author(s) or with their explicit written\npermission.\n\n5) The Font Software, modified or unmodified, in part or in whole,\nmust be distributed entirely under this license, and must not be\ndistributed under any other license. The requirement for fonts to\nremain under this license does not apply to any document created\nusing the Font Software.\n\nTERMINATION\nThis license becomes null and void if any of the above conditions are\nnot met.\n\nDISCLAIMER\nTHE FONT SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT\nOF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE\nCOPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nINCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL\nDAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM\nOTHER DEALINGS IN THE FONT SOFTWARE.\n"
  },
  {
    "path": "samples/BlazorApp/wwwroot/css/open-iconic/ICON-LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2014 Waybury\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE."
  },
  {
    "path": "samples/BlazorApp/wwwroot/css/open-iconic/README.md",
    "content": "[Open Iconic v1.1.1](http://useiconic.com/open)\n===========\n\n### 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&mdash;ready to use with Bootstrap and Foundation. [View the collection](http://useiconic.com/open#icons)\n\n\n\n## What's in Open Iconic?\n\n* 223 icons designed to be legible down to 8 pixels\n* Super-light SVG files - 61.8 for the entire set \n* SVG sprite&mdash;the modern replacement for icon fonts\n* Webfont (EOT, OTF, SVG, TTF, WOFF), PNG and WebP formats\n* Webfont stylesheets (including versions for Bootstrap and Foundation) in CSS, LESS, SCSS and Stylus formats\n* PNG and WebP raster images in 8px, 16px, 24px, 32px, 48px and 64px.\n\n\n## Getting Started\n\n#### 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.\n\n### General Usage\n\n#### Using Open Iconic's SVGs\n\nWe 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).\n\n```\n<img src=\"/open-iconic/svg/icon-name.svg\" alt=\"icon name\">\n```\n\n#### Using Open Iconic's SVG Sprite\n\nOpen 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.\n\nAdding 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* `<svg>` *tag and a unique class name for each different icon in the* `<use>` *tag.*  \n\n```\n<svg class=\"icon\">\n  <use xlink:href=\"open-iconic.svg#account-login\" class=\"icon-account-login\"></use>\n</svg>\n```\n\nSizing icons only needs basic CSS. All the icons are in a square format, so just set the `<svg>` tag with equal width and height dimensions.\n\n```\n.icon {\n  width: 16px;\n  height: 16px;\n}\n```\n\nColoring icons is even easier. All you need to do is set the `fill` rule on the `<use>` tag.\n\n```\n.icon-account-login {\n  fill: #f00;\n}\n```\n\nTo learn more about SVG Sprites, read [Chris Coyier's guide](http://css-tricks.com/svg-sprites-use-better-icon-fonts/).\n\n#### Using Open Iconic's Icon Font...\n\n\n##### …with Bootstrap\n\nYou can find our Bootstrap stylesheets in `font/css/open-iconic-bootstrap.{css, less, scss, styl}`\n\n\n```\n<link href=\"/open-iconic/font/css/open-iconic-bootstrap.css\" rel=\"stylesheet\">\n```\n\n\n```\n<span class=\"oi oi-icon-name\" title=\"icon name\" aria-hidden=\"true\"></span>\n```\n\n##### …with Foundation\n\nYou can find our Foundation stylesheets in `font/css/open-iconic-foundation.{css, less, scss, styl}`\n\n```\n<link href=\"/open-iconic/font/css/open-iconic-foundation.css\" rel=\"stylesheet\">\n```\n\n\n```\n<span class=\"fi-icon-name\" title=\"icon name\" aria-hidden=\"true\"></span>\n```\n\n##### …on its own\n\nYou can find our default stylesheets in `font/css/open-iconic.{css, less, scss, styl}`\n\n```\n<link href=\"/open-iconic/font/css/open-iconic.css\" rel=\"stylesheet\">\n```\n\n```\n<span class=\"oi\" data-glyph=\"icon-name\" title=\"icon name\" aria-hidden=\"true\"></span>\n```\n\n\n## License\n\n### Icons\n\nAll code (including SVG markup) is under the [MIT License](http://opensource.org/licenses/MIT).\n\n### Fonts\n\nAll fonts are under the [SIL Licensed](http://scripts.sil.org/cms/scripts/page.php?item_id=OFL_web).\n"
  },
  {
    "path": "samples/BlazorApp/wwwroot/css/site.css",
    "content": "@import url('open-iconic/font/css/open-iconic-bootstrap.min.css');\n\nhtml, body {\n    font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;\n}\n\na, .btn-link {\n    color: #0366d6;\n}\n\n.btn-primary {\n    color: #fff;\n    background-color: #1b6ec2;\n    border-color: #1861ac;\n}\n\napp {\n    position: relative;\n    display: flex;\n    flex-direction: column;\n}\n\n.top-row {\n    height: 3.5rem;\n    display: flex;\n    align-items: center;\n}\n\n.main {\n    flex: 1;\n}\n\n    .main .top-row {\n        background-color: #f7f7f7;\n        border-bottom: 1px solid #d6d5d5;\n        justify-content: flex-end;\n    }\n\n        .main .top-row > a, .main .top-row .btn-link {\n            white-space: nowrap;\n            margin-left: 1.5rem;\n        }\n\n.main .top-row a:first-child {\n    overflow: hidden;\n    text-overflow: ellipsis;\n}\n\n.sidebar {\n    background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);\n}\n\n    .sidebar .top-row {\n        background-color: rgba(0,0,0,0.4);\n    }\n\n    .sidebar .navbar-brand {\n        font-size: 1.1rem;\n    }\n\n    .sidebar .oi {\n        width: 2rem;\n        font-size: 1.1rem;\n        vertical-align: text-top;\n        top: -2px;\n    }\n\n    .sidebar .nav-item {\n        font-size: 0.9rem;\n        padding-bottom: 0.5rem;\n    }\n\n        .sidebar .nav-item:first-of-type {\n            padding-top: 1rem;\n        }\n\n        .sidebar .nav-item:last-of-type {\n            padding-bottom: 1rem;\n        }\n\n        .sidebar .nav-item a {\n            color: #d7d7d7;\n            border-radius: 4px;\n            height: 3rem;\n            display: flex;\n            align-items: center;\n            line-height: 3rem;\n        }\n\n            .sidebar .nav-item a.active {\n                background-color: rgba(255,255,255,0.25);\n                color: white;\n            }\n\n            .sidebar .nav-item a:hover {\n                background-color: rgba(255,255,255,0.1);\n                color: white;\n            }\n\n.content {\n    padding-top: 1.1rem;\n}\n\n.navbar-toggler {\n    background-color: rgba(255, 255, 255, 0.1);\n}\n\n.valid.modified:not([type=checkbox]) {\n    outline: 1px solid #26b050;\n}\n\n.invalid {\n    outline: 1px solid red;\n}\n\n.validation-message {\n    color: red;\n}\n\n#blazor-error-ui {\n    background: lightyellow;\n    bottom: 0;\n    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);\n    display: none;\n    left: 0;\n    padding: 0.6rem 1.25rem 0.7rem 1.25rem;\n    position: fixed;\n    width: 100%;\n    z-index: 1000;\n}\n\n#blazor-error-ui .dismiss {\n    cursor: pointer;\n    position: absolute;\n    right: 0.75rem;\n    top: 0.5rem;\n}\n\n@media (max-width: 767.98px) {\n    .main .top-row:not(.auth) {\n        display: none;\n    }\n\n    .main .top-row.auth {\n        justify-content: space-between;\n    }\n\n    .main .top-row a, .main .top-row .btn-link {\n        margin-left: 0;\n    }\n}\n\n@media (min-width: 768px) {\n    app {\n        flex-direction: row;\n    }\n\n    .sidebar {\n        width: 250px;\n        height: 100vh;\n        position: sticky;\n        top: 0;\n    }\n\n    .main .top-row {\n        position: sticky;\n        top: 0;\n    }\n\n    .main > div {\n        padding-left: 2rem !important;\n        padding-right: 1.5rem !important;\n    }\n\n    .navbar-toggler {\n        display: none;\n    }\n\n    .sidebar .collapse {\n        /* Never collapse the sidebar for wide screens */\n        display: block;\n    }\n}\n\n.widget {\n    border: 1px solid #ccc;\n    margin: 10px;\n    padding: 10px;\n}"
  },
  {
    "path": "samples/ConsoleApp/ConsoleApp.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n    <PropertyGroup>\n        <OutputType>Exe</OutputType>\n        <TargetFramework>netcoreapp3.1</TargetFramework>\n    </PropertyGroup>\n\n    <ItemGroup>\n      <ProjectReference Include=\"..\\..\\src\\Weikio.PluginFramework.Abstractions\\Weikio.PluginFramework.Abstractions.csproj\" />\n      <ProjectReference Include=\"..\\..\\src\\Weikio.PluginFramework\\Weikio.PluginFramework.csproj\" />\n      <ProjectReference Include=\"..\\Shared\\Weikio.PluginFramework.Samples.Shared\\Weikio.PluginFramework.Samples.Shared.csproj\" />\n    </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "samples/ConsoleApp/FirstPlugin.cs",
    "content": "﻿using System;\nusing Weikio.PluginFramework.Samples.Shared;\n\nnamespace ConsoleApp\n{\n    public class FirstPlugin : IPlugin\n    {\n        public void Run()\n        {\n            Console.WriteLine(\"First plugin\");\n        }\n    }\n}"
  },
  {
    "path": "samples/ConsoleApp/MyPlugin.cs",
    "content": "﻿using System;\nusing Weikio.PluginFramework.Samples.Shared;\n\nnamespace ConsoleApp\n{\n    public class MyPlugin : IMyPlugin\n    {\n        public void Run()\n        {\n            Console.WriteLine(\"My plugin which implements IMyPlugin\");\n        }\n    }\n}"
  },
  {
    "path": "samples/ConsoleApp/Program.cs",
    "content": "﻿using System;\nusing System.Threading.Tasks;\nusing Weikio.PluginFramework.Samples.Shared;\nusing Weikio.PluginFramework.Abstractions;\nusing Weikio.PluginFramework.Catalogs;\n\nnamespace ConsoleApp\n{\n    class Program\n    {\n        static async Task Main(string[] args)\n        {\n            await AssemblyCatalogSample();\n            await TypeCatalogSample();\n            await CompositeCatalogSample();\n        }\n\n        private static async Task AssemblyCatalogSample()\n        {\n            Console.WriteLine(\"Assembly catalog sample\");\n            \n            // 1. Create a new plugin catalog from the current assembly\n            var assemblyPluginCatalog = new AssemblyPluginCatalog(typeof(Program).Assembly, type => typeof(IPlugin).IsAssignableFrom(type));\n\n            // 2. Initialize the catalog\n            await assemblyPluginCatalog.Initialize();\n\n            // 3. Get the plugins from the catalog \n            var assemplyPlugins = assemblyPluginCatalog.GetPlugins();\n            \n            foreach (var plugin in assemplyPlugins)\n            {\n                var inst = (IPlugin) Activator.CreateInstance(plugin);\n                inst.Run();\n            }\n        }\n        \n        private static async Task TypeCatalogSample()\n        {\n            Console.WriteLine(\"Type catalog sample\");\n            \n            var typePluginCatalog = new TypePluginCatalog(typeof(FirstPlugin));\n            await typePluginCatalog.Initialize();\n\n            var typePlugin = typePluginCatalog.Get();\n            \n            var pluginInstance = (IPlugin) Activator.CreateInstance(typePlugin);\n            pluginInstance.Run();\n        }\n        \n        private static async Task CompositeCatalogSample()\n        {\n            Console.WriteLine(\"Composite catalog sample\");\n            \n            // 1. Create a new plugin catalog from the current assembly\n            var assemblyPluginCatalog = new AssemblyPluginCatalog(typeof(Program).Assembly, type => typeof(IPlugin).IsAssignableFrom(type));\n\n            // 2. Also create a new plugin catalog from a type\n            var typePluginCatalog = new TypePluginCatalog(typeof(MyPlugin));\n            \n            // 3. Then combine the catalogs into a composite catalog\n            var compositeCatalog = new CompositePluginCatalog(assemblyPluginCatalog, typePluginCatalog);\n            \n            // 4. Initialize the composite catalog\n            await compositeCatalog.Initialize();\n\n            // 5. Get the plugins from the catalog \n            var assemplyPlugins = compositeCatalog.GetPlugins();\n            \n            foreach (var plugin in assemplyPlugins)\n            {\n                if (plugin.Type.Name == \"MyPlugin\")\n                {\n                    var inst = (IMyPlugin) Activator.CreateInstance(plugin);\n                    inst.Run();\n                }\n                else\n                {\n                    var inst = (IPlugin) Activator.CreateInstance(plugin);\n                    inst.Run();\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "samples/ConsoleApp/SecondPlugin.cs",
    "content": "﻿using System;\nusing Weikio.PluginFramework.Samples.Shared;\n\nnamespace ConsoleApp\n{\n    public class SecondPlugin : IPlugin\n    {\n        public void Run()\n        {\n            Console.WriteLine(\"Second plugin\");\n        }\n    }\n}"
  },
  {
    "path": "samples/Shared/Weikio.PluginFramework.Samples.Shared/IMyPlugin.cs",
    "content": "﻿namespace Weikio.PluginFramework.Samples.Shared\n{\n    public interface IMyPlugin\n    {\n        void Run();\n    }\n}\n"
  },
  {
    "path": "samples/Shared/Weikio.PluginFramework.Samples.Shared/IOperator.cs",
    "content": "﻿namespace Weikio.PluginFramework.Samples.Shared\n{\n    public interface IOperator\n    {\n        int Calculate(int x, int y);\n    }\n}\n"
  },
  {
    "path": "samples/Shared/Weikio.PluginFramework.Samples.Shared/IPlugin.cs",
    "content": "﻿using System;\n\nnamespace Weikio.PluginFramework.Samples.Shared\n{\n    public interface IPlugin\n    {\n        void Run();\n    }\n    \n    public interface IOutPlugin\n    {\n        string Get();\n    }\n\n    public interface IWidget\n    {\n        string Title { get; }\n    }\n\n    public interface IDialog\n    {\n        void Show();\n    }\n}\n"
  },
  {
    "path": "samples/Shared/Weikio.PluginFramework.Samples.Shared/RemainderOperator.cs",
    "content": "﻿namespace Weikio.PluginFramework.Samples.Shared\n{\n    public class RemainderOperator : IOperator\n    {\n        public int Calculate(int x, int y)\n        {\n            return x % y;\n        }\n    }\n}\n"
  },
  {
    "path": "samples/Shared/Weikio.PluginFramework.Samples.Shared/Weikio.PluginFramework.Samples.Shared.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>netcoreapp3.1</TargetFramework>\n    <IsPackable>true</IsPackable>\n    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>\n    <Description>Plugin Framework shared sample</Description>\n    <PackageDescription>Plugin Framework shared sample</PackageDescription>\n    <Title>Plugin Framework shared sample</Title>\n    <PackageId>Weikio.PluginFramework.Samples.Shared</PackageId>\n    <Product>Weikio.PluginFramework.Samples.Shared</Product>\n    <AssemblyName>Weikio.PluginFramework.Samples.Shared</AssemblyName>\n    <PackageTags>plugins;addons;plugin framework;samples</PackageTags>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "samples/Shared/Weikio.PluginFramework.Samples.SharedPlugins/MinusOperator.cs",
    "content": "﻿using Weikio.PluginFramework.Samples.Shared;\n\nnamespace Weikio.PluginFramework.Samples.SharedPlugins\n{\n    public class MinusOperator : IOperator\n    {\n        public int Calculate(int x, int y)\n        {\n            return x - y;\n        }\n    }\n}"
  },
  {
    "path": "samples/Shared/Weikio.PluginFramework.Samples.SharedPlugins/MultiplyOperator.cs",
    "content": "﻿using System.ComponentModel;\nusing Weikio.PluginFramework.Samples.Shared;\n\nnamespace Weikio.PluginFramework.Samples.SharedPlugins\n{\n    [DisplayName(\"The multiplier plugin\")]\n    public class MultiplyOperator : IOperator\n    {\n        public int Calculate(int x, int y)\n        {\n            return x * y;\n        }\n    }\n}\n"
  },
  {
    "path": "samples/Shared/Weikio.PluginFramework.Samples.SharedPlugins/SecondSharedPlugin.cs",
    "content": "﻿using System;\nusing Weikio.PluginFramework.Samples.Shared;\n\nnamespace Weikio.PluginFramework.Samples.SharedPlugins\n{\n    public class SecondSharedPlugin : IOutPlugin\n    {\n        public string Get()\n        {\n            return \"Second shared plugin\";\n        }\n    }\n}\n"
  },
  {
    "path": "samples/Shared/Weikio.PluginFramework.Samples.SharedPlugins/SumOperator.cs",
    "content": "﻿using Weikio.PluginFramework.Samples.Shared;\n\nnamespace Weikio.PluginFramework.Samples.SharedPlugins\n{\n    public class SumOperator : IOperator\n    {\n        public int Calculate(int x, int y)\n        {\n            return x + y;\n        }\n    }\n}"
  },
  {
    "path": "samples/Shared/Weikio.PluginFramework.Samples.SharedPlugins/Weikio.PluginFramework.Samples.SharedPlugins.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>netcoreapp3.1</TargetFramework>\n    <IsPackable>true</IsPackable>\n    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>\n    <Description>Plugin Framework shared sample plugins</Description>\n    <PackageDescription>Plugin Framework shared sample plugins</PackageDescription>\n    <Title>Plugin Framework shared sample plugins</Title>\n    <PackageId>Weikio.PluginFramework.Samples.SharedPlugins</PackageId>\n    <Product>Weikio.PluginFramework.Samples.SharedPlugins</Product>\n    <AssemblyName>Weikio.PluginFramework.Samples.SharedPlugins</AssemblyName>\n    <PackageTags>plugins;addons;plugin framework;samples</PackageTags>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Weikio.PluginFramework.Samples.Shared\\Weikio.PluginFramework.Samples.Shared.csproj\"/>\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "samples/WebApp/Controllers/CalculatorController.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\nusing System.Text.Json;\nusing Microsoft.AspNetCore.Mvc;\nusing Weikio.PluginFramework.Samples.Shared;\nusing Weikio.PluginFramework.Abstractions;\n\nnamespace WebApp.Controllers\n{\n    [ApiController]\n    [Route(\"[controller]\")]\n    public class CalculatorController : ControllerBase\n    {\n        private readonly IEnumerable<IOperator> _operators;\n        private readonly IEnumerable<Plugin> _plugins;\n        private readonly IOperator _defaultOperator;\n\n        public CalculatorController(IEnumerable<IOperator> operators, IEnumerable<Plugin> plugins, IOperator defaultOperator)\n        {\n            _operators = operators;\n            _plugins = plugins;\n            _defaultOperator = defaultOperator;\n        }\n        \n        [HttpGet]\n        public string Get()\n        {\n            return JsonSerializer.Serialize(new\n            {\n                allPlugins = _plugins.Select(p => p.ToString()),\n                operators = _operators.Select(o => o.GetType().Name),\n                defaultOperator = _defaultOperator.GetType().Name\n            }, new JsonSerializerOptions { WriteIndented = true});\n        }\n    }\n}\n"
  },
  {
    "path": "samples/WebApp/Program.cs",
    "content": "using Microsoft.AspNetCore.Hosting;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Hosting;\n\nnamespace WebApp\n{\n    public class Program\n    {\n        public static void Main(string[] args)\n        {\n            CreateHostBuilder(args).Build().Run();\n        }\n\n        public static IHostBuilder CreateHostBuilder(string[] args) =>\n            Host.CreateDefaultBuilder(args)\n                .ConfigureWebHostDefaults(webBuilder =>\n                {\n                    webBuilder.UseStartup<Startup>();\n                });\n    }\n}\n"
  },
  {
    "path": "samples/WebApp/Startup.cs",
    "content": "using System.Collections.Generic;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Weikio.PluginFramework.Samples.Shared;\nusing Weikio.PluginFramework.Abstractions;\nusing Weikio.PluginFramework.AspNetCore;\nusing Weikio.PluginFramework.Catalogs;\nusing Weikio.PluginFramework.Samples.SharedPlugins;\n\nnamespace WebApp\n{\n    public class Startup\n    {\n        public Startup(IConfiguration configuration)\n        {\n            Configuration = configuration;\n        }\n\n        public IConfiguration Configuration { get; }\n\n        // This method gets called by the runtime. Use this method to add services to the container.\n        public void ConfigureServices(IServiceCollection services)\n        {\n            var folderPluginCatalog = new FolderPluginCatalog(@\"..\\Shared\\Weikio.PluginFramework.Samples.SharedPlugins\\bin\\debug\\netcoreapp3.1\", type =>\n            {\n                type.Implements<IOperator>();\n            });\n\n            services.AddPluginFramework()\n                .AddPluginCatalog(folderPluginCatalog)\n                .AddPluginType<IOperator>(configureDefault: option =>\n                {\n                    option.DefaultType = (provider, types) => typeof(SumOperator);\n                });\n\n            // Alternatively\n            // services.AddPluginFramework<IOperator>(@\"..\\Shared\\Weikio.PluginFramework.Samples.SharedPlugins\\bin\\debug\\netcoreapp3.1\");\n\n            // Default plugin type returned can be optionally configured with DefaultType function\n            //services.AddPluginFramework()\n            //    .AddPluginCatalog(folderPluginCatalog)\n            //    .AddPluginType<IOperator>(configureDefault: option =>\n            //    {\n            //        option.DefaultType = (serviceProvider, implementingTypes) => typeof(MultiplyOperator);\n            //    });\n\n            // Alternatively default plugin type can be also configured with Configure and provided with the same DefaultType function\n            //services.Configure<DefaultPluginOption>(nameof(IOperator), option =>\n            //    option.DefaultType = (serviceProvider, implementingTypes) => typeof(MultiplyOperator));\n\n            services.AddControllers();\n        }\n\n        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.\n        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)\n        {\n            if (env.IsDevelopment())\n            {\n                app.UseDeveloperExceptionPage();\n            }\n\n            app.UseHttpsRedirection();\n\n            app.UseRouting();\n\n            app.UseAuthorization();\n\n            app.UseEndpoints(endpoints =>\n            {\n                endpoints.MapControllers();\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "samples/WebApp/WebApp.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n    <PropertyGroup>\n        <TargetFramework>netcoreapp3.1</TargetFramework>\n    </PropertyGroup>\n\n    <ItemGroup>\n      <ProjectReference Include=\"..\\..\\src\\Weikio.PluginFramework.AspNetCore\\Weikio.PluginFramework.AspNetCore.csproj\" />\n      <ProjectReference Include=\"..\\Shared\\Weikio.PluginFramework.Samples.SharedPlugins\\Weikio.PluginFramework.Samples.SharedPlugins.csproj\" />\n      <ProjectReference Include=\"..\\Shared\\Weikio.PluginFramework.Samples.Shared\\Weikio.PluginFramework.Samples.Shared.csproj\" />\n    </ItemGroup>\n\n    <ItemGroup>\n      <Content Update=\"Properties\\launchSettings.json\">\n        <CopyToPublishDirectory>Never</CopyToPublishDirectory>\n      </Content>\n    </ItemGroup>\n\n\n</Project>\n"
  },
  {
    "path": "samples/WebApp/appsettings.Development.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft\": \"Warning\",\n      \"Microsoft.Hosting.Lifetime\": \"Information\"\n    }\n  }\n}\n"
  },
  {
    "path": "samples/WebApp/appsettings.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft\": \"Warning\",\n      \"Microsoft.Hosting.Lifetime\": \"Information\"\n    }\n  },\n  \"AllowedHosts\": \"*\"\n}\n"
  },
  {
    "path": "samples/WebAppPluginsLibrary/CustomPlugin.cs",
    "content": "﻿using System;\n\nnamespace WebAppPluginsLibrary\n{\n    public class CustomPlugin\n    {\n    }\n}\n"
  },
  {
    "path": "samples/WebAppPluginsLibrary/WebAppPluginsLibrary.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n    <PropertyGroup>\n        <TargetFramework>netstandard2.0</TargetFramework>\n    </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "samples/WebAppWithAppSettings/Controllers/CalculatorController.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Text;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.Extensions.DependencyInjection;\nusing Weikio.PluginFramework.Abstractions;\nusing Weikio.PluginFramework.AspNetCore;\nusing Weikio.PluginFramework.Samples.Shared;\n\nnamespace WebAppWithAppSettings.Controllers\n{\n    [ApiController]\n    [Route(\"[controller]\")]\n    public class CalculatorController : ControllerBase\n    {\n        private readonly IEnumerable<Plugin> _plugins;\n        private readonly IServiceProvider _serviceProvider;\n        private readonly PluginProvider _pluginProvider;\n\n        public CalculatorController(IEnumerable<Plugin> plugins, IServiceProvider serviceProvider, PluginProvider pluginProvider)\n        {\n            _plugins = plugins;\n            _serviceProvider = serviceProvider;\n            _pluginProvider = pluginProvider;\n        }\n        \n        [HttpGet]\n        public string Get()\n        {\n            var result = new StringBuilder();\n\n            result.AppendLine(\"All:\");\n            foreach (var plugin in _plugins)\n            {\n                result.AppendLine($\"{plugin.Name}: {plugin.Version}, Tags: {string.Join(\", \", plugin.Tags)}\");\n            }\n\n            var mathPlugins = _pluginProvider.GetByTag(\"MathOperator\");\n            var value1 = 10;\n            var value2 = 20;\n\n            result.AppendLine($\"Math operations with values {value1} and {value2}\");\n\n            foreach (var mathPlugin in mathPlugins)\n            {\n                var mathPluginInstance = _serviceProvider.Create<IOperator>(mathPlugin);\n                \n                var mathResult = mathPluginInstance.Calculate(value1, value2);\n                result.AppendLine($\"{mathPlugin.Name}: {mathResult}\");\n            }\n            \n            return result.ToString();\n        }\n    }\n}\n"
  },
  {
    "path": "samples/WebAppWithAppSettings/Program.cs",
    "content": "using Microsoft.AspNetCore.Hosting;\nusing Microsoft.Extensions.Hosting;\n\nnamespace WebAppWithAppSettings\n{\n    public class Program\n    {\n        public static void Main(string[] args)\n        {\n            CreateHostBuilder(args).Build().Run();\n        }\n\n        public static IHostBuilder CreateHostBuilder(string[] args) =>\n            Host.CreateDefaultBuilder(args)\n                .ConfigureWebHostDefaults(webBuilder =>\n                {\n                    webBuilder.UseStartup<Startup>();\n                });\n    }\n}\n"
  },
  {
    "path": "samples/WebAppWithAppSettings/Startup.cs",
    "content": "using Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Weikio.PluginFramework.Samples.Shared;\nusing Weikio.PluginFramework.TypeFinding;\n\nnamespace WebAppWithAppSettings\n{\n    public class Startup\n    {\n        public void ConfigureServices(IServiceCollection services)\n        {\n            TypeFinderOptions.Defaults.TypeFinderCriterias.Add(TypeFinderCriteriaBuilder.Create().Implements<IOperator>().Tag(\"MathOperator\"));\n            TypeFinderOptions.Defaults.TypeFinderCriterias.Add(TypeFinderCriteriaBuilder.Create().Tag(\"All\"));\n            services.AddPluginFramework();\n            \n            services.AddControllers();\n        }\n\n        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)\n        {\n            if (env.IsDevelopment())\n            {\n                app.UseDeveloperExceptionPage();\n            }\n\n            app.UseHttpsRedirection();\n\n            app.UseRouting();\n\n            app.UseAuthorization();\n\n            app.UseEndpoints(endpoints =>\n            {\n                endpoints.MapControllers();\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "samples/WebAppWithAppSettings/WebAppWithAppSettings.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n    <PropertyGroup>\n        <TargetFramework>netcoreapp3.1</TargetFramework>\n    </PropertyGroup>\n\n    <ItemGroup>\n      <ProjectReference Include=\"..\\..\\src\\Weikio.PluginFramework.AspNetCore\\Weikio.PluginFramework.AspNetCore.csproj\" />\n      <ProjectReference Include=\"..\\Shared\\Weikio.PluginFramework.Samples.SharedPlugins\\Weikio.PluginFramework.Samples.SharedPlugins.csproj\" />\n      <ProjectReference Include=\"..\\Shared\\Weikio.PluginFramework.Samples.Shared\\Weikio.PluginFramework.Samples.Shared.csproj\" />\n      <ProjectReference Include=\"..\\WebAppPluginsLibrary\\WebAppPluginsLibrary.csproj\" />\n    </ItemGroup>\n\n    <ItemGroup>\n      <Content Update=\"Properties\\launchSettings.json\">\n        <CopyToPublishDirectory>Never</CopyToPublishDirectory>\n      </Content>\n    </ItemGroup>\n\n\n</Project>\n"
  },
  {
    "path": "samples/WebAppWithAppSettings/appsettings.Development.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft\": \"Warning\",\n      \"Microsoft.Hosting.Lifetime\": \"Information\"\n    }\n  }\n}\n"
  },
  {
    "path": "samples/WebAppWithAppSettings/appsettings.json",
    "content": "{\n  \"PluginFramework\": {\n    \"Catalogs\": [\n      {\n        \"Type\": \"Folder\",\n        \"Path\": \"..\\\\Shared\\\\Weikio.PluginFramework.Samples.SharedPlugins\\\\bin\\\\debug\\\\netcoreapp3.1\"\n      },\n      {\n        \"Type\": \"Assembly\",\n        \"Path\": \".\\\\bin\\\\Debug\\\\netcoreapp3.1\\\\WebAppPluginsLibrary.dll\"\n      }\n    ]\n  }\n}\n"
  },
  {
    "path": "samples/WebAppWithDelegate/Controllers/DelegateController.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.Extensions.DependencyInjection;\nusing Weikio.PluginFramework.Abstractions;\n\nnamespace WebAppWithDelegate.Controllers\n{\n    [ApiController]\n    [Route(\"[controller]\")]\n    public class DelegateController : ControllerBase\n    {\n        private readonly IPluginCatalog _pluginCatalog;\n        private readonly IServiceProvider _sp;\n\n        public DelegateController(IPluginCatalog pluginCatalog, IServiceProvider serviceProvider)\n        {\n            _pluginCatalog = pluginCatalog;\n            _sp = serviceProvider;\n        }\n\n        [HttpGet]\n        public string Get()\n        {\n            var actionPlugin = _pluginCatalog.Get(\"MyActionPlugin\", Version.Parse(\"1.0.0.0\"));\n            var funcPlugin = _pluginCatalog.Get(\"MyFuncPlugin\", Version.Parse(\"1.0.0.0\"));\n            var funcExternalServicePlugin = _pluginCatalog.Get(\"MyExternalServicePlugin\", Version.Parse(\"1.0.0.0\"));\n\n            dynamic action = _sp.Create(actionPlugin);\n            dynamic func = _sp.Create(funcPlugin);\n            dynamic external = _sp.Create(funcExternalServicePlugin);\n\n            var s = new List<string>() { \"Hello from controller\" };\n            action.Run(s);\n\n            var result = func.Run(s);\n            \n            // Conversion rules are used to convert the func's string parameter into a property and to convert the ExternalService into a constructor parameter.\n            external.S = result;\n            result = external.Run();\n\n            return result;\n        }\n    }\n}\n"
  },
  {
    "path": "samples/WebAppWithDelegate/ExternalService.cs",
    "content": "﻿namespace WebAppWithDelegate\n{\n    public class ExternalService\n    {\n        public string GetWords()\n        {\n            return \"Hello from external service\";\n        }\n    }\n}\n"
  },
  {
    "path": "samples/WebAppWithDelegate/Program.cs",
    "content": "using Microsoft.AspNetCore.Hosting;\nusing Microsoft.Extensions.Hosting;\n\nnamespace WebAppWithDelegate\n{\n    public class Program\n    {\n        public static void Main(string[] args)\n        {\n            CreateHostBuilder(args).Build().Run();\n        }\n\n        public static IHostBuilder CreateHostBuilder(string[] args) =>\n            Host.CreateDefaultBuilder(args)\n                .ConfigureWebHostDefaults(webBuilder =>\n                {\n                    webBuilder.UseStartup<Startup>();\n                });\n    }\n}\n"
  },
  {
    "path": "samples/WebAppWithDelegate/Startup.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Reflection;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Weikio.PluginFramework.Catalogs;\nusing Weikio.PluginFramework.Catalogs.Delegates;\n\nnamespace WebAppWithDelegate\n{\n    public class Startup\n    {\n        // This method gets called by the runtime. Use this method to add services to the container.\n        public void ConfigureServices(IServiceCollection services)\n        {\n            // 1. Create a Plugin Catalog from an Action\n            var actionDelegate = new Action<List<string>>(s =>\n            {\n                s.Add(\"Hello from action\");\n            });\n            var actionCatalog = new DelegatePluginCatalog(actionDelegate, \"MyActionPlugin\");\n\n            // 2. Create an another catalog from a Func\n            var funcDelegate = new Func<List<string>, string>(s =>\n            {\n                s.Add(\"Hello from func\");\n\n                return string.Join(Environment.NewLine, s);\n            });\n            var funcCatalog = new DelegatePluginCatalog(funcDelegate, \"MyFuncPlugin\");\n\n            // 3. Create a third catalog to show how constructor injection and parameters can be used\n            var funcWithExternalService = new Func<string, ExternalService, string>((s, service) =>\n            {\n                var words = service.GetWords();\n\n                s = s + Environment.NewLine + words;\n\n                return s;\n            });\n\n            var funcWithExternalServiceCatalog = new DelegatePluginCatalog(funcWithExternalService, pluginName: \"MyExternalServicePlugin\",\n                // 4. Use conversion rules to indicate that ExternalService should be a constructor parameter and the string should be a property\n                conversionRules: new List<DelegateConversionRule>()\n                {\n                    // Rules can target parameter types\n                    new DelegateConversionRule(info => info.ParameterType == typeof(ExternalService), nfo => new ParameterConversion() { ToConstructor = true }),\n                    // Conversions based on the parameter names also work\n                    new DelegateConversionRule(info => info.Name == \"s\", nfo => new ParameterConversion() { ToPublicProperty = true }),\n                });\n\n            services.AddPluginFramework()\n                .AddPluginCatalog(new CompositePluginCatalog(actionCatalog, funcCatalog, funcWithExternalServiceCatalog));\n\n            services.AddSingleton<ExternalService>();\n            services.AddControllers();\n        }\n\n        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.\n        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)\n        {\n            if (env.IsDevelopment())\n            {\n                app.UseDeveloperExceptionPage();\n            }\n\n            app.UseHttpsRedirection();\n\n            app.UseRouting();\n\n            app.UseAuthorization();\n\n            app.UseEndpoints(endpoints =>\n            {\n                endpoints.MapControllers();\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "samples/WebAppWithDelegate/WebAppWithDelegate.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n  <PropertyGroup>\n    <TargetFramework>netcoreapp3.1</TargetFramework>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Weikio.PluginFramework.AspNetCore\\Weikio.PluginFramework.AspNetCore.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Newtonsoft.Json\" Version=\"12.0.3\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Content Update=\"Properties\\launchSettings.json\">\n      <CopyToPublishDirectory>Never</CopyToPublishDirectory>\n    </Content>\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "samples/WebAppWithDelegate/appsettings.Development.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft\": \"Warning\",\n      \"Microsoft.Hosting.Lifetime\": \"Information\"\n    }\n  }\n}\n"
  },
  {
    "path": "samples/WebAppWithDelegate/appsettings.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft\": \"Warning\",\n      \"Microsoft.Hosting.Lifetime\": \"Information\"\n    }\n  },\n  \"AllowedHosts\": \"*\"\n}\n"
  },
  {
    "path": "samples/WebAppWithNuget/Controllers/CalculatorController.cs",
    "content": "﻿using System.Collections.Generic;\nusing Microsoft.AspNetCore.Mvc;\nusing Weikio.PluginFramework.Abstractions;\nusing Weikio.PluginFramework.Samples.Shared;\n\nnamespace WebAppWithNuget.Controllers\n{\n    [ApiController]\n    [Route(\"[controller]\")]\n    public class CalculatorController : ControllerBase\n    {\n        private readonly IEnumerable<IOperator> _operators;\n        private readonly IEnumerable<Plugin> _plugins;\n\n        public CalculatorController(IEnumerable<IOperator> operators, IEnumerable<Plugin> plugins, IOperator myOperator)\n        {\n            _operators = operators;\n            _plugins = plugins;\n        }\n        \n        [HttpGet]\n        public string Get()\n        {\n            var pluginsList = string.Join(\", \", _plugins);\n\n            return pluginsList;\n        }\n    }\n}\n"
  },
  {
    "path": "samples/WebAppWithNuget/NugetLogger.cs",
    "content": "﻿using System.Threading.Tasks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing NuGet.Common;\nusing LogLevel = NuGet.Common.LogLevel;\n\nnamespace WebAppWithNuget\n{\n    public class NugetLogger : LoggerBase\n    {\n        private readonly ILogger<NugetLogger> _logger;\n\n        public NugetLogger(IServiceCollection serviceCollection)\n        {\n            var provider = serviceCollection.BuildServiceProvider();\n            _logger = (ILogger<NugetLogger>) provider.GetService(typeof(ILogger<NugetLogger>));\n        }\n\n        public override void Log(ILogMessage message)\n        {\n            switch (message.Level)\n            {\n                case LogLevel.Debug:\n                    _logger.LogDebug(message.ToString());\n                    break;\n\n                case LogLevel.Verbose:\n                    _logger.LogTrace(message.ToString());\n                    break;\n\n                case LogLevel.Information:\n                    _logger.LogInformation(message.ToString());\n                    break;\n\n                case LogLevel.Minimal:\n                    _logger.LogTrace(message.ToString());\n                    break;\n\n                case LogLevel.Warning:\n                    _logger.LogWarning(message.ToString());\n                    break;\n\n                case LogLevel.Error:\n                    _logger.LogError(message.ToString());\n                    break;\n            }\n        }\n\n        public override Task LogAsync(ILogMessage message)\n        {\n            Log(message);\n\n            return Task.CompletedTask;\n        }\n    }\n}\n"
  },
  {
    "path": "samples/WebAppWithNuget/Program.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.Logging;\n\nnamespace WebAppWithNuget\n{\n    public class Program\n    {\n        public static void Main(string[] args)\n        {\n            CreateHostBuilder(args).Build().Run();\n        }\n\n        public static IHostBuilder CreateHostBuilder(string[] args) =>\n            Host.CreateDefaultBuilder(args)\n                .ConfigureWebHostDefaults(webBuilder =>\n                {\n                    webBuilder.UseStartup<Startup>();\n                });\n    }\n}\n"
  },
  {
    "path": "samples/WebAppWithNuget/Startup.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.AspNetCore.HttpsPolicy;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.Logging;\nusing Weikio.PluginFramework.Catalogs;\nusing Weikio.PluginFramework.Catalogs.NuGet;\nusing Weikio.PluginFramework.Samples.Shared;\n\nnamespace WebAppWithNuget\n{\n    public class Startup\n    {\n        public Startup(IConfiguration configuration)\n        {\n            Configuration = configuration;\n        }\n\n        public IConfiguration Configuration { get; }\n\n        // This method gets called by the runtime. Use this method to add services to the container.\n        public void ConfigureServices(IServiceCollection services)\n        {\n            NugetPluginCatalogOptions.Defaults.LoggerFactory = () => new NugetLogger(services);\n\n            var options = new NugetPluginCatalogOptions\n            {\n                ForcePackageCaching = true, \n                CustomPackagesFolder = Path.Combine(Path.GetTempPath(), \"NugetPackagePluginCatalog\", \"Sample\")\n            };\n\n            var nugetCatalog = new NugetPackagePluginCatalog(\"Weikio.PluginFramework.Samples.SharedPlugins\", includePrerelease: true, configureFinder: finder =>\n            {\n                finder.Implements<IOperator>();\n            }, options: options);\n\n            services.AddPluginFramework()\n                .AddPluginCatalog(nugetCatalog)\n                .AddPluginType<IOperator>();\n\n            services.AddControllers();\n        }\n\n        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.\n        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)\n        {\n            if (env.IsDevelopment())\n            {\n                app.UseDeveloperExceptionPage();\n            }\n\n            app.UseHttpsRedirection();\n\n            app.UseRouting();\n\n            app.UseAuthorization();\n\n            app.UseEndpoints(endpoints =>\n            {\n                endpoints.MapControllers();\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "samples/WebAppWithNuget/WebAppWithNuget.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n    <PropertyGroup>\n        <TargetFramework>netcoreapp3.1</TargetFramework>\n    </PropertyGroup>\n\n    <ItemGroup>\n      <ProjectReference Include=\"..\\..\\src\\Weikio.PluginFramework.AspNetCore\\Weikio.PluginFramework.AspNetCore.csproj\" />\n      <ProjectReference Include=\"..\\..\\src\\Weikio.PluginFramework.Catalogs.NuGet\\Weikio.PluginFramework.Catalogs.NuGet.csproj\" />\n      <ProjectReference Include=\"..\\Shared\\Weikio.PluginFramework.Samples.Shared\\Weikio.PluginFramework.Samples.Shared.csproj\" />\n    </ItemGroup>\n\n\n</Project>\n"
  },
  {
    "path": "samples/WebAppWithNuget/appsettings.Development.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft\": \"Warning\",\n      \"Microsoft.Hosting.Lifetime\": \"Information\"\n    }\n  }\n}\n"
  },
  {
    "path": "samples/WebAppWithNuget/appsettings.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft\": \"Warning\",\n      \"Microsoft.Hosting.Lifetime\": \"Information\"\n    }\n  },\n  \"AllowedHosts\": \"*\"\n}\n"
  },
  {
    "path": "samples/WebAppWithRoslyn/Controllers/RoslynController.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.Extensions.DependencyInjection;\nusing Weikio.PluginFramework.Abstractions;\n\nnamespace WebAppWithRoslyn.Controllers\n{\n    [ApiController]\n    [Route(\"[controller]\")]\n    public class RoslynController : ControllerBase\n    {\n        private readonly IPluginCatalog _pluginCatalog;\n        private readonly IServiceProvider _sp;\n\n        public RoslynController(IPluginCatalog pluginCatalog, IServiceProvider sp)\n        {\n            _pluginCatalog = pluginCatalog;\n            _sp = sp;\n        }\n        \n        [HttpGet]\n        public async Task<string> Get()\n        {\n            var scriptPlugin = _pluginCatalog.GetPlugins().First();\n                \n            dynamic scriptInstance = Activator.CreateInstance(scriptPlugin);\n            var scriptResult = await scriptInstance.Run();\n\n            var typePlugin = _pluginCatalog.Get(\"MyPlugin\", Version.Parse(\"1.5.0.0\"));\n\n            dynamic typeInstance = typePlugin.Create(_sp);\n            \n            var typeResult = typeInstance.RunThings();\n            \n            var result = new StringBuilder();\n            result.AppendLine(scriptResult);\n            result.AppendLine(typeResult);\n\n            return result.ToString();\n        }\n    }\n}\n"
  },
  {
    "path": "samples/WebAppWithRoslyn/ExternalService.cs",
    "content": "﻿namespace WebAppWithRoslyn\n{\n    public class ExternalService\n    {\n        public string DoWork()\n        {\n            return \"External service did some work\";\n        }\n    }\n}\n"
  },
  {
    "path": "samples/WebAppWithRoslyn/Program.cs",
    "content": "using Microsoft.AspNetCore.Hosting;\nusing Microsoft.Extensions.Hosting;\n\nnamespace WebAppWithRoslyn\n{\n    public class Program\n    {\n        public static void Main(string[] args)\n        {\n            CreateHostBuilder(args).Build().Run();\n        }\n\n        public static IHostBuilder CreateHostBuilder(string[] args) =>\n            Host.CreateDefaultBuilder(args)\n                .ConfigureWebHostDefaults(webBuilder =>\n                {\n                    webBuilder.UseStartup<Startup>();\n                });\n    }\n}\n"
  },
  {
    "path": "samples/WebAppWithRoslyn/Startup.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Reflection;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Weikio.PluginFramework.Catalogs;\nusing Weikio.PluginFramework.Catalogs.Roslyn;\n\nnamespace WebAppWithRoslyn\n{\n    public class Startup\n    {\n        public Startup(IConfiguration configuration)\n        {\n            Configuration = configuration;\n        }\n\n        public IConfiguration Configuration { get; }\n\n        // This method gets called by the runtime. Use this method to add services to the container.\n        public void ConfigureServices(IServiceCollection services)\n        {\n            // First we create a Roslyn Plugin Catalog which uses the scripting version of C#/Roslyn\n            var script = \"var x = \\\"Hello from Roslyn Plugin\\\"; return x;\";\n            var roslynScriptCatalog = new RoslynPluginCatalog(script);\n\n            // We also create an another Roslyn Plugin Catalog to show how to create a plugin from a class. \n            // This catalog also uses dependency injection, external references and additional namespaces.\n            var code = @\"public class MyClass\n                   {\n                       private ExternalService _service;\n                       public MyClass(ExternalService service)\n                       {\n                            _service = service;\n                       } \n\n                       public string RunThings()\n                       {\n                            var result = JsonConvert.SerializeObject(15);\n                            result += _service.DoWork();\n                            return result; \n                       }\n                   }\";\n\n            var options = new RoslynPluginCatalogOptions()\n            {\n                PluginName = \"MyPlugin\",\n                PluginVersion = new Version(\"1.5.0.0\"),\n                AdditionalReferences = new List<Assembly>() { typeof(Newtonsoft.Json.JsonConvert).Assembly, typeof(ExternalService).Assembly },\n                AdditionalNamespaces = new List<string>() { \"Newtonsoft.Json\", \"WebAppWithRoslyn\" }\n            };\n            \n            var roslynCodeCatalog = new RoslynPluginCatalog(code, options);\n\n            services.AddPluginFramework()\n                .AddPluginCatalog(new CompositePluginCatalog(roslynScriptCatalog, roslynCodeCatalog));\n\n            services.AddSingleton<ExternalService>();\n            services.AddControllers();\n        }\n\n        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.\n        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)\n        {\n            if (env.IsDevelopment())\n            {\n                app.UseDeveloperExceptionPage();\n            }\n\n            app.UseHttpsRedirection();\n\n            app.UseRouting();\n\n            app.UseAuthorization();\n\n            app.UseEndpoints(endpoints =>\n            {\n                endpoints.MapControllers();\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "samples/WebAppWithRoslyn/WebAppWithRoslyn.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n  <PropertyGroup>\n    <TargetFramework>netcoreapp3.1</TargetFramework>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Weikio.PluginFramework.AspNetCore\\Weikio.PluginFramework.AspNetCore.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\Weikio.PluginFramework.Catalogs.Roslyn\\Weikio.PluginFramework.Catalogs.Roslyn.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Newtonsoft.Json\" Version=\"12.0.3\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Content Update=\"Properties\\launchSettings.json\">\n      <CopyToPublishDirectory>Never</CopyToPublishDirectory>\n    </Content>\n  </ItemGroup>\n\n\n</Project>\n"
  },
  {
    "path": "samples/WebAppWithRoslyn/appsettings.Development.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft\": \"Warning\",\n      \"Microsoft.Hosting.Lifetime\": \"Information\"\n    }\n  }\n}\n"
  },
  {
    "path": "samples/WebAppWithRoslyn/appsettings.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft\": \"Warning\",\n      \"Microsoft.Hosting.Lifetime\": \"Information\"\n    }\n  },\n  \"AllowedHosts\": \"*\"\n}\n"
  },
  {
    "path": "samples/WinFormsApp/DivideOperator.cs",
    "content": "﻿using Weikio.PluginFramework.Samples.Shared;\n\nnamespace WinFormsApp\n{\n    public class DivideOperator : IOperator\n    {\n        public int Calculate(int x, int y)\n        {\n            return x / y;\n        }\n    }\n}\n"
  },
  {
    "path": "samples/WinFormsApp/Form1.Designer.cs",
    "content": "﻿namespace WinFormsApp\n{\n    partial class Form1\n    {\n        /// <summary>\n        ///  Required designer variable.\n        /// </summary>\n        private System.ComponentModel.IContainer components = null;\n\n        /// <summary>\n        ///  Clean up any resources being used.\n        /// </summary>\n        /// <param name=\"disposing\">true if managed resources should be disposed; otherwise, false.</param>\n        protected override void Dispose(bool disposing)\n        {\n            if (disposing && (components != null))\n            {\n                components.Dispose();\n            }\n\n            base.Dispose(disposing);\n        }\n\n        #region Windows Form Designer generated code\n\n        /// <summary>\n        /// Required method for Designer support - do not modify\n        /// the contents of this method with the code editor.\n        /// </summary>\n        private void InitializeComponent()\n        {\n            this.listBox1 = new System.Windows.Forms.ListBox();\n            this.button1 = new System.Windows.Forms.Button();\n            this.textBox1 = new System.Windows.Forms.TextBox();\n            this.label1 = new System.Windows.Forms.Label();\n            this.menuStrip1 = new System.Windows.Forms.MenuStrip();\n            this.dialogPluginsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.menuStrip1.SuspendLayout();\n            this.SuspendLayout();\n\n            // \n            // listBox1\n            // \n            this.listBox1.FormattingEnabled = true;\n            this.listBox1.Location = new System.Drawing.Point(12, 123);\n            this.listBox1.Name = \"listBox1\";\n            this.listBox1.Size = new System.Drawing.Size(438, 277);\n            this.listBox1.TabIndex = 0;\n\n            // \n            // button1\n            // \n            this.button1.Location = new System.Drawing.Point(12, 414);\n            this.button1.Name = \"button1\";\n            this.button1.Size = new System.Drawing.Size(102, 24);\n            this.button1.TabIndex = 1;\n            this.button1.Text = \"Run Plugin\";\n            this.button1.UseVisualStyleBackColor = true;\n            this.button1.Click += new System.EventHandler(this.button1_Click);\n\n            // \n            // textBox1\n            // \n            this.textBox1.Location = new System.Drawing.Point(120, 414);\n            this.textBox1.Multiline = true;\n            this.textBox1.Name = \"textBox1\";\n            this.textBox1.Size = new System.Drawing.Size(330, 24);\n            this.textBox1.TabIndex = 2;\n\n            // \n            // label1\n            // \n            this.label1.Location = new System.Drawing.Point(12, 101);\n            this.label1.Name = \"label1\";\n            this.label1.Size = new System.Drawing.Size(98, 19);\n            this.label1.TabIndex = 3;\n            this.label1.Text = \"Plugins:\";\n\n            // \n            // menuStrip1\n            // \n            this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.dialogPluginsToolStripMenuItem });\n            this.menuStrip1.Location = new System.Drawing.Point(0, 0);\n            this.menuStrip1.Name = \"menuStrip1\";\n            this.menuStrip1.Size = new System.Drawing.Size(462, 24);\n            this.menuStrip1.TabIndex = 4;\n            this.menuStrip1.Text = \"menuStrip1\";\n\n            // \n            // dialogPluginsToolStripMenuItem\n            // \n            this.dialogPluginsToolStripMenuItem.Name = \"dialogPluginsToolStripMenuItem\";\n            this.dialogPluginsToolStripMenuItem.Size = new System.Drawing.Size(104, 20);\n            this.dialogPluginsToolStripMenuItem.Text = \"Dialog Plugins...\";\n\n            // \n            // Form1\n            // \n            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);\n            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;\n            this.ClientSize = new System.Drawing.Size(462, 450);\n            this.Controls.Add(this.label1);\n            this.Controls.Add(this.textBox1);\n            this.Controls.Add(this.button1);\n            this.Controls.Add(this.listBox1);\n            this.Controls.Add(this.menuStrip1);\n            this.MainMenuStrip = this.menuStrip1;\n            this.Name = \"Form1\";\n            this.Text = \"Form1\";\n            this.Load += new System.EventHandler(this.Form1_Load);\n            this.menuStrip1.ResumeLayout(false);\n            this.menuStrip1.PerformLayout();\n            this.ResumeLayout(false);\n            this.PerformLayout();\n        }\n\n        private System.Windows.Forms.ToolStripMenuItem dialogPluginsToolStripMenuItem;\n        private System.Windows.Forms.MenuStrip menuStrip1;\n\n        private System.Windows.Forms.Button button1;\n        private System.Windows.Forms.Label label1;\n        private System.Windows.Forms.ListBox listBox1;\n        private System.Windows.Forms.TextBox textBox1;\n\n        #endregion\n    }\n}\n"
  },
  {
    "path": "samples/WinFormsApp/Form1.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing System.Windows.Forms;\nusing Weikio.PluginFramework.Abstractions;\nusing Weikio.PluginFramework.Catalogs;\nusing Weikio.PluginFramework.Catalogs.Delegates;\nusing Weikio.PluginFramework.Samples.Shared;\nusing Weikio.PluginFramework.TypeFinding;\n\nnamespace WinFormsApp\n{\n    public partial class Form1 : Form\n    {\n        private CompositePluginCatalog _allPlugins = new CompositePluginCatalog();\n\n        public Form1()\n        {\n            InitializeComponent();\n        }\n\n        private async void Form1_Load(object sender, EventArgs e)\n        {\n            // Demonstrates how tags can be used with Plugin Framework.\n            // Single _allPlugins catalog is created from multiple different catalogs. All the plugins are tagged.\n            await CreateCatalogs();\n            \n            // 1. Adds calculation operators using tag 'operator'\n            AddCalculationOperators();\n\n            // 2. Adds dialogs using 'dialog' tag\n            AddDialogs();\n\n            // 3. Adds buttons using 'button' tag\n            AddButtons();\n        }\n\n        private async Task CreateCatalogs()\n        {\n            // 1. Uses folder catalog to add calculation operations inside the app. Mimics the WPF-sample.\n            var folderPluginCatalog = new FolderPluginCatalog(@\"..\\..\\..\\..\\Shared\\Weikio.PluginFramework.Samples.SharedPlugins\\bin\\debug\\netcoreapp3.1\",\n                type => { type.Implements<IOperator>().Tag(\"operator\"); });\n            \n            _allPlugins.AddCatalog(folderPluginCatalog);\n            \n            var assemblyPluginCatalog = new AssemblyPluginCatalog(typeof(Form1).Assembly, builder =>\n            {\n                builder.Implements<IOperator>()\n                    .Tag(\"operator\");\n            });\n            \n            _allPlugins.AddCatalog(assemblyPluginCatalog);\n            \n            // 2. Another folder catalog is used to add other forms inside the app. For each form a button is added into the toolstrip\n            // Note: WinFormsPluginsLibrary must be manually built as it isn't referenced by this sample app\n            var folderCatalog = new FolderPluginCatalog(@\"..\\..\\..\\..\\WinFormsPluginsLibrary\\bin\\debug\\netcoreapp3.1\",\n                type =>\n                {\n                    type.Implements<IDialog>()\n                        .Tag(\"dialog\");\n                });\n            \n            _allPlugins.AddCatalog(folderCatalog);\n            \n            // 3. Lastly, DelegateCatalog is used for creating an exit-button\n            var exitAction = new Action(() =>\n            {\n                var result = MessageBox.Show(\"This is also a plugin. Do you want to exit this sample app?\", \"Exit App?\", MessageBoxButtons.YesNo);\n            \n                if (result == DialogResult.No)\n                {\n                    return;\n                }\n            \n                Application.Exit();\n            });\n            \n            var exitCatalog = new DelegatePluginCatalog(exitAction, options: new DelegatePluginCatalogOptions(){Tags = new List<string> { \"buttons\" }} , pluginName: \"Exit\" );\n            _allPlugins.AddCatalog(exitCatalog);\n\n            // Finally the plugin catalog is initialized\n            await _allPlugins.Initialize();\n        }\n        \n        private void AddCalculationOperators()\n        {\n            var allPlugins = _allPlugins.GetByTag(\"operator\");\n            foreach (var plugin in allPlugins)\n            {\n                listBox1.Items.Add(plugin);\n            }\n        }\n\n        private void AddDialogs()\n        {\n            var dialogPlugins = _allPlugins.GetByTag(\"dialog\");\n            \n            foreach (var dialogPlugin in dialogPlugins)\n            {\n                var menuItem = new ToolStripButton(dialogPlugin.Name, null, (o, args) =>\n                {\n                    var instance = (IDialog) Activator.CreateInstance(dialogPlugin);\n                    instance.Show();\n                });\n\n                dialogPluginsToolStripMenuItem.DropDownItems.Add(menuItem);\n            }\n        }\n\n        private void AddButtons()\n        {\n            var buttonPlugins = _allPlugins.GetByTag(\"buttons\");\n\n            foreach (var buttonPlugin in buttonPlugins)\n            {\n                menuStrip1.Items.Add(new ToolStripButton(buttonPlugin.Name, null, (sender, args) =>\n                {\n                    dynamic instance = Activator.CreateInstance(buttonPlugin);\n                    instance.Run();\n                }));\n            }\n        }\n\n        private void button1_Click(object sender, EventArgs e)\n        {\n            var selectedPlugin = listBox1.SelectedItem as Plugin;\n\n            if (selectedPlugin == null)\n            {\n                return;\n            }\n\n            var instance = (IOperator) Activator.CreateInstance(selectedPlugin);\n\n            var result = instance.Calculate(20, 10);\n\n            textBox1.Text = result.ToString();\n        }\n    }\n}\n"
  },
  {
    "path": "samples/WinFormsApp/Form1.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <metadata name=\"menuStrip1.TrayLocation\" type=\"System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n    <value>17, 17</value>\n  </metadata>\n</root>"
  },
  {
    "path": "samples/WinFormsApp/Program.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing System.Windows.Forms;\nusing Weikio.PluginFramework.Context;\n\nnamespace WinFormsApp\n{\n    static class Program\n    {\n        /// <summary>\n        ///  The main entry point for the application.\n        /// </summary>\n        [STAThread]\n        static void Main()\n        {\n            Application.SetHighDpiMode(HighDpiMode.SystemAware);\n            Application.EnableVisualStyles();\n            Application.SetCompatibleTextRenderingDefault(false);\n            Application.Run(new Form1());\n        }\n    }\n}\n"
  },
  {
    "path": "samples/WinFormsApp/WinFormsApp.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk.WindowsDesktop\">\n\n    <PropertyGroup>\n        <OutputType>WinExe</OutputType>\n        <TargetFramework>netcoreapp3.1</TargetFramework>\n        <UseWindowsForms>true</UseWindowsForms>\n    </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Weikio.PluginFramework\\Weikio.PluginFramework.csproj\" />\n    <ProjectReference Include=\"..\\Shared\\Weikio.PluginFramework.Samples.Shared\\Weikio.PluginFramework.Samples.Shared.csproj\" />\n  </ItemGroup>\n  \n</Project>"
  },
  {
    "path": "samples/WinFormsPluginsLibrary/LabelPlugin.Designer.cs",
    "content": "﻿using System.ComponentModel;\nusing System.Drawing;\n\nnamespace WinFormsPluginsLibrary\n{\n    partial class LabelPlugin\n    {\n        /// <summary>\n        /// Required designer variable.\n        /// </summary>\n        private IContainer components = null;\n\n        /// <summary>\n        /// Clean up any resources being used.\n        /// </summary>\n        /// <param name=\"disposing\">true if managed resources should be disposed; otherwise, false.</param>\n        protected override void Dispose(bool disposing)\n        {\n            if (disposing && (components != null))\n            {\n                components.Dispose();\n            }\n\n            base.Dispose(disposing);\n        }\n\n        #region Windows Form Designer generated code\n\n        /// <summary>\n        /// Required method for Designer support - do not modify\n        /// the contents of this method with the code editor.\n        /// </summary>\n        private void InitializeComponent()\n        {\n            this.button1 = new System.Windows.Forms.Button();\n            this.label1 = new System.Windows.Forms.Label();\n            this.SuspendLayout();\n\n            // \n            // button1\n            // \n            this.button1.Location = new System.Drawing.Point(105, 12);\n            this.button1.Name = \"button1\";\n            this.button1.Size = new System.Drawing.Size(110, 50);\n            this.button1.TabIndex = 0;\n            this.button1.Text = \"Update Label\";\n            this.button1.UseVisualStyleBackColor = true;\n            this.button1.Click += new System.EventHandler(this.button1_Click);\n\n            // \n            // label1\n            // \n            this.label1.Location = new System.Drawing.Point(90, 88);\n            this.label1.Name = \"label1\";\n            this.label1.Size = new System.Drawing.Size(125, 36);\n            this.label1.TabIndex = 1;\n\n            // \n            // LabelPlugin\n            // \n            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);\n            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;\n            this.ClientSize = new System.Drawing.Size(313, 184);\n            this.Controls.Add(this.label1);\n            this.Controls.Add(this.button1);\n            this.Name = \"LabelPlugin\";\n            this.Text = \"LabelPlugin\";\n            this.ResumeLayout(false);\n        }\n\n        private System.Windows.Forms.Label label1;\n\n        private System.Windows.Forms.Button button1;\n\n        #endregion\n    }\n}\n\n"
  },
  {
    "path": "samples/WinFormsPluginsLibrary/LabelPlugin.cs",
    "content": "﻿using System;\nusing System.ComponentModel;\nusing System.Windows.Forms;\nusing Weikio.PluginFramework.Samples.Shared;\n\nnamespace WinFormsPluginsLibrary\n{\n    public partial class LabelPlugin : Form, IDialog\n    {\n        public LabelPlugin()\n        {\n            InitializeComponent();\n        }\n\n        private void button1_Click(object sender, EventArgs e)\n        {\n            label1.Text = \"Another simple example\";\n        }\n    }\n}\n\n"
  },
  {
    "path": "samples/WinFormsPluginsLibrary/LabelPlugin.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n</root>"
  },
  {
    "path": "samples/WinFormsPluginsLibrary/TestPlugin.Designer.cs",
    "content": "﻿using System.ComponentModel;\n\nnamespace WinFormsPluginsLibrary\n{\n    partial class TestPlugin\n    {\n        /// <summary>\n        /// Required designer variable.\n        /// </summary>\n        private IContainer components = null;\n\n        /// <summary>\n        /// Clean up any resources being used.\n        /// </summary>\n        /// <param name=\"disposing\">true if managed resources should be disposed; otherwise, false.</param>\n        protected override void Dispose(bool disposing)\n        {\n            if (disposing && (components != null))\n            {\n                components.Dispose();\n            }\n\n            base.Dispose(disposing);\n        }\n\n        #region Windows Form Designer generated code\n\n        /// <summary>\n        /// Required method for Designer support - do not modify\n        /// the contents of this method with the code editor.\n        /// </summary>\n        private void InitializeComponent()\n        {\n            this.button1 = new System.Windows.Forms.Button();\n            this.SuspendLayout();\n\n            // \n            // button1\n            // \n            this.button1.Location = new System.Drawing.Point(118, 86);\n            this.button1.Name = \"button1\";\n            this.button1.Size = new System.Drawing.Size(202, 42);\n            this.button1.TabIndex = 0;\n            this.button1.Text = \"Say Hello\";\n            this.button1.UseVisualStyleBackColor = true;\n            this.button1.Click += new System.EventHandler(this.button1_Click);\n\n            // \n            // TestPlugin\n            // \n            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);\n            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;\n            this.ClientSize = new System.Drawing.Size(433, 233);\n            this.Controls.Add(this.button1);\n            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;\n            this.Name = \"TestPlugin\";\n            this.Text = \"TestPlugin\";\n            this.ResumeLayout(false);\n        }\n\n        private System.Windows.Forms.Button button1;\n\n        #endregion\n    }\n}\n\n"
  },
  {
    "path": "samples/WinFormsPluginsLibrary/TestPlugin.cs",
    "content": "﻿using System;\nusing System.ComponentModel;\nusing System.Windows.Forms;\nusing Weikio.PluginFramework.Samples.Shared;\n\nnamespace WinFormsPluginsLibrary\n{\n    [DisplayName(\"Hello World\")]\n    public partial class TestPlugin : Form, IDialog\n    {\n        public TestPlugin()\n        {\n            InitializeComponent();\n        }\n\n        private void button1_Click(object sender, EventArgs e)\n        {\n            MessageBox.Show(\"Hello Plugin Framework\");\n        }\n    }\n}\n\n"
  },
  {
    "path": "samples/WinFormsPluginsLibrary/TestPlugin.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n</root>"
  },
  {
    "path": "samples/WinFormsPluginsLibrary/WinFormsPluginsLibrary.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk.WindowsDesktop\">\n\n    <PropertyGroup>\n        <TargetFramework>netcoreapp3.1</TargetFramework>\n        <UseWindowsForms>true</UseWindowsForms>\n    </PropertyGroup>\n\n    <ItemGroup>\n      <Compile Update=\"TestPlugin.cs\">\n        <SubType>Form</SubType>\n      </Compile>\n      <Compile Update=\"LabelPlugin.cs\">\n        <SubType>Form</SubType>\n      </Compile>\n    </ItemGroup>\n\n    <ItemGroup>\n      <ProjectReference Include=\"..\\Shared\\Weikio.PluginFramework.Samples.Shared\\Weikio.PluginFramework.Samples.Shared.csproj\" />\n    </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "samples/WpfApp/App.xaml",
    "content": "﻿<Application x:Class=\"WpfApp.App\"\n             xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n             xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n             xmlns:local=\"clr-namespace:WpfApp\"\n             StartupUri=\"MainWindow.xaml\">\n    <Application.Resources>\n         \n    </Application.Resources>\n</Application>\n"
  },
  {
    "path": "samples/WpfApp/App.xaml.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Configuration;\nusing System.Data;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing System.Windows;\n\nnamespace WpfApp\n{\n    /// <summary>\n    /// Interaction logic for App.xaml\n    /// </summary>\n    public partial class App : Application\n    {\n    }\n}\n"
  },
  {
    "path": "samples/WpfApp/AssemblyInfo.cs",
    "content": "using System.Windows;\n\n[assembly: ThemeInfo(\n    ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located\n    //(used if a resource is not found in the page,\n    // or application resource dictionaries)\n    ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located\n    //(used if a resource is not found in the page,\n    // app, or any theme specific resource dictionaries)\n)]\n"
  },
  {
    "path": "samples/WpfApp/DivideOperator.cs",
    "content": "﻿using Weikio.PluginFramework.Samples.Shared;\n\nnamespace WpfApp\n{\n    public class DivideOperator : IOperator\n    {\n        public int Calculate(int x, int y)\n        {\n            return x / y;\n        }\n    }\n}\n"
  },
  {
    "path": "samples/WpfApp/MainWindow.xaml",
    "content": "﻿<Window x:Class=\"WpfApp.MainWindow\"\n        xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n        xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n        xmlns:local=\"clr-namespace:WpfApp\"\n        mc:Ignorable=\"d\"\n        Title=\"MainWindow\" Height=\"450\" Width=\"800\" Loaded=\"MainWindow_OnLoaded\">\n    <Grid>\n        <Grid.RowDefinitions>\n            <RowDefinition Height=\"auto\" />\n            <RowDefinition />\n            <RowDefinition Height=\"auto\" />\n        </Grid.RowDefinitions>\n\n\n        <TextBlock Text=\"Plugins:\" />\n        <ListBox x:Name=\"PluginsList\" Grid.Row=\"1\" />\n        <Grid Grid.Row=\"2\">\n            <Grid.ColumnDefinitions>\n                <ColumnDefinition />\n                <ColumnDefinition />\n            </Grid.ColumnDefinitions>\n            <Button Grid.Column=\"0\" Content=\"Run Plugin\" Click=\"ButtonBase_OnClick\" />\n            <TextBlock x:Name=\"PluginOutput\" Grid.Column=\"1\" />\n        </Grid>\n    </Grid>\n</Window>"
  },
  {
    "path": "samples/WpfApp/MainWindow.xaml.cs",
    "content": "﻿using System;\nusing System.Collections.ObjectModel;\nusing System.Windows;\nusing Weikio.PluginFramework.Samples.Shared;\nusing Weikio.PluginFramework.Abstractions;\nusing Weikio.PluginFramework.Catalogs;\n\nnamespace WpfApp\n{\n    public partial class MainWindow : Window\n    {\n        private readonly ObservableCollection<Plugin> _plugins = new ObservableCollection<Plugin>();\n        \n        public MainWindow()\n        {\n            InitializeComponent();\n        }\n\n        private async void MainWindow_OnLoaded(object sender, RoutedEventArgs e)\n        {\n            var folderPluginCatalog = new FolderPluginCatalog(@\"..\\..\\..\\..\\Shared\\Weikio.PluginFramework.Samples.SharedPlugins\\bin\\debug\\netcoreapp3.1\", type =>\n            {\n                type.Implements<IOperator>();\n            });\n            \n            var assemblyPluginCatalog = new AssemblyPluginCatalog(typeof(MainWindow).Assembly, type => typeof(IOperator).IsAssignableFrom(type));\n            \n            var pluginCatalog = new CompositePluginCatalog(folderPluginCatalog, assemblyPluginCatalog); \n            await pluginCatalog.Initialize();\n\n            var allPlugins = pluginCatalog.GetPlugins();\n\n            foreach (var plugin in allPlugins)\n            {\n                _plugins.Add(plugin);\n            }\n\n            PluginsList.ItemsSource = _plugins;\n        }\n\n        private void ButtonBase_OnClick(object sender, RoutedEventArgs e)\n        {\n            if (PluginsList.SelectedItem == null)\n            {\n                return;\n            }\n\n            var selectedPlugin = (Plugin) PluginsList.SelectedItem;\n\n            var instance = (IOperator) Activator.CreateInstance(selectedPlugin);\n\n            var result = instance.Calculate(20, 10);\n\n            PluginOutput.Text = result.ToString();\n        }\n    }\n}\n"
  },
  {
    "path": "samples/WpfApp/WpfApp.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk.WindowsDesktop\">\n\n    <PropertyGroup>\n        <OutputType>WinExe</OutputType>\n        <TargetFramework>netcoreapp3.1</TargetFramework>\n        <UseWPF>true</UseWPF>\n    </PropertyGroup>\n\n    <ItemGroup>\n      <ProjectReference Include=\"..\\..\\src\\Weikio.PluginFramework.Abstractions\\Weikio.PluginFramework.Abstractions.csproj\" />\n      <ProjectReference Include=\"..\\..\\src\\Weikio.PluginFramework\\Weikio.PluginFramework.csproj\" />\n      <ProjectReference Include=\"..\\Shared\\Weikio.PluginFramework.Samples.Shared\\Weikio.PluginFramework.Samples.Shared.csproj\" />\n    </ItemGroup>\n\n</Project>"
  },
  {
    "path": "src/PluginFramework.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30330.147\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Weikio.PluginFramework\", \"Weikio.PluginFramework\\Weikio.PluginFramework.csproj\", \"{BB67695B-1CDF-4FEC-8627-82FD349D1403}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Weikio.PluginFramework.Abstractions\", \"Weikio.PluginFramework.Abstractions\\Weikio.PluginFramework.Abstractions.csproj\", \"{5C264288-C384-48A3-AF94-850D98830E13}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Weikio.PluginFramework.Tests\", \"..\\tests\\unit\\Weikio.PluginFramework.Tests\\Weikio.PluginFramework.Tests.csproj\", \"{6CDBFF3C-932B-4A66-8779-B5C72B33AF7F}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Tests\", \"Tests\", \"{DE041517-4760-4748-97F6-DB71D6AFFF5B}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"TestAssembly1\", \"..\\tests\\Assemblies\\TestAssembly1\\TestAssembly1.csproj\", \"{DB21DEFB-37D4-4006-A6B9-735671151D29}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"TestAssembly2\", \"..\\tests\\Assemblies\\TestAssembly2\\TestAssembly2.csproj\", \"{F2987B1B-2FBD-4F1A-B95D-7F14618B2971}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"TestAssembly3\", \"..\\tests\\Assemblies\\TestAssembly3\\TestAssembly3.csproj\", \"{BB7D0751-895E-4820-9F52-CE4ECEE0F1FD}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"TestIntefaces\", \"..\\tests\\Assemblies\\TestIntefaces\\TestIntefaces.csproj\", \"{044D3F05-A2F2-4D4A-A3FE-360F57BB765D}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"JsonNetOld\", \"..\\tests\\Assemblies\\JsonNetOld\\JsonNetOld.csproj\", \"{8653C860-AF1B-42E6-8DAD-AEBC08D676B2}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"JsonNetNew\", \"..\\tests\\Assemblies\\JsonNetNew\\JsonNetNew.csproj\", \"{6FB33F21-3C1B-4BB0-AFC6-E512EE9F5928}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Resources\", \"Resources\", \"{B2BA1C10-1130-45ED-83F1-32BF8FBF4D4A}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Samples\", \"Samples\", \"{FF3A507D-D242-44F6-8940-49E0B51B6F02}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ConsoleApp\", \"..\\samples\\ConsoleApp\\ConsoleApp.csproj\", \"{C161BE3A-99A1-4A89-A2CE-79A5A1994FFC}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Weikio.PluginFramework.Samples.Shared\", \"..\\samples\\Shared\\Weikio.PluginFramework.Samples.Shared\\Weikio.PluginFramework.Samples.Shared.csproj\", \"{DBC0AD60-7261-4CEB-BE4F-3AD12C39F813}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"WpfApp\", \"..\\samples\\WpfApp\\WpfApp.csproj\", \"{91A58039-85B5-4B2C-8F25-10DD6033F3AA}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Weikio.PluginFramework.Samples.SharedPlugins\", \"..\\samples\\Shared\\Weikio.PluginFramework.Samples.SharedPlugins\\Weikio.PluginFramework.Samples.SharedPlugins.csproj\", \"{6E19B5B2-9106-4EB3-8B0E-1C735FB4C815}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"WebApp\", \"..\\samples\\WebApp\\WebApp.csproj\", \"{30C02979-E0C0-4AD0-B88F-23EF28807473}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Weikio.PluginFramework.AspNetCore\", \"Weikio.PluginFramework.AspNetCore\\Weikio.PluginFramework.AspNetCore.csproj\", \"{E4F3E21D-653A-4AE7-B1DA-63B3F041367C}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Shared\", \"Shared\", \"{E24D3F2A-4080-475B-92D3-C80B9BD20A70}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Weikio.PluginFramework.Catalogs.NuGet\", \"Weikio.PluginFramework.Catalogs.NuGet\\Weikio.PluginFramework.Catalogs.NuGet.csproj\", \"{4BCDAB59-F231-4241-B6BE-93BDC047C86F}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Weikio.PluginFramework.Catalogs.Roslyn\", \"Weikio.PluginFramework.Catalogs.Roslyn\\Weikio.PluginFramework.Catalogs.Roslyn.csproj\", \"{74D03415-F262-4DA2-B319-6A88F3278CC7}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Weikio.PluginFramework.Catalogs.Roslyn.Tests\", \"..\\tests\\unit\\Weikio.PluginFramework.Catalogs.Roslyn.Tests\\Weikio.PluginFramework.Catalogs.Roslyn.Tests.csproj\", \"{E7600CAB-94DC-4A17-ABB2-B789A6409E02}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Weikio.PluginFramework.Catalogs.NuGet.Tests\", \"..\\tests\\integration\\Weikio.PluginFramework.Catalogs.NuGet.Tests\\Weikio.PluginFramework.Catalogs.NuGet.Tests.csproj\", \"{174C5479-712A-46DB-BD91-C031F6B3A55D}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"WebAppWithNuget\", \"..\\samples\\WebAppWithNuget\\WebAppWithNuget.csproj\", \"{0FFD32D3-3A4F-453E-B7A2-8891F77F03D0}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"WebAppWithRoslyn\", \"..\\samples\\WebAppWithRoslyn\\WebAppWithRoslyn.csproj\", \"{9C46DA92-CB56-45FA-A904-0A7330C71C2C}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"WebAppWithDelegate\", \"..\\samples\\WebAppWithDelegate\\WebAppWithDelegate.csproj\", \"{C2DD5D1C-2F8A-4EC9-BE90-66418A8602AE}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"BlazorApp\", \"..\\Samples\\BlazorApp\\BlazorApp.csproj\", \"{A7EC9D91-CED0-43E7-BAB3-3B72230BFC0B}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"WinFormsApp\", \"..\\samples\\WinFormsApp\\WinFormsApp.csproj\", \"{6D392453-FC9E-45AD-A9A7-7596A93B3E6C}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"WinFormsPluginsLibrary\", \"..\\samples\\WinFormsPluginsLibrary\\WinFormsPluginsLibrary.csproj\", \"{E92B0C5D-FFAC-4AB9-B069-869AEED565B0}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Weikio.PluginFramework.Configuration\", \"Weikio.PluginFramework.Configuration\\Weikio.PluginFramework.Configuration.csproj\", \"{882BB58E-D256-4BBF-8C5F-80C4FA39B775}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"WebAppWithAppSettings\", \"..\\samples\\WebAppWithAppSettings\\WebAppWithAppSettings.csproj\", \"{A5FAE1A5-74A0-4A83-9520-DCABF6610ADE}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"WebAppPluginsLibrary\", \"..\\samples\\WebAppPluginsLibrary\\WebAppPluginsLibrary.csproj\", \"{38CCE0F7-F998-4766-A14A-44C047E8D0AA}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"WebSites\", \"WebSites\", \"{38E778EC-D2F9-46E8-9D48-9405B1D05BDC}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"PluginFrameworkTestBed\", \"..\\tests\\integration\\WebSites\\PluginFrameworkTestBed\\PluginFrameworkTestBed.csproj\", \"{1F634A43-B7E4-4C8A-9877-AE6A03E9ACB5}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Weikio.PluginFramework.AspNetCore.IntegrationTests\", \"..\\tests\\integration\\Weikio.PluginFramework.AspNetCore.IntegrationTests\\Weikio.PluginFramework.AspNetCore.IntegrationTests.csproj\", \"{7AA40D04-0826-4F4A-9028-2270BAED0B9B}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{BB67695B-1CDF-4FEC-8627-82FD349D1403}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{BB67695B-1CDF-4FEC-8627-82FD349D1403}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{BB67695B-1CDF-4FEC-8627-82FD349D1403}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{BB67695B-1CDF-4FEC-8627-82FD349D1403}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{5C264288-C384-48A3-AF94-850D98830E13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{5C264288-C384-48A3-AF94-850D98830E13}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{5C264288-C384-48A3-AF94-850D98830E13}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{5C264288-C384-48A3-AF94-850D98830E13}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{6CDBFF3C-932B-4A66-8779-B5C72B33AF7F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{6CDBFF3C-932B-4A66-8779-B5C72B33AF7F}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{6CDBFF3C-932B-4A66-8779-B5C72B33AF7F}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{6CDBFF3C-932B-4A66-8779-B5C72B33AF7F}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{DB21DEFB-37D4-4006-A6B9-735671151D29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{DB21DEFB-37D4-4006-A6B9-735671151D29}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{DB21DEFB-37D4-4006-A6B9-735671151D29}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{DB21DEFB-37D4-4006-A6B9-735671151D29}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{F2987B1B-2FBD-4F1A-B95D-7F14618B2971}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{F2987B1B-2FBD-4F1A-B95D-7F14618B2971}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{F2987B1B-2FBD-4F1A-B95D-7F14618B2971}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{F2987B1B-2FBD-4F1A-B95D-7F14618B2971}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{BB7D0751-895E-4820-9F52-CE4ECEE0F1FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{BB7D0751-895E-4820-9F52-CE4ECEE0F1FD}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{BB7D0751-895E-4820-9F52-CE4ECEE0F1FD}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{BB7D0751-895E-4820-9F52-CE4ECEE0F1FD}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{044D3F05-A2F2-4D4A-A3FE-360F57BB765D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{044D3F05-A2F2-4D4A-A3FE-360F57BB765D}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{044D3F05-A2F2-4D4A-A3FE-360F57BB765D}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{044D3F05-A2F2-4D4A-A3FE-360F57BB765D}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{8653C860-AF1B-42E6-8DAD-AEBC08D676B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{8653C860-AF1B-42E6-8DAD-AEBC08D676B2}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{8653C860-AF1B-42E6-8DAD-AEBC08D676B2}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{8653C860-AF1B-42E6-8DAD-AEBC08D676B2}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{6FB33F21-3C1B-4BB0-AFC6-E512EE9F5928}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{6FB33F21-3C1B-4BB0-AFC6-E512EE9F5928}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{6FB33F21-3C1B-4BB0-AFC6-E512EE9F5928}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{6FB33F21-3C1B-4BB0-AFC6-E512EE9F5928}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{C161BE3A-99A1-4A89-A2CE-79A5A1994FFC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{C161BE3A-99A1-4A89-A2CE-79A5A1994FFC}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{C161BE3A-99A1-4A89-A2CE-79A5A1994FFC}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{C161BE3A-99A1-4A89-A2CE-79A5A1994FFC}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{DBC0AD60-7261-4CEB-BE4F-3AD12C39F813}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{DBC0AD60-7261-4CEB-BE4F-3AD12C39F813}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{DBC0AD60-7261-4CEB-BE4F-3AD12C39F813}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{DBC0AD60-7261-4CEB-BE4F-3AD12C39F813}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{91A58039-85B5-4B2C-8F25-10DD6033F3AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{91A58039-85B5-4B2C-8F25-10DD6033F3AA}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{91A58039-85B5-4B2C-8F25-10DD6033F3AA}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{91A58039-85B5-4B2C-8F25-10DD6033F3AA}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{6E19B5B2-9106-4EB3-8B0E-1C735FB4C815}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{6E19B5B2-9106-4EB3-8B0E-1C735FB4C815}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{6E19B5B2-9106-4EB3-8B0E-1C735FB4C815}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{6E19B5B2-9106-4EB3-8B0E-1C735FB4C815}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{30C02979-E0C0-4AD0-B88F-23EF28807473}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{30C02979-E0C0-4AD0-B88F-23EF28807473}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{30C02979-E0C0-4AD0-B88F-23EF28807473}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{30C02979-E0C0-4AD0-B88F-23EF28807473}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{E4F3E21D-653A-4AE7-B1DA-63B3F041367C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{E4F3E21D-653A-4AE7-B1DA-63B3F041367C}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{E4F3E21D-653A-4AE7-B1DA-63B3F041367C}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{E4F3E21D-653A-4AE7-B1DA-63B3F041367C}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{4BCDAB59-F231-4241-B6BE-93BDC047C86F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{4BCDAB59-F231-4241-B6BE-93BDC047C86F}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{4BCDAB59-F231-4241-B6BE-93BDC047C86F}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{4BCDAB59-F231-4241-B6BE-93BDC047C86F}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{74D03415-F262-4DA2-B319-6A88F3278CC7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{74D03415-F262-4DA2-B319-6A88F3278CC7}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{74D03415-F262-4DA2-B319-6A88F3278CC7}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{74D03415-F262-4DA2-B319-6A88F3278CC7}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{E7600CAB-94DC-4A17-ABB2-B789A6409E02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{E7600CAB-94DC-4A17-ABB2-B789A6409E02}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{E7600CAB-94DC-4A17-ABB2-B789A6409E02}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{E7600CAB-94DC-4A17-ABB2-B789A6409E02}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{174C5479-712A-46DB-BD91-C031F6B3A55D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{174C5479-712A-46DB-BD91-C031F6B3A55D}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{174C5479-712A-46DB-BD91-C031F6B3A55D}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{174C5479-712A-46DB-BD91-C031F6B3A55D}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{0FFD32D3-3A4F-453E-B7A2-8891F77F03D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{0FFD32D3-3A4F-453E-B7A2-8891F77F03D0}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{0FFD32D3-3A4F-453E-B7A2-8891F77F03D0}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{0FFD32D3-3A4F-453E-B7A2-8891F77F03D0}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{9C46DA92-CB56-45FA-A904-0A7330C71C2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{9C46DA92-CB56-45FA-A904-0A7330C71C2C}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{9C46DA92-CB56-45FA-A904-0A7330C71C2C}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{9C46DA92-CB56-45FA-A904-0A7330C71C2C}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{C2DD5D1C-2F8A-4EC9-BE90-66418A8602AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{C2DD5D1C-2F8A-4EC9-BE90-66418A8602AE}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{C2DD5D1C-2F8A-4EC9-BE90-66418A8602AE}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{C2DD5D1C-2F8A-4EC9-BE90-66418A8602AE}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{A7EC9D91-CED0-43E7-BAB3-3B72230BFC0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{A7EC9D91-CED0-43E7-BAB3-3B72230BFC0B}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{A7EC9D91-CED0-43E7-BAB3-3B72230BFC0B}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{A7EC9D91-CED0-43E7-BAB3-3B72230BFC0B}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{6D392453-FC9E-45AD-A9A7-7596A93B3E6C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{6D392453-FC9E-45AD-A9A7-7596A93B3E6C}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{6D392453-FC9E-45AD-A9A7-7596A93B3E6C}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{6D392453-FC9E-45AD-A9A7-7596A93B3E6C}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{E92B0C5D-FFAC-4AB9-B069-869AEED565B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{E92B0C5D-FFAC-4AB9-B069-869AEED565B0}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{E92B0C5D-FFAC-4AB9-B069-869AEED565B0}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{E92B0C5D-FFAC-4AB9-B069-869AEED565B0}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{882BB58E-D256-4BBF-8C5F-80C4FA39B775}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{882BB58E-D256-4BBF-8C5F-80C4FA39B775}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{882BB58E-D256-4BBF-8C5F-80C4FA39B775}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{882BB58E-D256-4BBF-8C5F-80C4FA39B775}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{A5FAE1A5-74A0-4A83-9520-DCABF6610ADE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{A5FAE1A5-74A0-4A83-9520-DCABF6610ADE}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{A5FAE1A5-74A0-4A83-9520-DCABF6610ADE}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{A5FAE1A5-74A0-4A83-9520-DCABF6610ADE}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{38CCE0F7-F998-4766-A14A-44C047E8D0AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{38CCE0F7-F998-4766-A14A-44C047E8D0AA}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{38CCE0F7-F998-4766-A14A-44C047E8D0AA}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{38CCE0F7-F998-4766-A14A-44C047E8D0AA}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{1F634A43-B7E4-4C8A-9877-AE6A03E9ACB5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{1F634A43-B7E4-4C8A-9877-AE6A03E9ACB5}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{1F634A43-B7E4-4C8A-9877-AE6A03E9ACB5}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{1F634A43-B7E4-4C8A-9877-AE6A03E9ACB5}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{7AA40D04-0826-4F4A-9028-2270BAED0B9B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{7AA40D04-0826-4F4A-9028-2270BAED0B9B}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{7AA40D04-0826-4F4A-9028-2270BAED0B9B}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{7AA40D04-0826-4F4A-9028-2270BAED0B9B}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(NestedProjects) = preSolution\n\t\t{6CDBFF3C-932B-4A66-8779-B5C72B33AF7F} = {DE041517-4760-4748-97F6-DB71D6AFFF5B}\n\t\t{DB21DEFB-37D4-4006-A6B9-735671151D29} = {B2BA1C10-1130-45ED-83F1-32BF8FBF4D4A}\n\t\t{F2987B1B-2FBD-4F1A-B95D-7F14618B2971} = {B2BA1C10-1130-45ED-83F1-32BF8FBF4D4A}\n\t\t{BB7D0751-895E-4820-9F52-CE4ECEE0F1FD} = {B2BA1C10-1130-45ED-83F1-32BF8FBF4D4A}\n\t\t{044D3F05-A2F2-4D4A-A3FE-360F57BB765D} = {B2BA1C10-1130-45ED-83F1-32BF8FBF4D4A}\n\t\t{8653C860-AF1B-42E6-8DAD-AEBC08D676B2} = {B2BA1C10-1130-45ED-83F1-32BF8FBF4D4A}\n\t\t{6FB33F21-3C1B-4BB0-AFC6-E512EE9F5928} = {B2BA1C10-1130-45ED-83F1-32BF8FBF4D4A}\n\t\t{B2BA1C10-1130-45ED-83F1-32BF8FBF4D4A} = {DE041517-4760-4748-97F6-DB71D6AFFF5B}\n\t\t{C161BE3A-99A1-4A89-A2CE-79A5A1994FFC} = {FF3A507D-D242-44F6-8940-49E0B51B6F02}\n\t\t{DBC0AD60-7261-4CEB-BE4F-3AD12C39F813} = {E24D3F2A-4080-475B-92D3-C80B9BD20A70}\n\t\t{91A58039-85B5-4B2C-8F25-10DD6033F3AA} = {FF3A507D-D242-44F6-8940-49E0B51B6F02}\n\t\t{6E19B5B2-9106-4EB3-8B0E-1C735FB4C815} = {E24D3F2A-4080-475B-92D3-C80B9BD20A70}\n\t\t{30C02979-E0C0-4AD0-B88F-23EF28807473} = {FF3A507D-D242-44F6-8940-49E0B51B6F02}\n\t\t{E24D3F2A-4080-475B-92D3-C80B9BD20A70} = {FF3A507D-D242-44F6-8940-49E0B51B6F02}\n\t\t{E7600CAB-94DC-4A17-ABB2-B789A6409E02} = {DE041517-4760-4748-97F6-DB71D6AFFF5B}\n\t\t{174C5479-712A-46DB-BD91-C031F6B3A55D} = {DE041517-4760-4748-97F6-DB71D6AFFF5B}\n\t\t{0FFD32D3-3A4F-453E-B7A2-8891F77F03D0} = {FF3A507D-D242-44F6-8940-49E0B51B6F02}\n\t\t{9C46DA92-CB56-45FA-A904-0A7330C71C2C} = {FF3A507D-D242-44F6-8940-49E0B51B6F02}\n\t\t{C2DD5D1C-2F8A-4EC9-BE90-66418A8602AE} = {FF3A507D-D242-44F6-8940-49E0B51B6F02}\n\t\t{A7EC9D91-CED0-43E7-BAB3-3B72230BFC0B} = {FF3A507D-D242-44F6-8940-49E0B51B6F02}\n\t\t{6D392453-FC9E-45AD-A9A7-7596A93B3E6C} = {FF3A507D-D242-44F6-8940-49E0B51B6F02}\n\t\t{E92B0C5D-FFAC-4AB9-B069-869AEED565B0} = {FF3A507D-D242-44F6-8940-49E0B51B6F02}\n\t\t{A5FAE1A5-74A0-4A83-9520-DCABF6610ADE} = {FF3A507D-D242-44F6-8940-49E0B51B6F02}\n\t\t{38CCE0F7-F998-4766-A14A-44C047E8D0AA} = {FF3A507D-D242-44F6-8940-49E0B51B6F02}\n\t\t{38E778EC-D2F9-46E8-9D48-9405B1D05BDC} = {DE041517-4760-4748-97F6-DB71D6AFFF5B}\n\t\t{1F634A43-B7E4-4C8A-9877-AE6A03E9ACB5} = {38E778EC-D2F9-46E8-9D48-9405B1D05BDC}\n\t\t{7AA40D04-0826-4F4A-9028-2270BAED0B9B} = {DE041517-4760-4748-97F6-DB71D6AFFF5B}\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {AAEBC2B4-FB52-4272-8C25-571FB3CA01E5}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "src/Weikio.PluginFramework/Catalogs/AssemblyPluginCatalog.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Reflection;\nusing System.Threading.Tasks;\nusing Weikio.PluginFramework.Abstractions;\nusing Weikio.PluginFramework.Context;\nusing Weikio.PluginFramework.TypeFinding;\n\nnamespace Weikio.PluginFramework.Catalogs\n{\n    public class AssemblyPluginCatalog : IPluginCatalog\n    {\n        private readonly string _assemblyPath;\n        private Assembly _assembly;\n        private readonly AssemblyPluginCatalogOptions _options;\n        private PluginAssemblyLoadContext _pluginAssemblyLoadContext;\n        private List<TypePluginCatalog> _plugins = null;\n\n        public AssemblyPluginCatalog(string assemblyPath) : this(assemblyPath, null, null, null)\n        {\n        }\n\n        public AssemblyPluginCatalog(Assembly assembly) : this(null, assembly)\n        {\n        }\n\n        public AssemblyPluginCatalog(string assemblyPath, AssemblyPluginCatalogOptions options = null) : this(assemblyPath, null, null, null, null, null,\n            options)\n        {\n        }\n\n        public AssemblyPluginCatalog(Assembly assembly, AssemblyPluginCatalogOptions options = null) : this(null, assembly, null, null, null, null, options)\n        {\n        }\n\n        public AssemblyPluginCatalog(string assemblyPath, TypeFinderCriteria criteria = null, AssemblyPluginCatalogOptions options = null) : this(assemblyPath,\n            null, null, null,\n            null, criteria, options)\n        {\n        }\n\n        public AssemblyPluginCatalog(string assemblyPath, Action<TypeFinderCriteriaBuilder> configureFinder = null,\n            AssemblyPluginCatalogOptions options = null) : this(assemblyPath,\n            null, null, null, configureFinder, null, options)\n        {\n        }\n\n        public AssemblyPluginCatalog(Assembly assembly, Action<TypeFinderCriteriaBuilder> configureFinder = null,\n            AssemblyPluginCatalogOptions options = null) : this(null,\n            assembly, null, null, configureFinder, null, options)\n        {\n        }\n\n        public AssemblyPluginCatalog(string assemblyPath, Predicate<Type> filter = null, AssemblyPluginCatalogOptions options = null) : this(assemblyPath, null,\n            filter, null, null, null, options)\n        {\n        }\n\n        public AssemblyPluginCatalog(Assembly assembly, Predicate<Type> filter = null, AssemblyPluginCatalogOptions options = null) : this(null, assembly,\n            filter, null, null, null, options)\n        {\n        }\n\n        public AssemblyPluginCatalog(string assemblyPath, Dictionary<string, Predicate<Type>> taggedFilters,\n            AssemblyPluginCatalogOptions options = null) : this(assemblyPath, null, null, taggedFilters, null, null, options)\n        {\n        }\n\n        public AssemblyPluginCatalog(Assembly assembly, Dictionary<string, Predicate<Type>> taggedFilters,\n            AssemblyPluginCatalogOptions options = null) : this(null, assembly, null, taggedFilters, null, null, options)\n        {\n        }\n\n        public AssemblyPluginCatalog(string assemblyPath = null, Assembly assembly = null, Predicate<Type> filter = null,\n            Dictionary<string, Predicate<Type>> taggedFilters = null, Action<TypeFinderCriteriaBuilder> configureFinder = null,\n            TypeFinderCriteria criteria = null, AssemblyPluginCatalogOptions options = null)\n        {\n            if (assembly != null)\n            {\n                _assembly = assembly;\n                _assemblyPath = _assembly.Location;\n            }\n            else if (!string.IsNullOrWhiteSpace(assemblyPath))\n            {\n                _assemblyPath = assemblyPath;\n            }\n            else\n            {\n                throw new ArgumentNullException($\"{nameof(assembly)} or {nameof(assemblyPath)} must be set.\");\n            }\n\n            _options = options ?? new AssemblyPluginCatalogOptions();\n\n            SetFilters(filter, taggedFilters, criteria, configureFinder);\n        }\n\n        private void SetFilters(Predicate<Type> filter, Dictionary<string, Predicate<Type>> taggedFilters, TypeFinderCriteria criteria,\n            Action<TypeFinderCriteriaBuilder> configureFinder)\n        {\n            if (_options.TypeFinderOptions == null)\n            {\n                _options.TypeFinderOptions = new TypeFinderOptions();\n            }\n\n            if (_options.TypeFinderOptions.TypeFinderCriterias == null)\n            {\n                _options.TypeFinderOptions.TypeFinderCriterias = new List<TypeFinderCriteria>();\n            }\n\n            if (filter != null)\n            {\n                var filterCriteria = new TypeFinderCriteria { Query = (context, type) => filter(type) };\n                filterCriteria.Tags.Add(string.Empty);\n\n                _options.TypeFinderOptions.TypeFinderCriterias.Add(filterCriteria);\n            }\n\n            if (taggedFilters?.Any() == true)\n            {\n                foreach (var taggedFilter in taggedFilters)\n                {\n                    var taggedCriteria = new TypeFinderCriteria { Query = (context, type) => taggedFilter.Value(type) };\n                    taggedCriteria.Tags.Add(taggedFilter.Key);\n\n                    _options.TypeFinderOptions.TypeFinderCriterias.Add(taggedCriteria);\n                }\n            }\n\n            if (configureFinder != null)\n            {\n                var builder = new TypeFinderCriteriaBuilder();\n                configureFinder(builder);\n\n                var configuredCriteria = builder.Build();\n\n                _options.TypeFinderOptions.TypeFinderCriterias.Add(configuredCriteria);\n            }\n\n            if (criteria != null)\n            {\n                _options.TypeFinderOptions.TypeFinderCriterias.Add(criteria);\n            }\n\n            if (_options.TypeFinderCriterias?.Any() == true)\n            {\n                foreach (var typeFinderCriteria in _options.TypeFinderCriterias)\n                {\n                    var crit = typeFinderCriteria.Value;\n                    crit.Tags = new List<string>() { typeFinderCriteria.Key };\n\n                    _options.TypeFinderOptions.TypeFinderCriterias.Add(crit);\n                }\n            }\n            \n            if (_options.TypeFinderOptions.TypeFinderCriterias.Any() != true)\n            {\n                var findAll = TypeFinderCriteriaBuilder\n                    .Create()\n                    .Tag(string.Empty)\n                    .Build();\n\n                _options.TypeFinderOptions.TypeFinderCriterias.Add(findAll);\n            }\n        }\n\n        public async Task Initialize()\n        {\n            if (!string.IsNullOrWhiteSpace(_assemblyPath) && _assembly == null)\n            {\n                if (!File.Exists(_assemblyPath))\n                {\n                    throw new ArgumentException($\"Assembly in path {_assemblyPath} does not exist.\");\n                }\n            }\n\n            if (_assembly == null && File.Exists(_assemblyPath) || File.Exists(_assemblyPath) && _pluginAssemblyLoadContext == null)\n            {\n                _pluginAssemblyLoadContext = new PluginAssemblyLoadContext(_assemblyPath, _options.PluginLoadContextOptions);\n                _assembly = _pluginAssemblyLoadContext.Load();\n            }\n\n            _plugins = new List<TypePluginCatalog>();\n\n            var finder = new TypeFinder();\n\n            var handledPluginTypes = new List<Type>();\n            foreach (var typeFinderCriteria in _options.TypeFinderOptions.TypeFinderCriterias)\n            {\n                var pluginTypes = finder.Find(typeFinderCriteria, _assembly, _pluginAssemblyLoadContext);\n\n                foreach (var type in pluginTypes)\n                {\n                    if (handledPluginTypes.Contains(type))\n                    {\n                        // Make sure to create only a single type plugin catalog for each plugin type. \n                        // The type catalog will add all the matching tags\n                        continue;\n                    }\n                    \n                    var typePluginCatalog = new TypePluginCatalog(type,\n                        new TypePluginCatalogOptions()\n                        {\n                            PluginNameOptions = _options.PluginNameOptions,\n                            TypeFindingContext = _pluginAssemblyLoadContext,\n                            TypeFinderOptions = _options.TypeFinderOptions\n                        });\n\n                    await typePluginCatalog.Initialize();\n\n                    _plugins.Add(typePluginCatalog);\n                    \n                    handledPluginTypes.Add(type);\n                }\n            }\n\n            IsInitialized = true;\n        }\n\n        public bool IsInitialized { get; private set; }\n\n        public List<Plugin> GetPlugins()\n        {\n            return _plugins.SelectMany(x => x.GetPlugins()).ToList();\n        }\n\n        public Plugin Get(string name, Version version)\n        {\n            foreach (var pluginCatalog in _plugins)\n            {\n                var foundPlugin = pluginCatalog.Get(name, version);\n\n                if (foundPlugin == null)\n                {\n                    continue;\n                }\n\n                return foundPlugin;\n            }\n\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework/Catalogs/AssemblyPluginCatalogOptions.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing Weikio.PluginFramework.Abstractions;\nusing Weikio.PluginFramework.Context;\nusing Weikio.PluginFramework.TypeFinding;\n\nnamespace Weikio.PluginFramework.Catalogs\n{\n    public class AssemblyPluginCatalogOptions\n    {\n        /// <summary>\n        /// Gets or sets the <see cref=\"PluginLoadContextOptions\"/>.\n        /// </summary>\n        public PluginLoadContextOptions PluginLoadContextOptions = new PluginLoadContextOptions();\n        \n        [Obsolete(\"Please use TypeFinderOptions. This will be removed in a future release.\")]\n        public Dictionary<string, TypeFinderCriteria> TypeFinderCriterias = new Dictionary<string, TypeFinderCriteria>();\n\n        /// <summary>\n        /// Gets or sets how the plugin names and version should be defined. <seealso cref=\"PluginNameOptions\"/>.\n        /// </summary>\n        public PluginNameOptions PluginNameOptions { get; set; } = Defaults.PluginNameOptions;\n        \n        /// <summary>\n        /// Gets or sets the <see cref=\"TypeFinderOptions\"/>. \n        /// </summary>\n        public TypeFinderOptions TypeFinderOptions { get; set; } = new TypeFinderOptions();\n\n        public static class Defaults\n        {\n            public static PluginNameOptions PluginNameOptions { get; set; } = new PluginNameOptions();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework/Catalogs/CompositePluginCatalog.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Weikio.PluginFramework.Abstractions;\n\nnamespace Weikio.PluginFramework.Catalogs\n{\n    /// <summary>\n    /// Composite Plugin Catalog combines 1-n other Plugin Catalogs. \n    /// </summary>\n    public class CompositePluginCatalog : IPluginCatalog\n    {\n        private readonly List<IPluginCatalog> _catalogs;\n\n        /// <inheritdoc />\n        public bool IsInitialized { get; private set; }\n\n        /// <inheritdoc />\n        public List<Plugin> GetPlugins()\n        {\n            var result = new List<Plugin>();\n\n            foreach (var pluginCatalog in _catalogs)\n            {\n                var pluginsInCatalog = pluginCatalog.GetPlugins();\n                result.AddRange(pluginsInCatalog);\n            }\n\n            return result;\n        }\n\n        /// <inheritdoc />\n        public Plugin Get(string name, Version version)\n        {\n            foreach (var pluginCatalog in _catalogs)\n            {\n                var plugin = pluginCatalog.Get(name, version);\n\n                if (plugin == null)\n                {\n                    continue;\n                }\n\n                return plugin;\n            }\n\n            return null;\n        }\n\n        public CompositePluginCatalog(params IPluginCatalog[] catalogs)\n        {\n            _catalogs = catalogs.ToList();\n        }\n\n        public void AddCatalog(IPluginCatalog catalog)\n        {\n            _catalogs.Add(catalog);\n        }\n\n        /// <inheritdoc />\n        public async Task Initialize()\n        {\n            if (_catalogs?.Any() != true)\n            {\n                IsInitialized = true;\n\n                return;\n            }\n\n            foreach (var pluginCatalog in _catalogs)\n            {\n                await pluginCatalog.Initialize();\n            }\n\n            IsInitialized = true;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework/Catalogs/Delegates/ConversionRule.cs",
    "content": "﻿using System;\nusing System.Reflection;\n\nnamespace Weikio.PluginFramework.Catalogs.Delegates\n{\n    public class DelegateConversionRule\n    {\n        private readonly Predicate<ParameterInfo> _canHandle;\n        private readonly Func<ParameterInfo, ParameterConversion> _handle;\n\n        public DelegateConversionRule(Predicate<ParameterInfo> canHandle, Func<ParameterInfo, ParameterConversion> handle)\n        {\n            if (canHandle == null)\n            {\n                throw new ArgumentNullException(nameof(canHandle));\n            }\n\n            if (handle == null)\n            {\n                throw new ArgumentNullException(nameof(handle));\n            }\n            \n            _canHandle = canHandle;\n            _handle = handle;\n        }\n\n        public bool CanHandle(ParameterInfo parameterInfo)\n        {\n            return _canHandle(parameterInfo);\n        }\n        \n        public ParameterConversion Handle(ParameterInfo parameterInfo)\n        {\n            return _handle(parameterInfo);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework/Catalogs/Delegates/DelegateCatalog.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Weikio.PluginFramework.Abstractions;\nusing Weikio.PluginFramework.TypeFinding;\nusing Weikio.TypeGenerator;\nusing Weikio.TypeGenerator.Delegates;\n\nnamespace Weikio.PluginFramework.Catalogs.Delegates\n{\n    public class DelegatePluginCatalog : IPluginCatalog\n    {\n        private TypePluginCatalog _catalog;\n        private readonly MulticastDelegate _multicastDelegate;\n\n        private readonly DelegatePluginCatalogOptions _options;\n\n        public DelegatePluginCatalog(MulticastDelegate multicastDelegate) : this(multicastDelegate, pluginName: null)\n        {\n        }\n\n        /// <summary>\n        /// Creates an instance of DelegatePluginCatalog \n        /// </summary>\n        /// <param name=\"multicastDelegate\">Plugin's delegate</param>\n        /// <param name=\"pluginName\">Name of the plugin</param>\n        public DelegatePluginCatalog(MulticastDelegate multicastDelegate, string pluginName = \"\") : this(multicastDelegate, null, null, null, pluginName)\n        {\n        }\n\n        public DelegatePluginCatalog(MulticastDelegate multicastDelegate, DelegatePluginCatalogOptions options) : this(multicastDelegate,\n            options?.ConversionRules, options?.NameOptions, options)\n        {\n        }\n\n        public DelegatePluginCatalog(MulticastDelegate multicastDelegate,\n            List<DelegateConversionRule> conversionRules = null,\n            PluginNameOptions nameOptions = null, DelegatePluginCatalogOptions options = null, string pluginName = null)\n        {\n            if (multicastDelegate == null)\n            {\n                throw new ArgumentNullException(nameof(multicastDelegate));\n            }\n\n            _multicastDelegate = multicastDelegate;\n\n            if (conversionRules == null)\n            {\n                conversionRules = new List<DelegateConversionRule>();\n            }\n\n            if (options != null)\n            {\n                _options = options;\n            }\n            else\n            {\n                _options = new DelegatePluginCatalogOptions();\n            }\n\n            _options.ConversionRules = conversionRules;\n\n            if (nameOptions == null)\n            {\n                nameOptions = new PluginNameOptions();\n            }\n\n            _options.NameOptions = nameOptions;\n\n            if (!string.IsNullOrWhiteSpace(pluginName))\n            {\n                _options.NameOptions.PluginNameGenerator = (pluginNameOptions, type) => pluginName;\n            }\n        }\n\n        public async Task Initialize()\n        {\n            var converter = new DelegateToTypeWrapper();\n\n            // Convert this catalog's options to the format supported by Delegate Wrapper.\n            // TODO: At some good point change the catalog so that it uses the Delegate Wrapper's options instead of defining its own.\n            var delegateToTypeWrapperOptions = ConvertOptions();\n            var assembly = converter.CreateType(_multicastDelegate, delegateToTypeWrapperOptions);\n\n            var options = new TypePluginCatalogOptions() { PluginNameOptions = _options.NameOptions };\n\n            if (_options.Tags?.Any() == true)\n            {\n                options.TypeFinderOptions = new TypeFinderOptions\n                {\n                    TypeFinderCriterias = new List<TypeFinderCriteria> { TypeFinderCriteriaBuilder.Create().Tag(_options.Tags.ToArray()) }\n                };\n            }\n\n            _catalog = new TypePluginCatalog(assembly, options);\n            await _catalog.Initialize();\n\n            IsInitialized = true;\n        }\n\n        private DelegateToTypeWrapperOptions ConvertOptions()\n        {\n            var convRules = GetConversionRules();\n\n            return new DelegateToTypeWrapperOptions()\n            {\n                ConversionRules = convRules,\n                MethodName = _options.MethodName,\n                NamespaceName = _options.NamespaceName,\n                TypeName = _options.TypeName,\n                MethodNameGenerator = wrapperOptions => _options.MethodNameGenerator(_options),\n                NamespaceNameGenerator = wrapperOptions => _options.NamespaceNameGenerator(_options),\n                TypeNameGenerator = wrapperOptions => _options.TypeNameGenerator(_options),\n            };\n        }\n\n        private List<ParameterConversionRule> GetConversionRules()\n        {\n            var convRules = new List<ParameterConversionRule>();\n\n            foreach (var conversionRule in _options.ConversionRules)\n            {\n                var paramConversion = new ParameterConversionRule(conversionRule.CanHandle, info =>\n                {\n                    var handleResult = conversionRule.Handle(info);\n\n                    return new TypeGenerator.ParameterConversion()\n                    {\n                        Name = handleResult.Name, ToConstructor = handleResult.ToConstructor, ToPublicProperty = handleResult.ToPublicProperty\n                    };\n                });\n\n                convRules.Add(paramConversion);\n            }\n\n            return convRules;\n        }\n\n        public bool IsInitialized { get; set; }\n\n        public List<Plugin> GetPlugins()\n        {\n            return _catalog.GetPlugins();\n        }\n\n        public Plugin Get(string name, Version version)\n        {\n            return _catalog.Get(name, version);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework/Catalogs/Delegates/DelegatePluginCatalogOptions.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Reflection;\nusing Weikio.PluginFramework.Abstractions;\n\nnamespace Weikio.PluginFramework.Catalogs.Delegates\n{\n    public class DelegatePluginCatalogOptions\n    {\n        public PluginNameOptions NameOptions { get; set; } = new PluginNameOptions();\n        public List<DelegateConversionRule> ConversionRules { get; set; } = new List<DelegateConversionRule>();\n        public string MethodName { get; set; } = \"Run\";\n        public string TypeName { get; set; } = \"GeneratedType\";\n        public string NamespaceName { get; set; } = \"GeneratedNamespace\";\n        public Func<DelegatePluginCatalogOptions, string> MethodNameGenerator { get; set; } = options => options.MethodName;\n        public Func<DelegatePluginCatalogOptions, string> TypeNameGenerator { get; set; } = options => options.TypeName;\n        public Func<DelegatePluginCatalogOptions, string> NamespaceNameGenerator { get; set; } = options => options.NamespaceName;\n        public List<string> Tags { get; set; } = new List<string>();\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework/Catalogs/Delegates/ParameterConversion.cs",
    "content": "﻿namespace Weikio.PluginFramework.Catalogs.Delegates\n{\n    public class ParameterConversion\n    {\n        public bool ToConstructor { get; set; }\n        public bool ToPublicProperty { get; set; }\n        public string Name { get; set; }\n    }\n}"
  },
  {
    "path": "src/Weikio.PluginFramework/Catalogs/EmptyPluginCatalog.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Reflection;\nusing System.Threading.Tasks;\nusing Weikio.PluginFramework.Abstractions;\n\nnamespace Weikio.PluginFramework.Catalogs\n{\n    /// <summary>\n    /// Empty Plugin catalog. Doesn't contain anything, is automatically initialized when created. \n    /// </summary>\n    public class EmptyPluginCatalog : IPluginCatalog\n    {\n        /// <inheritdoc />\n        public Task Initialize()\n        {\n            return Task.CompletedTask;\n        }\n\n        /// <inheritdoc />\n        public bool IsInitialized { get; } = true;\n\n        /// <inheritdoc />\n        public List<Plugin> GetPlugins()\n        {\n            return new List<Plugin>();\n        }\n\n        /// <inheritdoc />\n        public Plugin Get(string name, Version version)\n        {\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework/Catalogs/FolderPluginCatalog.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Reflection;\nusing System.Reflection.PortableExecutable;\nusing System.Runtime.InteropServices;\nusing System.Runtime.Loader;\nusing System.Threading.Tasks;\nusing Weikio.PluginFramework.Abstractions;\nusing Weikio.PluginFramework.Context;\nusing Weikio.PluginFramework.TypeFinding;\n\nnamespace Weikio.PluginFramework.Catalogs\n{\n    /// <summary>\n    /// Plugin folder for a single folder (including or excluding subfolders). Locates the plugins from the assemblies (by default this means dll-files).\n    /// </summary>\n    public class FolderPluginCatalog : IPluginCatalog\n    {\n        private readonly string _folderPath;\n        private readonly FolderPluginCatalogOptions _options;\n        private readonly List<AssemblyPluginCatalog> _catalogs = new List<AssemblyPluginCatalog>();\n\n        /// <inheritdoc />\n        public bool IsInitialized { get; private set; }\n\n        private List<Plugin> Plugins\n        {\n            get\n            {\n                return _catalogs.SelectMany(x => x.GetPlugins()).ToList();\n            }\n        }\n\n        public FolderPluginCatalog(string folderPath) : this(folderPath, new FolderPluginCatalogOptions())\n        {\n        }\n\n        public FolderPluginCatalog(string folderPath, FolderPluginCatalogOptions options) : this(folderPath, null, null, options)\n        {\n        }\n\n        public FolderPluginCatalog(string folderPath, Action<TypeFinderCriteriaBuilder> configureFinder) : this(folderPath, configureFinder, null, null)\n        {\n        }\n\n        public FolderPluginCatalog(string folderPath, TypeFinderCriteria finderCriteria) : this(folderPath, finderCriteria, null)\n        {\n        }\n\n        public FolderPluginCatalog(string folderPath, TypeFinderCriteria finderCriteria, FolderPluginCatalogOptions options) : this(folderPath, null,\n            finderCriteria, options)\n        {\n        }\n\n        public FolderPluginCatalog(string folderPath, Action<TypeFinderCriteriaBuilder> configureFinder, FolderPluginCatalogOptions options) : this(folderPath,\n            configureFinder, null, options)\n        {\n        }\n\n        public FolderPluginCatalog(string folderPath, Action<TypeFinderCriteriaBuilder> configureFinder, TypeFinderCriteria finderCriteria,\n            FolderPluginCatalogOptions options)\n        {\n            if (string.IsNullOrWhiteSpace(folderPath))\n            {\n                throw new ArgumentNullException(nameof(folderPath));\n            }\n\n            _folderPath = folderPath;\n            _options = options ?? new FolderPluginCatalogOptions();\n\n            if (_options.TypeFinderOptions == null)\n            {\n                _options.TypeFinderOptions = new TypeFinderOptions();\n            }\n\n            if (_options.TypeFinderOptions.TypeFinderCriterias == null)\n            {\n                _options.TypeFinderOptions.TypeFinderCriterias = new List<TypeFinderCriteria>();\n            }\n\n            if (configureFinder != null)\n            {\n                var builder = new TypeFinderCriteriaBuilder();\n                configureFinder(builder);\n\n                var criteria = builder.Build();\n\n                _options.TypeFinderOptions.TypeFinderCriterias.Add(criteria);\n            }\n\n            if (finderCriteria != null)\n            {\n                _options.TypeFinderOptions.TypeFinderCriterias.Add(finderCriteria);\n            }\n\n            if (_options.TypeFinderCriteria != null)\n            {\n                _options.TypeFinderOptions.TypeFinderCriterias.Add(_options.TypeFinderCriteria);\n            }\n\n            if (_options.TypeFinderCriterias?.Any() == true)\n            {\n                foreach (var typeFinderCriteria in _options.TypeFinderCriterias)\n                {\n                    var crit = typeFinderCriteria.Value;\n                    crit.Tags = new List<string>() { typeFinderCriteria.Key };\n\n                    _options.TypeFinderOptions.TypeFinderCriterias.Add(crit);\n                }\n            }\n        }\n\n        /// <inheritdoc />\n        public List<Plugin> GetPlugins()\n        {\n            return Plugins;\n        }\n\n        /// <inheritdoc />\n        public Plugin Get(string name, Version version)\n        {\n            foreach (var assemblyPluginCatalog in _catalogs)\n            {\n                var plugin = assemblyPluginCatalog.Get(name, version);\n\n                if (plugin == null)\n                {\n                    continue;\n                }\n\n                return plugin;\n            }\n\n            return null;\n        }\n\n        /// <inheritdoc />\n        public async Task Initialize()\n        {\n            var foundFiles = new List<string>();\n\n            foreach (var searchPattern in _options.SearchPatterns)\n            {\n                var dllFiles = Directory.GetFiles(_folderPath, searchPattern,\n                    _options.IncludeSubfolders ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);\n\n                foundFiles.AddRange(dllFiles);\n            }\n\n            foundFiles = foundFiles.Distinct().ToList();\n\n            foreach (var assemblyPath in foundFiles)\n            {\n                // Assemblies are treated as readonly as long as possible\n                var isPluginAssembly = IsPluginAssembly(assemblyPath);\n\n                if (isPluginAssembly == false)\n                {\n                    continue;\n                }\n\n                var assemblyCatalogOptions = new AssemblyPluginCatalogOptions\n                {\n                    PluginLoadContextOptions = _options.PluginLoadContextOptions,\n                    TypeFinderOptions = _options.TypeFinderOptions,\n                    PluginNameOptions = _options.PluginNameOptions\n                };\n\n                // We are actually just delegating the responsibility from FolderPluginCatalog to AssemblyPluginCatalog. \n                var assemblyCatalog = new AssemblyPluginCatalog(assemblyPath, assemblyCatalogOptions);\n                await assemblyCatalog.Initialize();\n\n                _catalogs.Add(assemblyCatalog);\n            }\n\n            IsInitialized = true;\n        }\n\n        private bool IsPluginAssembly(string assemblyPath)\n        {\n            using (Stream stream = File.OpenRead(assemblyPath))\n            using (var reader = new PEReader(stream))\n            {\n                if (!reader.HasMetadata)\n                {\n                    return false;\n                }\n\n                if (_options.TypeFinderOptions?.TypeFinderCriterias?.Any() != true)\n                {\n                    // If there are no type finders configured, assume that each DLL is a plugin\n                    return true;\n                }\n\n                var runtimeDirectory = RuntimeEnvironment.GetRuntimeDirectory();\n                var runtimeAssemblies = Directory.GetFiles(runtimeDirectory, \"*.dll\");\n                var paths = new List<string>(runtimeAssemblies) { assemblyPath };\n\n                if (_options.PluginLoadContextOptions.AdditionalRuntimePaths?.Any() == true)\n                {\n                    foreach (var additionalRuntimePath in _options.PluginLoadContextOptions.AdditionalRuntimePaths)\n                    {\n                        var dlls = Directory.GetFiles(additionalRuntimePath, \"*.dll\");\n                        paths.AddRange(dlls);\n                    }\n                }\n\n                if (_options.PluginLoadContextOptions.UseHostApplicationAssemblies == UseHostApplicationAssembliesEnum.Always)\n                {\n                    var hostApplicationPath = Environment.CurrentDirectory;\n                    var hostDlls = Directory.GetFiles(hostApplicationPath, \"*.dll\", SearchOption.AllDirectories);\n\n                    paths.AddRange(hostDlls);\n\n                    AddSharedFrameworkDlls(hostApplicationPath, runtimeDirectory, paths);\n                }\n                else if (_options.PluginLoadContextOptions.UseHostApplicationAssemblies == UseHostApplicationAssembliesEnum.Never)\n                {\n                    var pluginPath = Path.GetDirectoryName(assemblyPath);\n                    var dllsInPluginPath = Directory.GetFiles(pluginPath, \"*.dll\", SearchOption.AllDirectories);\n\n                    paths.AddRange(dllsInPluginPath);\n                }\n                else if (_options.PluginLoadContextOptions.UseHostApplicationAssemblies == UseHostApplicationAssembliesEnum.Selected)\n                {\n                    foreach (var hostApplicationAssembly in _options.PluginLoadContextOptions.HostApplicationAssemblies)\n                    {\n                        var assembly = Assembly.Load(hostApplicationAssembly);\n                        paths.Add(assembly.Location);\n                    }\n                }\n\n                paths = paths.Distinct().ToList();\n\n                // Also make sure to include only one dll of each. If same dll is found from multiple locations, use the first found dll and remove the others.\n                var duplicateDlls = paths.Select(x => new {FullPath = x, FileName = Path.GetFileName(x)}).GroupBy(x => x.FileName)\n                    .Where(x => x.Count() > 1)\n                    .ToList();\n\n                var removed = new List<string>();\n\n                foreach (var duplicateDll in duplicateDlls)\n                {\n                    foreach (var duplicateDllPath in duplicateDll.Skip(1))\n                    {\n                        removed.Add(duplicateDllPath.FullPath);\n                    }\n                }\n\n                foreach (var re in removed)\n                {\n                    paths.Remove(re);\n                }\n\n                var resolver = new PathAssemblyResolver(paths);\n\n                // We use the metadata (readonly) versions of the assemblies before loading them\n                using (var metadataContext = new MetadataLoadContext(resolver))\n                {\n                    var metadataPluginLoadContext = new MetadataTypeFindingContext(metadataContext);\n                    var readonlyAssembly = metadataContext.LoadFromAssemblyPath(assemblyPath);\n\n                    var typeFinder = new TypeFinder();\n\n                    foreach (var finderCriteria in _options.TypeFinderOptions.TypeFinderCriterias)\n                    {\n                        var typesFound = typeFinder.Find(finderCriteria, readonlyAssembly, metadataPluginLoadContext);\n\n                        if (typesFound?.Any() == true)\n                        {\n                            return true;\n                        }\n                    }\n                }\n            }\n\n            return false;\n        }\n\n        private void AddSharedFrameworkDlls(string hostApplicationPath, string runtimeDirectory, List<string> paths)\n        {\n            // Fixing #23. If the main application references a shared framework (for example WinForms), we want to add these dlls also\n            var defaultAssemblies = AssemblyLoadContext.Default.Assemblies.ToList();\n\n            var defaultAssemblyDirectories = defaultAssemblies.Where(x => x.IsDynamic == false).Where(x => string.IsNullOrWhiteSpace(x.Location) == false)\n                .GroupBy(x => Path.GetDirectoryName(x.Location)).Select(x => x.Key).ToList();\n\n            foreach (var assemblyDirectory in defaultAssemblyDirectories)\n            {\n                if (string.Equals(assemblyDirectory.TrimEnd('\\\\').TrimEnd('/'), hostApplicationPath.TrimEnd('\\\\').TrimEnd('/')))\n                {\n                    continue;\n                }\n\n                if (string.Equals(assemblyDirectory.TrimEnd('\\\\').TrimEnd('/'), runtimeDirectory.TrimEnd('\\\\').TrimEnd('/')))\n                {\n                    continue;\n                }\n\n                if (_options.PluginLoadContextOptions.AdditionalRuntimePaths == null)\n                {\n                    _options.PluginLoadContextOptions.AdditionalRuntimePaths = new List<string>();\n                }\n\n                if (_options.PluginLoadContextOptions.AdditionalRuntimePaths.Contains(assemblyDirectory) == false)\n                {\n                    _options.PluginLoadContextOptions.AdditionalRuntimePaths.Add(assemblyDirectory);\n                }\n\n                var dlls = Directory.GetFiles(assemblyDirectory, \"*.dll\");\n                paths.AddRange(dlls);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework/Catalogs/FolderPluginCatalogOptions.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing Weikio.PluginFramework.Abstractions;\nusing Weikio.PluginFramework.Context;\nusing Weikio.PluginFramework.TypeFinding;\n\nnamespace Weikio.PluginFramework.Catalogs\n{\n    /// <summary>\n    /// Options for configuring how the <see cref=\"FolderPluginCatalog\"/> works.\n    /// </summary>\n    public class FolderPluginCatalogOptions\n    {\n        /// <summary>\n        /// Gets or sets if subfolders should be included. Defaults to true.\n        /// </summary>\n        public bool IncludeSubfolders { get; set; } = true;\n\n        /// <summary>\n        /// Gets or sets the search patterns when locating plugins. By default only located dll-files.\n        /// </summary>\n        public List<string> SearchPatterns { get; set; } = new List<string>() { \"*.dll\" };\n\n        /// <summary>\n        /// Gets or sets the <see cref=\"PluginLoadContextOptions\"/>.\n        /// </summary>\n        public PluginLoadContextOptions PluginLoadContextOptions { get; set; } = new PluginLoadContextOptions();\n\n        /// <summary>\n        /// Gets or sets a single type finder criteria\n        /// </summary>\n        [Obsolete(\"Please use TypeFinderOptions. This will be removed in a future release.\")]\n        public TypeFinderCriteria TypeFinderCriteria { get; set; }\n\n        /// <summary>\n        /// Gets or sets a collection of type finder criteria. The key is used to \"tag\" found plugins.\n        /// </summary>\n        [Obsolete(\"Please use TypeFinderOptions. This will be removed in a future release.\")]\n        public Dictionary<string, TypeFinderCriteria> TypeFinderCriterias { get; set; } = new Dictionary<string, TypeFinderCriteria>();\n\n        /// <summary>\n        /// Gets or sets the <see cref=\"TypeFinderOptions\"/>.\n        /// </summary>\n        public TypeFinderOptions TypeFinderOptions { get; set; } = new TypeFinderOptions();\n\n        /// <summary>\n        /// Gets or sets how the plugin names and version should be defined. <seealso cref=\"PluginNameOptions\"/>\n        /// </summary>\n        public PluginNameOptions PluginNameOptions { get; set; } = Defaults.PluginNameOptions;\n        \n        public static class Defaults\n        {\n            public static PluginNameOptions PluginNameOptions { get; set; } = new PluginNameOptions();\n        }\n        \n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework/Catalogs/TypePluginCatalog.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing System.Threading.Tasks;\nusing Weikio.PluginFramework.Abstractions;\nusing Weikio.PluginFramework.Context;\nusing Weikio.PluginFramework.TypeFinding;\n\nnamespace Weikio.PluginFramework.Catalogs\n{\n    /// <summary>\n    /// Plugin Catalog for a single .NET Type.\n    /// </summary>\n    public class TypePluginCatalog : IPluginCatalog\n    {\n        private readonly Type _pluginType;\n        private readonly TypePluginCatalogOptions _options;\n        private Plugin _plugin;\n\n        /// <summary>\n        /// Gets the <see cref=\"TypePluginCatalogOptions\"/> for this catalog\n        /// </summary>\n        public TypePluginCatalogOptions Options\n        {\n            get\n            {\n                return _options;\n            }\n        }\n\n        public TypePluginCatalog(Type pluginType) : this(pluginType, null, null, null)\n        {\n        }\n\n        public TypePluginCatalog(Type pluginType, PluginNameOptions nameOptions) : this(pluginType, null, nameOptions, null)\n        {\n        }\n\n        public TypePluginCatalog(Type pluginType, Action<PluginNameOptions> configure) : this(pluginType, configure, null, null)\n        {\n        }\n\n        public TypePluginCatalog(Type pluginType, TypePluginCatalogOptions options) : this(pluginType, null, null, options)\n        {\n        }\n\n        public TypePluginCatalog(Type pluginType, Action<PluginNameOptions> configure, PluginNameOptions nameOptions, TypePluginCatalogOptions options)\n        {\n            if (pluginType == null)\n            {\n                throw new ArgumentNullException(nameof(pluginType));\n            }\n\n            _pluginType = pluginType;\n            _options = options ?? new TypePluginCatalogOptions();\n\n            if (_options.TypeFinderCriterias == null)\n            {\n                _options.TypeFinderCriterias = new Dictionary<string, TypeFinderCriteria>();\n            }\n\n            if (_options.TypeFinderCriterias.Any() != true)\n            {\n                _options.TypeFinderCriterias.Add(string.Empty, new TypeFinderCriteria() { Query = (context, type) => true });\n            }\n\n            if (_options.TypeFindingContext == null)\n            {\n                _options.TypeFindingContext = new PluginAssemblyLoadContext(pluginType.Assembly);\n            }\n\n            if (_options.TypeFinderOptions == null)\n            {\n                _options.TypeFinderOptions = new TypeFinderOptions();\n            }\n\n            if (_options.TypeFinderOptions.TypeFinderCriterias?.Any() != true)\n            {\n                _options.TypeFinderOptions.TypeFinderCriterias = new List<TypeFinderCriteria>();\n\n                if (_options.TypeFinderCriterias?.Any() == true)\n                {\n                    foreach (var typeFinderCriteria in _options.TypeFinderCriterias)\n                    {\n                        var typeFinder = typeFinderCriteria.Value;\n                        typeFinder.Tags = new List<string>() { typeFinderCriteria.Key };\n\n                        _options.TypeFinderOptions.TypeFinderCriterias.Add(typeFinder);\n                    }\n                }\n            }\n\n            if (configure == null && nameOptions == null)\n            {\n                return;\n            }\n\n            var naming = nameOptions ?? new PluginNameOptions();\n            configure?.Invoke(naming);\n\n            _options.PluginNameOptions = naming;\n        }\n\n        public Task Initialize()\n        {\n            var namingOptions = _options.PluginNameOptions;\n            var version = namingOptions.PluginVersionGenerator(namingOptions, _pluginType);\n            var pluginName = namingOptions.PluginNameGenerator(namingOptions, _pluginType);\n            var description = namingOptions.PluginDescriptionGenerator(namingOptions, _pluginType);\n            var productVersion = namingOptions.PluginProductVersionGenerator(namingOptions, _pluginType);\n\n            var tags = new List<string>();\n\n            var finder = new TypeFinder();\n\n            foreach (var typeFinderCriteria in _options.TypeFinderOptions.TypeFinderCriterias)\n            {\n                var isMatch = finder.IsMatch(typeFinderCriteria, _pluginType, _options.TypeFindingContext);\n\n                if (isMatch)\n                {\n                    if (typeFinderCriteria.Tags?.Any() == true)\n                    {\n                        tags.AddRange(typeFinderCriteria.Tags);\n                    }\n                }\n            }\n\n            _plugin = new Plugin(_pluginType.Assembly, _pluginType, pluginName, version, this, description, productVersion, tags: tags);\n\n            IsInitialized = true;\n\n            return Task.CompletedTask;\n        }\n\n        /// <inheritdoc />\n        public bool IsInitialized { get; private set; }\n\n        /// <inheritdoc />\n        public List<Plugin> GetPlugins()\n        {\n            return new List<Plugin>() { _plugin };\n        }\n\n        /// <inheritdoc />\n        public Plugin Get(string name, Version version)\n        {\n            if (!string.Equals(name, _plugin.Name, StringComparison.InvariantCultureIgnoreCase) ||\n                version != _plugin.Version)\n            {\n                return null;\n            }\n\n            return _plugin;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework/Catalogs/TypePluginCatalogOptions.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing Weikio.PluginFramework.Abstractions;\nusing Weikio.PluginFramework.TypeFinding;\n\nnamespace Weikio.PluginFramework.Catalogs\n{\n    /// <summary>\n    /// Options for configuring how the <see cref=\"TypePluginCatalogOptions\"/> works.\n    /// </summary>\n    public class TypePluginCatalogOptions\n    {\n        /// <summary>\n        /// Gets or sets how the plugin names and version should be defined. <seealso cref=\"PluginNameOptions\"/>.\n        /// </summary>\n        public PluginNameOptions PluginNameOptions { get; set; } = Defaults.PluginNameOptions;\n\n        [Obsolete(\"Please use TypeFinderOptions. This will be removed in a future release.\")]\n        public Dictionary<string, TypeFinderCriteria> TypeFinderCriterias = new Dictionary<string, TypeFinderCriteria>();\n        \n        /// <summary>\n        /// Gets or sets the <see cref=\"TypeFinderOptions\"/>. \n        /// </summary>\n        public TypeFinderOptions TypeFinderOptions { get; set; } = new TypeFinderOptions();\n\n        /// <summary>\n        /// Gets or sets the <see cref=\"ITypeFindingContext\"/>.\n        /// </summary>\n        public ITypeFindingContext TypeFindingContext { get; set; } = null;\n        \n        public static class Defaults\n        {\n            public static PluginNameOptions PluginNameOptions { get; set; } = new PluginNameOptions();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework/Context/MetadataTypeFindingContext.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing System.Reflection;\nusing Weikio.PluginFramework.TypeFinding;\n\nnamespace Weikio.PluginFramework.Context\n{\n    public class MetadataTypeFindingContext : ITypeFindingContext\n    {\n        private readonly MetadataLoadContext _metadataLoadContext;\n\n        public MetadataTypeFindingContext(MetadataLoadContext metadataLoadContext)\n        {\n            _metadataLoadContext = metadataLoadContext;\n        }\n\n        public Assembly FindAssembly(string assemblyName)\n        {\n            var result = _metadataLoadContext.LoadFromAssemblyName(assemblyName);\n\n            return result;\n        }\n\n        public Type FindType(Type type)\n        {\n            var assemblyName = type.Assembly.GetName();\n            var assemblies = _metadataLoadContext.GetAssemblies();\n\n            var assembly = assemblies.FirstOrDefault(x => string.Equals(x.FullName, assemblyName.FullName));\n\n            if (assembly == null)\n            {\n                assembly = _metadataLoadContext.LoadFromAssemblyName(assemblyName);\n            }\n\n            var result = assembly.GetType(type.FullName);\n\n            return result;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework/Context/PluginAssemblyLoadContext.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Data;\nusing System.IO;\nusing System.Linq;\nusing System.Reflection;\nusing System.Runtime.Loader;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Logging.Abstractions;\nusing Weikio.PluginFramework.Catalogs;\nusing Weikio.PluginFramework.TypeFinding;\n\nnamespace Weikio.PluginFramework.Context\n{\n    /// <summary>\n    /// Defines a Plugin Load Context which allows the loading of plugin specific version's of assemblies.\n    /// </summary>\n    public class PluginAssemblyLoadContext : AssemblyLoadContext, ITypeFindingContext\n    {\n        private readonly string _pluginPath;\n        private readonly AssemblyDependencyResolver _resolver;\n        private readonly PluginLoadContextOptions _options;\n        private readonly List<RuntimeAssemblyHint> _runtimeAssemblyHints;\n\n        public PluginAssemblyLoadContext(Assembly assembly, PluginLoadContextOptions options = null) : this(assembly.Location, options)\n        {\n        }\n        \n        public PluginAssemblyLoadContext(string pluginPath, PluginLoadContextOptions options = null) : base(true)\n        {\n            _pluginPath = pluginPath;\n            _resolver = new AssemblyDependencyResolver(pluginPath);\n            _options = options ?? new PluginLoadContextOptions();\n            \n            _runtimeAssemblyHints = _options.RuntimeAssemblyHints;\n\n            if (_runtimeAssemblyHints == null)\n            {\n                _runtimeAssemblyHints = new List<RuntimeAssemblyHint>();\n            }\n        }\n\n        public Assembly Load()\n        {\n            var assemblyName = new AssemblyName(Path.GetFileNameWithoutExtension(_pluginPath));\n\n            var result = LoadFromAssemblyName(assemblyName);\n\n            return result;\n        }\n\n        protected override Assembly Load(AssemblyName assemblyName)\n        {\n            Log(LogLevel.Debug, \"Loading {AssemblyName}\", args: assemblyName);\n\n            if (TryUseHostApplicationAssembly(assemblyName))\n            {\n                var foundFromHostApplication = LoadHostApplicationAssembly(assemblyName);\n\n                if (foundFromHostApplication)\n                {\n                    Log(LogLevel.Debug, \"Assembly {AssemblyName} is available through host application's AssemblyLoadContext. Use it. \", ex: null,\n                        assemblyName);\n\n                    return null;\n                }\n\n                Log(LogLevel.Debug,\n                    \"Host application's AssemblyLoadContext doesn't contain {AssemblyName}. Try to resolve it through the plugin's references.\", ex: null,\n                    assemblyName);\n            }\n\n            string assemblyPath;\n\n            var assemblyFileName = assemblyName.Name + \".dll\";\n\n            if (_runtimeAssemblyHints.Any(x => string.Equals(assemblyFileName, x.FileName)))\n            {\n                Log(LogLevel.Debug, \"Found assembly hint for {AssemblyName}\", ex: null, assemblyName);\n                assemblyPath = _runtimeAssemblyHints.First(x => string.Equals(assemblyFileName, x.FileName)).Path;\n            }\n            else\n            {\n                Log(LogLevel.Debug, \"No assembly hint found for {AssemblyName}. Using the default resolver for locating the file\", ex: null, assemblyName);\n                assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);\n            }\n\n            if (assemblyPath != null)\n            {\n                Log(LogLevel.Debug, \"Loading {AssemblyName} into AssemblyLoadContext from {Path}\", ex: null, assemblyName, assemblyPath);\n\n                var result = LoadFromAssemblyPath(assemblyPath);\n                return result;\n            }\n\n            if (_options.UseHostApplicationAssemblies == UseHostApplicationAssembliesEnum.PreferPlugin)\n            {\n                var foundFromHostApplication = LoadHostApplicationAssembly(assemblyName);\n\n                if (foundFromHostApplication)\n                {\n                    Log(LogLevel.Debug, \"Assembly {AssemblyName} not available from plugin's references but is available through host application's AssemblyLoadContext. Use it. \", ex: null,\n                        assemblyName);\n\n                    return null;\n                }\n            }\n\n            if (_options.AdditionalRuntimePaths?.Any() != true)\n            {\n                Log(LogLevel.Warning, \"Couldn't locate assembly using {AssemblyName}. Please try adding AdditionalRuntimePaths using \" + nameof(PluginLoadContextOptions.Defaults.AdditionalRuntimePaths), ex: null, assemblyName);\n\n                return null;\n            }\n\n            // Solving issue 23. The project doesn't reference WinForms but the plugin does.\n            // Try to locate the required dll using AdditionalRuntimePaths\n            foreach (var runtimePath in _options.AdditionalRuntimePaths)\n            {\n                var fileName = assemblyFileName;\n                var filePath = Directory.GetFiles(runtimePath, fileName, SearchOption.AllDirectories).FirstOrDefault();\n\n                if (filePath != null)\n                {\n                    Log(LogLevel.Debug, \"Located {AssemblyName} to {AssemblyPath} using {AdditionalRuntimePath}\", ex: null, assemblyName, filePath, runtimePath);\n\n                    return LoadFromAssemblyPath(filePath);\n                }\n            }\n\n            Log(LogLevel.Warning, \"Couldn't locate assembly using {AssemblyName}. Didn't find the assembly from AdditionalRuntimePaths. Please try adding AdditionalRuntimePaths using \" + nameof(PluginLoadContextOptions.Defaults.AdditionalRuntimePaths), ex: null, assemblyName);\n\n            return null;\n        }\n\n        private bool TryUseHostApplicationAssembly(AssemblyName assemblyName)\n        {\n            Log(LogLevel.Debug, \"Determining if {AssemblyName} should be loaded from host application's or from plugin's AssemblyLoadContext\",\n                args: assemblyName);\n\n            if (_options.UseHostApplicationAssemblies == UseHostApplicationAssembliesEnum.Never)\n            {\n                Log(LogLevel.Debug, \"UseHostApplicationAssemblies is set to Never. Try to load assembly from plugin's AssemblyLoadContext\", args: assemblyName);\n\n                return false;\n            }\n\n            if (_options.UseHostApplicationAssemblies == UseHostApplicationAssembliesEnum.Always)\n            {\n                Log(LogLevel.Debug, \"UseHostApplicationAssemblies is set to Always. Try to load assembly from host application's AssemblyLoadContext\",\n                    args: assemblyName);\n\n                return true;\n            }\n\n            if (_options.UseHostApplicationAssemblies == UseHostApplicationAssembliesEnum.Selected)\n            {\n                var name = assemblyName.Name;\n\n                var result = _options.HostApplicationAssemblies?.Any(x => string.Equals(x.Name, name, StringComparison.InvariantCultureIgnoreCase)) == true;\n\n                Log(LogLevel.Debug, \"UseHostApplicationAssemblies is set to Selected. {AssemblyName} listed in the HostApplicationAssemblies: {Result}\", ex: null,\n                    assemblyName, result);\n\n                return result;\n            }\n\n            if (_options.UseHostApplicationAssemblies == UseHostApplicationAssembliesEnum.PreferPlugin)\n            {\n                Log(LogLevel.Debug, \"UseHostApplicationAssemblies is set to PreferPlugin. Try to load assembly from plugin's AssemblyLoadContext and fallback to host application's AssemblyLoadContext\",\n                    args: assemblyName);\n\n                return false;\n            }\n            \n            return false;\n        }\n\n        private bool LoadHostApplicationAssembly(AssemblyName assemblyName)\n        {\n            try\n            {\n                Default.LoadFromAssemblyName(assemblyName);\n\n                return true;\n            }\n            catch\n            {\n                return false;\n            }\n        }\n        \n        protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)\n        {\n            var nativeHint = _runtimeAssemblyHints.FirstOrDefault(x => x.IsNative && string.Equals(x.FileName, unmanagedDllName));\n\n            if (nativeHint != null)\n            {\n                return  LoadUnmanagedDllFromPath(nativeHint.Path);\n            }\n            \n            var libraryPath = _resolver.ResolveUnmanagedDllToPath(unmanagedDllName);\n\n            if (libraryPath != null)\n            {\n                return LoadUnmanagedDllFromPath(libraryPath);\n            }\n            \n            return IntPtr.Zero;\n        }\n\n        private void Log(LogLevel logLevel, string message, Exception ex = null, params object[] args)\n        {\n            var logger = GetLogger();\n\n            logger.Log(logLevel, ex, message, args);\n        }\n\n        private static string loggerLock = \"lock\";\n        private ILogger<PluginAssemblyLoadContext> _logger;\n\n        private ILogger<PluginAssemblyLoadContext> GetLogger()\n        {\n            // ReSharper disable once InvertIf\n            if (_logger == null)\n            {\n                lock (loggerLock)\n                {\n                    if (_logger == null)\n                    {\n                        if (_options?.LoggerFactory == null)\n                        {\n                            _logger = NullLogger<PluginAssemblyLoadContext>.Instance;\n                        }\n                        else\n                        {\n                            _logger = _options.LoggerFactory();\n                        }\n                    }\n                }\n            }\n\n            return _logger;\n        }\n\n        public Assembly FindAssembly(string assemblyName)\n        {\n            return Load(new AssemblyName(assemblyName));\n        }\n\n        public Type FindType(Type type)\n        {\n            var assemblyName = type.Assembly.GetName();\n            var assembly = Load(assemblyName);\n\n            if (assembly == null)\n            {\n                assembly = Assembly.Load(assemblyName);\n            }\n\n            var result = assembly.GetType(type.FullName);\n\n            return result;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework/Context/PluginLoadContextOptions.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Reflection;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Logging.Abstractions;\n\nnamespace Weikio.PluginFramework.Context\n{\n    /// <summary>\n    /// Options for PluginLoadContext\n    /// </summary>\n    public class PluginLoadContextOptions\n    {\n        /// <summary>\n        /// 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\n        /// and the plugin use the same version of the assembly, even if they reference different versions.\n        /// </summary>\n        public UseHostApplicationAssembliesEnum UseHostApplicationAssemblies { get; set; } = Defaults.UseHostApplicationAssemblies;\n\n        /// <summary>\n        /// Gets or sets the assemblies which the plugin should use if UseHostApplicationAssemblies is set to Selected. These assemblies are used\n        /// even if the plugin itself references an another version of the same assembly.\n        /// </summary>\n        public List<AssemblyName> HostApplicationAssemblies { get; set; } = Defaults.HostApplicationAssemblies;\n\n        /// <summary>\n        /// Gets or sets the function which is used to create the logger for PluginLoadContextOptions\n        /// </summary>\n        public Func<ILogger<PluginAssemblyLoadContext>> LoggerFactory { get; set; } = Defaults.LoggerFactory;\n\n        /// <summary>\n        /// Gets or sets the additional runtime paths which are used when locating plugin assemblies  \n        /// </summary>\n        public List<string> AdditionalRuntimePaths { get; set; } = Defaults.AdditionalRuntimePaths;\n\n        /// <summary>\n        /// 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.\n        /// </summary>\n        public List<RuntimeAssemblyHint> RuntimeAssemblyHints { get; set; } = Defaults.RuntimeAssemblyHints;\n        \n        public static class Defaults\n        {\n            /// <summary>\n            /// 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\n            /// and the plugin use the same version of the assembly, even if they reference different versions. \n            /// </summary>\n            public static UseHostApplicationAssembliesEnum UseHostApplicationAssemblies { get; set; } = UseHostApplicationAssembliesEnum.Always;\n\n            /// <summary>\n            /// Gets or sets the assemblies which the plugin should use if UseHostApplicationAssemblies is set to Selected. These assemblies are used\n            /// even if the plugin itself references an another version of the same assembly.\n            /// </summary>\n            public static List<AssemblyName> HostApplicationAssemblies { get; set; } = new List<AssemblyName>();\n\n            /// <summary>\n            /// Gets or sets the function which is used to create the logger for PluginLoadContextOptions\n            /// </summary>\n            public static Func<ILogger<PluginAssemblyLoadContext>> LoggerFactory { get; set; } = () => NullLogger<PluginAssemblyLoadContext>.Instance;\n            \n            /// <summary>\n            /// Gets or sets the additional runtime paths which are used when locating plugin assemblies  \n            /// </summary>\n            public static List<string> AdditionalRuntimePaths { get; set; } = new List<string>();\n\n            /// <summary>\n            /// 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.\n            /// </summary>\n            public static List<RuntimeAssemblyHint> RuntimeAssemblyHints { get; set; } = new List<RuntimeAssemblyHint>();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework/Context/RuntimeAssemblyHint.cs",
    "content": "namespace Weikio.PluginFramework.Context\n{\n    public class RuntimeAssemblyHint\n    {\n        public string FileName { get; set; }\n        public string Path { get; set; }\n        public bool IsNative { get; set; }\n\n        public RuntimeAssemblyHint(string fileName, string path, bool isNative)\n        {\n            FileName = fileName;\n            Path = path;\n            IsNative = isNative;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework/Context/UseHostApplicationAssembliesEnum.cs",
    "content": "﻿namespace Weikio.PluginFramework.Context\n{\n    public enum UseHostApplicationAssembliesEnum\n    {\n        /// <summary>\n        /// Never use user host application's assemblies\n        /// </summary>\n        Never,\n        \n        /// <summary>\n        /// Only use the listed hosted application assemblies\n        /// </summary>\n        Selected,\n        \n        /// <summary>\n        /// Always try to use host application's assemblies\n        /// </summary>\n        Always,\n        \n        /// <summary>\n        /// Prefer plugin's referenced assemblies, fallback to host application's assemblies\n        /// </summary>\n        PreferPlugin\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework/TypeFinding/ITypeFindingContext.cs",
    "content": "﻿using System;\nusing System.Reflection;\n\nnamespace Weikio.PluginFramework.TypeFinding\n{\n    public interface ITypeFindingContext\n    {\n        Assembly FindAssembly(string assemblyName);\n        Type FindType(Type type);\n    }\n}"
  },
  {
    "path": "src/Weikio.PluginFramework/TypeFinding/TypeFinder.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Reflection;\nusing System.Text.RegularExpressions;\n\nnamespace Weikio.PluginFramework.TypeFinding\n{\n    public class TypeFinder\n    {\n        public bool IsMatch(TypeFinderCriteria criteria, Type type, ITypeFindingContext typeFindingContext)\n        {\n            if (criteria.Query != null)\n            {\n                var isMatch = criteria.Query(typeFindingContext, type);\n\n                if (isMatch == false)\n                {\n                    return false;\n                }\n\n                return true;\n            }\n\n            if (criteria.IsAbstract != null)\n            {\n                if (type.IsAbstract != criteria.IsAbstract.GetValueOrDefault())\n                {\n                    return false;\n                }\n            }\n\n            if (criteria.IsInterface != null)\n            {\n                if (type.IsInterface != criteria.IsInterface.GetValueOrDefault())\n                {\n                    return false;\n                }\n            }\n\n            if (string.IsNullOrWhiteSpace(criteria.Name) == false)\n            {\n                var regEx = NameToRegex(criteria.Name);\n\n                if (regEx.IsMatch(type.FullName) == false)\n                {\n                    var hasDirectNamingMatch = string.Equals(criteria.Name, type.Name, StringComparison.InvariantCultureIgnoreCase) ||\n                                               string.Equals(criteria.Name, type.FullName, StringComparison.InvariantCultureIgnoreCase);\n\n                    if (hasDirectNamingMatch == false)\n                    {\n                        return false;\n                    }\n                }\n            }\n\n            if (criteria.Inherits != null)\n            {\n                var inheritedType = typeFindingContext.FindType(criteria.Inherits);\n\n                if (inheritedType.IsAssignableFrom(type) == false)\n                {\n                    return false;\n                }\n            }\n\n            if (criteria.Implements != null)\n            {\n                var interfaceType = typeFindingContext.FindType(criteria.Implements);\n\n                if (interfaceType.IsAssignableFrom(type) == false)\n                {\n                    return false;\n                }\n            }\n\n            if (criteria.AssignableTo != null)\n            {\n                var assignableToType = typeFindingContext.FindType(criteria.AssignableTo);\n\n                if (assignableToType.IsAssignableFrom(type) == false)\n                {\n                    return false;\n                }\n            }\n\n            if (criteria.HasAttribute != null)\n            {\n                var attributes = type.GetCustomAttributesData();\n                var attributeFound = false;\n\n                foreach (var attributeData in attributes)\n                {\n                    if (string.Equals(attributeData.AttributeType.FullName, criteria.HasAttribute.FullName, StringComparison.InvariantCultureIgnoreCase) ==\n                        false)\n                    {\n                        continue;\n                    }\n\n                    attributeFound = true;\n\n                    break;\n                }\n\n                if (attributeFound == false)\n                {\n                    return false;\n                }\n            }\n\n            return true;\n        }\n\n        public List<Type> Find(TypeFinderCriteria criteria, Assembly assembly, ITypeFindingContext typeFindingContext)\n        {\n            if (criteria == null)\n            {\n                throw new ArgumentNullException(nameof(criteria));\n            }\n\n            var result = new List<Type>();\n\n            var types = assembly.GetExportedTypes();\n\n            foreach (var type in types)\n            {\n                var isMatch = IsMatch(criteria, type, typeFindingContext);\n\n                if (isMatch == false)\n                {\n                    continue;\n                }\n                \n                result.Add(type);\n            }\n\n            return result;\n        }\n\n        private static Regex NameToRegex(string nameFilter)\n        {\n            // https://stackoverflow.com/a/30300521/66988\n            var regex = \"^\" + Regex.Escape(nameFilter).Replace(\"\\\\?\", \".\").Replace(\"\\\\*\", \".*\") + \"$\";\n\n            return new Regex(regex, RegexOptions.Compiled);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework/TypeFinding/TypeFinderCriteria.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace Weikio.PluginFramework.TypeFinding\n{\n    public class TypeFinderCriteria\n    {\n        public Type Inherits { get; set; }\n        public Type Implements { get; set; }\n        public Type AssignableTo { get; set; }\n        public bool? IsAbstract { get; set; }\n        public bool? IsInterface { get; set; }\n        public string Name { get; set; }\n        public Func<ITypeFindingContext, Type, bool> Query { get; set; }\n        public Type HasAttribute { get; set; }\n        public List<string> Tags { get; set; } = new List<string>();\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework/TypeFinding/TypeFinderCriteriaBuilder.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace Weikio.PluginFramework.TypeFinding\n{\n    public class TypeFinderCriteriaBuilder\n    {\n        private Type _inherits;\n        private Type _implements;\n        private Type _assignable;\n        private bool? _isAbstract = false;\n        private bool? _isInterface = false;\n        private string _name;\n        private Type _attribute;\n        private List<string> _tags = new List<string>();\n\n        public TypeFinderCriteria Build()\n        {\n            var res = new TypeFinderCriteria\n            {\n                IsInterface = _isInterface,\n                Implements = _implements,\n                Inherits = _inherits,\n                AssignableTo = _assignable,\n                Name = _name,\n                IsAbstract = _isAbstract,\n                HasAttribute = _attribute,\n                Tags = _tags\n            };\n\n            return res;\n        }\n\n        public static implicit operator TypeFinderCriteria(TypeFinderCriteriaBuilder criteriaBuilder)\n        {\n            return criteriaBuilder.Build();\n        }\n\n        public static TypeFinderCriteriaBuilder Create()\n        {\n            return new TypeFinderCriteriaBuilder();\n        }\n\n        public TypeFinderCriteriaBuilder HasName(string name)\n        {\n            _name = name;\n\n            return this;\n        }\n\n        public TypeFinderCriteriaBuilder Implements<T>()\n        {\n            return Implements(typeof(T));\n        }\n\n        public TypeFinderCriteriaBuilder Implements(Type t)\n        {\n            _implements = t;\n\n            return this;\n        }\n\n        public TypeFinderCriteriaBuilder Inherits<T>()\n        {\n            return Inherits(typeof(T));\n        }\n\n        public TypeFinderCriteriaBuilder Inherits(Type t)\n        {\n            _inherits = t;\n\n            return this;\n        }\n\n        public TypeFinderCriteriaBuilder IsAbstract(bool? isAbstract)\n        {\n            _isAbstract = isAbstract;\n\n            return this;\n        }\n\n        public TypeFinderCriteriaBuilder IsInterface(bool? isInterface)\n        {\n            _isInterface = isInterface;\n\n            return this;\n        }\n        \n        public TypeFinderCriteriaBuilder AssignableTo(Type assignableTo)\n        {\n            _assignable = assignableTo;\n\n            return this;\n        }\n\n        public TypeFinderCriteriaBuilder HasAttribute(Type attribute)\n        {\n            _attribute = attribute;\n\n            return this;\n        }\n\n        public TypeFinderCriteriaBuilder Tag(string tag)\n        {\n            if (_tags == null)\n            {\n                _tags = new List<string>();\n            }\n            \n            if (_tags.Contains(tag))\n            {\n                return this;\n            }\n            \n            _tags.Add(tag);\n\n            return this;\n        }\n        \n        public TypeFinderCriteriaBuilder Tag(params string[] tags)\n        {\n            if (_tags == null)\n            {\n                _tags = new List<string>();\n            }\n\n            foreach (var tag in tags)\n            {\n                if (_tags.Contains(tag))\n                {\n                    continue;\n                }\n            \n                _tags.Add(tag);\n            }\n\n\n            return this;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework/TypeFinding/TypeFinderOptions.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Collections.ObjectModel;\n\nnamespace Weikio.PluginFramework.TypeFinding\n{\n    public class TypeFinderOptions\n    {\n        /// <summary>\n        /// Gets or sets the <see cref=\"TypeFinderCriteria\"/>\n        /// </summary>\n        public List<TypeFinderCriteria> TypeFinderCriterias { get; set; } = new List<TypeFinderCriteria>(Defaults.GetDefaultTypeFinderCriterias());\n\n        public static class Defaults\n        {\n            public static List<TypeFinderCriteria> TypeFinderCriterias { get; set; } = new List<TypeFinderCriteria>();\n\n            public static ReadOnlyCollection<TypeFinderCriteria> GetDefaultTypeFinderCriterias()\n            {\n                return TypeFinderCriterias.AsReadOnly();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework/Weikio.PluginFramework.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFrameworks>netcoreapp3.1;net6.0</TargetFrameworks>\n    <IsPackable>true</IsPackable>\n    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>\n    <Description>Plugin Framework is a powerful plugin platform for your .NET applications.</Description>\n    <PackageDescription>Everything is a plugin! Use assemblies, NuGet packages and C# Scripts as plugins in your .NET Applications.</PackageDescription>\n    <PackageId>Weikio.PluginFramework</PackageId>\n    <Product>Weikio.PluginFramework</Product>\n    <AssemblyName>Weikio.PluginFramework</AssemblyName>\n    <PackageTags>plugins;addons;extensions;plugin framework</PackageTags>\n    <PackageIcon>logo_transparent_color_256.png</PackageIcon>\n    <Title>Plugin Framework</Title>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <None Include=\"../../docs/logo_transparent_color_256.png\" Pack=\"true\" Visible=\"false\" PackagePath=\"\" />\n    <None Include=\"../../readme.md\" Pack=\"true\" Visible=\"false\" PackagePath=\"\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"MinVer\" Version=\"2.0.*\" PrivateAssets=\"all\" />\n    <PackageReference Include=\"System.Reflection.MetadataLoadContext\" Version=\"4.7.1\" />\n    <PackageReference Include=\"Microsoft.Extensions.Logging\" Version=\"3.1.2\" />\n    <PackageReference Include=\"Microsoft.CodeAnalysis.CSharp\" Version=\"3.3.1\" />\n    <PackageReference Include=\"Weikio.TypeGenerator\" Version=\"1.4.1\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Weikio.PluginFramework.Abstractions\\Weikio.PluginFramework.Abstractions.csproj\" />\n  </ItemGroup>\n  \n</Project>\n"
  },
  {
    "path": "src/Weikio.PluginFramework.Abstractions/IPluginCatalog.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Reflection;\nusing System.Threading.Tasks;\n\nnamespace Weikio.PluginFramework.Abstractions\n{\n    /// <summary>\n    /// Represents a single Plugin Catalog. Can contain 0-n plugins.\n    /// </summary>\n    public interface IPluginCatalog\n    {\n        /// <summary>\n        /// Initializes the catalog\n        /// </summary>\n        Task Initialize();\n        \n        /// <summary>\n        /// Gets if the catalog is initialized\n        /// </summary>\n        bool IsInitialized { get; }\n        \n        /// <summary>\n        /// Gets all the plugins\n        /// </summary>\n        /// <returns>List of <see cref=\"Plugin\"/></returns>\n        List<Plugin> GetPlugins();\n        \n        /// <summary>\n        /// Gets a single plugin based on its name and version\n        /// </summary>\n        /// <returns>The <see cref=\"Plugin\"/></returns>\n        Plugin Get(string name, Version version);\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework.Abstractions/IPluginCatalogExtensions.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\n\nnamespace Weikio.PluginFramework.Abstractions\n{\n    public static class IPluginCatalogExtensions\n    {\n        /// <summary>\n        /// Gets the only plugin inside the catalog. Throws if there is none or multiple.\n        /// </summary>\n        /// <param name=\"catalog\">The catalog from which the plugin is retrieved.</param>\n        /// <returns>The plugin</returns>\n        public static Plugin Single(this IPluginCatalog catalog)\n        {\n            var plugins = catalog.GetPlugins();\n\n            return plugins.Single();\n        }\n        \n        /// <summary>\n        /// Gets the only plugin inside the catalog. Throws if there is none or multiple.\n        /// </summary>\n        /// <param name=\"catalog\">The catalog from which the plugin is retrieved.</param>\n        /// <returns>The plugin</returns>\n        public static Plugin Get(this IPluginCatalog catalog)\n        {\n            return catalog.Single();\n        }\n\n        /// <summary>\n        /// Gets the plugins by tag.\n        /// </summary>\n        /// <param name=\"catalog\">The catalog from which the plugin is retrieved.</param>\n        /// <param name=\"tag\">The tag.</param>\n        /// <returns>The plugin</returns>\n        public static List<Plugin> GetByTag(this IPluginCatalog catalog, string tag)\n        {\n            return catalog.GetPlugins().Where(x => x.Tags.Contains(tag)).ToList();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework.Abstractions/Plugin.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\n\nnamespace Weikio.PluginFramework.Abstractions\n{\n    /// <summary>\n    /// Represents a single Plugin. Each plugin has a name, version and .NET Type. \n    /// </summary>\n    public class Plugin\n    {\n        /// <summary>\n        /// Gets the name of the plugin\n        /// </summary>\n        public string Name { get; }\n\n        /// <summary>\n        /// Gets the plugin version\n        /// </summary>\n        public Version Version { get; }\n\n        /// <summary>\n        /// Gets the .NET Type which is the plugin\n        /// </summary>\n        public Type Type { get; }\n\n        /// <summary>\n        /// Gets the plugin type's assembly\n        /// </summary>\n        public Assembly Assembly { get; }\n\n        /// <summary>\n        /// Gets the catalog which contains the plugins\n        /// </summary>\n        public IPluginCatalog Source { get; }\n\n        /// <summary>\n        /// Gets the description of the plugin\n        /// </summary>\n        public string Description { get; }\n\n        /// <summary>\n        /// Gets the description of the plugin\n        /// </summary>\n        public string ProductVersion { get; }\n        \n        /// <summary>\n        /// Gets the tag of the plugin\n        /// </summary>\n        public string Tag\n        {\n            get\n            {\n                return Tags.FirstOrDefault();\n            }\n        }\n\n        /// <summary>\n        /// Gets the tags of the plugin\n        /// </summary>\n        public List<string> Tags { get; }\n        \n        public Plugin(Assembly assembly, Type type, string name, Version version, IPluginCatalog source, string description = \"\", string productVersion = \"\",\n            string tag = \"\", List<string> tags = null)\n        {\n            Assembly = assembly;\n            Type = type;\n            Name = name;\n            Version = version;\n            Source = source;\n            Description = description;\n            ProductVersion = productVersion;\n            Tags = tags;\n\n            if (Tags == null)\n            {\n                Tags = new List<string>();\n            }\n\n            if (!string.IsNullOrWhiteSpace(tag))\n            {\n                Tags.Add(tag);\n            }\n        }\n\n        public static implicit operator Type(Plugin plugin)\n        {\n            return plugin.Type;\n        }\n\n        public override string ToString()\n        {\n            return $\"{Name}: {Version}\";\n        }\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework.Abstractions/PluginFrameworkOptions.cs",
    "content": "﻿namespace Weikio.PluginFramework.Abstractions\n{\n    /// <summary>\n    /// Configures the options for Plugin Framework.\n    /// </summary>\n    public class PluginFrameworkOptions\n    {\n        public bool UseConfiguration { get; set; } = true;\n        public string ConfigurationSection { get; set; } = \"PluginFramework\";\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework.Abstractions/PluginNameOptions.cs",
    "content": "﻿using System;\nusing System.ComponentModel;\nusing System.Diagnostics;\nusing System.Reflection;\n\nnamespace Weikio.PluginFramework.Abstractions\n{\n    /// <summary>\n    /// Configuration options for defining how the plugin name and plugin version are generated.\n    /// </summary>\n    public class PluginNameOptions\n    {\n        /// <summary>\n        /// Gets or sets the func which defines how the plugin's name is deducted. By default tries to find the plugin's name from <see cref=\"DisplayNameAttribute\"/>.\n        /// If that is missing, type's full name is used. \n        /// </summary>\n        public Func<PluginNameOptions, Type, string> PluginNameGenerator { get; set; } = (options, type) =>\n        {\n            var displayNameAttribute = type.GetCustomAttribute(typeof(DisplayNameAttribute), true) as DisplayNameAttribute;\n\n            if (displayNameAttribute == null)\n            {\n                return type.FullName;\n            }\n\n            if (string.IsNullOrWhiteSpace(displayNameAttribute.DisplayName))\n            {\n                return type.FullName;\n            }\n\n            return displayNameAttribute.DisplayName;\n        };\n\n        /// <summary>\n        /// 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.\n        /// </summary>\n        public Func<PluginNameOptions, Type, Version> PluginVersionGenerator { get; set; } = (options, type) =>\n        {\n            var assemblyLocation = type.Assembly.Location;\n            Version version;\n\n            if (!string.IsNullOrWhiteSpace(assemblyLocation))\n            {\n                var versionInfo = FileVersionInfo.GetVersionInfo(assemblyLocation);\n\n                if (string.IsNullOrWhiteSpace(versionInfo.FileVersion))\n                {\n                    version = new Version(1, 0, 0, 0);\n                }\n                else if (string.Equals(versionInfo.FileVersion, \"0.0.0.0\"))\n                {\n                    version = new Version(1, 0, 0, 0);\n                }\n                else\n                {\n                    version = Version.Parse(versionInfo.FileVersion);\n                }\n            }\n            else\n            {\n                version = new Version(1, 0, 0, 0);\n            }\n\n            return version;\n        };\n\n        /// <summary>\n        /// 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.\n        /// </summary>\n        public Func<PluginNameOptions, Type, string> PluginDescriptionGenerator { get; set; } = (options, type) =>\n        {\n            var assemblyLocation = type.Assembly.Location;\n\n            if (string.IsNullOrWhiteSpace(assemblyLocation))\n            {\n                return string.Empty;\n            }\n\n            var versionInfo = FileVersionInfo.GetVersionInfo(assemblyLocation);\n\n            return versionInfo.Comments;\n        };\n\n        /// <summary>\n        /// 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.\n        /// </summary>\n        public Func<PluginNameOptions, Type, string> PluginProductVersionGenerator { get; set; } = (options, type) =>\n        {\n            var assemblyLocation = type.Assembly.Location;\n\n            if (string.IsNullOrWhiteSpace(assemblyLocation))\n            {\n                return string.Empty;\n            }\n\n            var versionInfo = FileVersionInfo.GetVersionInfo(assemblyLocation);\n\n            return versionInfo.ProductVersion;\n        };\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework.Abstractions/Weikio.PluginFramework.Abstractions.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>netstandard2.0</TargetFramework>\n    <IsPackable>true</IsPackable>\n    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>\n    <Description>Abstractions for Plugin Framework.</Description>\n    <PackageDescription>Abstractions for Plugin Framework.</PackageDescription>\n    <PackageId>Weikio.PluginFramework.Abstractions</PackageId>\n    <Product>Weikio.PluginFramework.Abstractions</Product>\n    <AssemblyName>Weikio.PluginFramework.Abstractions</AssemblyName>\n    <PackageTags>plugins;addons;extensions;plugin framework</PackageTags>\n    <PackageIcon>logo_transparent_color_256.png</PackageIcon>\n    <Title>Plugin Framework Abstractions</Title>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <None Include=\"../../docs/logo_transparent_color_256.png\" Pack=\"true\" Visible=\"false\" PackagePath=\"\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"MinVer\" Version=\"2.0.*\" PrivateAssets=\"all\" />\n  </ItemGroup>\n  \n</Project>"
  },
  {
    "path": "src/Weikio.PluginFramework.AspNetCore/DefaultPluginOption.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\n\nnamespace Weikio.PluginFramework.AspNetCore\n{\n    public class DefaultPluginOption\n    {\n        public Func<IServiceProvider, IEnumerable<Type>, Type> DefaultType { get; set; }\n            = (serviceProvider, implementingTypes) => implementingTypes.FirstOrDefault();\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework.AspNetCore/PluginExtensions.cs",
    "content": "﻿using System;\nusing Weikio.PluginFramework.Abstractions;\n\n// ReSharper disable once CheckNamespace\nnamespace Microsoft.Extensions.DependencyInjection\n{\n    public static class PluginExtensions\n    {\n        public static object Create(this Plugin plugin, IServiceProvider serviceProvider, params object[] parameters)\n        {\n            return ActivatorUtilities.CreateInstance(serviceProvider, plugin, parameters);\n        }\n        \n        public static T Create<T>(this Plugin plugin, IServiceProvider serviceProvider, params object[] parameters) where T : class\n        {\n            return ActivatorUtilities.CreateInstance(serviceProvider, plugin, parameters) as T;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework.AspNetCore/PluginFrameworkInitializer.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.Logging;\nusing Weikio.PluginFramework.Abstractions;\n\nnamespace Weikio.PluginFramework.AspNetCore\n{\n    public class PluginFrameworkInitializer : IHostedService\n    {\n        private readonly IEnumerable<IPluginCatalog> _pluginCatalogs;\n        private readonly ILogger<PluginFrameworkInitializer> _logger;\n\n        public PluginFrameworkInitializer(IEnumerable<IPluginCatalog> pluginCatalogs, ILogger<PluginFrameworkInitializer> logger)\n        {\n            _pluginCatalogs = pluginCatalogs;\n            _logger = logger;\n        }\n\n        public async Task StartAsync(CancellationToken cancellationToken)\n        {\n            try\n            {\n                _logger.LogInformation(\"Initializing {PluginCatalogCount} plugin catalogs\", _pluginCatalogs.Count());\n\n                foreach (var pluginCatalog in _pluginCatalogs)\n                {\n                    try\n                    {\n                        _logger.LogDebug(\"Initializing {PluginCatalog}\", pluginCatalog);\n\n                        await pluginCatalog.Initialize();\n\n                        _logger.LogDebug(\"Initialized {PluginCatalog}\", pluginCatalog);\n                        _logger.LogTrace(\"Found the following plugins from {PluginCatalog}:\", pluginCatalog);\n\n                        foreach (var plugin in pluginCatalog.GetPlugins())\n                        {\n                            _logger.LogTrace(plugin.ToString());\n                        }\n                    }\n                    catch (Exception e)\n                    {\n                        _logger.LogError(e, \"Failed to initialize {PluginCatalog}\", pluginCatalog);\n                    }\n                }\n\n                _logger.LogInformation(\"Initialized {PluginCatalogCount} plugin catalogs\", _pluginCatalogs.Count());\n            }\n            catch (Exception e)\n            {\n                _logger.LogError(e, \"Failed to initialize plugin catalogs\");\n\n                throw;\n            }\n        }\n\n        public Task StopAsync(CancellationToken cancellationToken)\n        {\n            return Task.CompletedTask;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework.AspNetCore/PluginProvider.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Microsoft.Extensions.DependencyInjection;\nusing Weikio.PluginFramework.Abstractions;\n\nnamespace Weikio.PluginFramework.AspNetCore\n{\n    public class PluginProvider\n    {\n        private readonly IEnumerable<IPluginCatalog> _catalogs;\n        private readonly IServiceProvider _serviceProvider;\n\n        public PluginProvider(IEnumerable<IPluginCatalog> catalogs, IServiceProvider serviceProvider)\n        {\n            _catalogs = catalogs;\n            _serviceProvider = serviceProvider;\n        }\n\n        public List<Plugin> GetByTag(string tag)\n        {\n            var result = new List<Plugin>();\n\n            foreach (var pluginCatalog in _catalogs)\n            {\n                var pluginsByTag = pluginCatalog.GetByTag(tag);\n                result.AddRange(pluginsByTag);\n            }\n\n            return result;\n        }\n\n        public List<Plugin> GetPlugins()\n        {\n            var result = new List<Plugin>();\n            foreach (var pluginCatalog in _catalogs)\n            {\n                result.AddRange(pluginCatalog.GetPlugins());\n            }\n\n            return result;\n        }\n        \n        public Plugin Get(string name, Version version)\n        {\n            foreach (var pluginCatalog in _catalogs)\n            {\n                var result = pluginCatalog.Get(name, version);\n\n                if (result != null)\n                {\n                    return result;\n                }\n            }\n\n            return null;\n        }\n        \n        public List<T> GetTypes<T>() where T : class\n        {\n            var result = new List<T>();\n            var catalogs = _serviceProvider.GetServices<IPluginCatalog>();\n\n            foreach (var catalog in catalogs)\n            {\n                var plugins = catalog.GetPlugins();\n\n                foreach (var plugin in plugins.Where(x => typeof(T).IsAssignableFrom(x)))\n                {\n                    var op = plugin.Create<T>(_serviceProvider);\n\n                    result.Add(op);\n                }\n            }\n\n            return result;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework.AspNetCore/ServiceCollectionExtensions.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Reflection;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing Microsoft.Extensions.Options;\nusing Weikio.PluginFramework.Abstractions;\nusing Weikio.PluginFramework.AspNetCore;\nusing Weikio.PluginFramework.Catalogs;\nusing Weikio.PluginFramework.Configuration;\nusing Weikio.PluginFramework.Configuration.Converters;\nusing Weikio.PluginFramework.Configuration.Providers;\nusing Weikio.PluginFramework.Context;\nusing Weikio.PluginFramework.TypeFinding;\n\n// ReSharper disable once CheckNamespace\nnamespace Microsoft.Extensions.DependencyInjection\n{\n    public static class ServiceCollectionExtensions\n    {\n        public static IServiceCollection AddPluginFramework(this IServiceCollection services, Action<PluginFrameworkOptions> configure = null)\n        {\n            if (configure != null)\n            {\n                services.Configure(configure);\n            }\n            \n            services.AddHostedService<PluginFrameworkInitializer>();\n            services.AddTransient<PluginProvider>();\n\n            services.TryAddTransient(typeof(IPluginCatalogConfigurationLoader), typeof(PluginCatalogConfigurationLoader));\n            services.AddTransient(typeof(IConfigurationToCatalogConverter), typeof(FolderCatalogConfigurationConverter));\n            services.AddTransient(typeof(IConfigurationToCatalogConverter), typeof(AssemblyCatalogConfigurationCoverter));\n\n            services.AddConfiguration();\n\n            services.AddSingleton(sp =>\n            {\n                var result = new List<Plugin>();\n                var catalogs = sp.GetServices<IPluginCatalog>();\n\n                foreach (var catalog in catalogs)\n                {\n                    var plugins = catalog.GetPlugins();\n\n                    result.AddRange(plugins);\n                }\n\n                return result.AsEnumerable();\n            });\n\n            var aspNetCoreControllerAssemblyLocation = typeof(Controller).Assembly.Location;\n\n            if (string.IsNullOrWhiteSpace(aspNetCoreControllerAssemblyLocation))\n            {\n                return services;\n            }\n\n            var aspNetCoreLocation = Path.GetDirectoryName(aspNetCoreControllerAssemblyLocation);\n\n            if (PluginLoadContextOptions.Defaults.AdditionalRuntimePaths == null)\n            {\n                PluginLoadContextOptions.Defaults.AdditionalRuntimePaths = new List<string>();\n            }\n\n            if (!PluginLoadContextOptions.Defaults.AdditionalRuntimePaths.Contains(aspNetCoreLocation))\n            {\n                PluginLoadContextOptions.Defaults.AdditionalRuntimePaths.Add(aspNetCoreLocation);\n            }\n\n            return services;\n        }\n\n        public static IServiceCollection AddPluginFramework<TType>(this IServiceCollection services, string dllPath = \"\") where TType : class\n        {\n            services.AddPluginFramework();\n\n            if (string.IsNullOrWhiteSpace(dllPath))\n            {\n                var entryAssembly = Assembly.GetEntryAssembly();\n\n                if (entryAssembly == null)\n                {\n                    dllPath = Environment.CurrentDirectory;\n                }\n                else\n                {\n                    dllPath = Path.GetDirectoryName(entryAssembly.Location);\n                }\n            }\n\n            var typeFinderCriteria = TypeFinderCriteriaBuilder.Create()\n                .AssignableTo(typeof(TType))\n                .Build();\n\n            var catalog = new FolderPluginCatalog(dllPath, typeFinderCriteria);\n            services.AddPluginCatalog(catalog);\n\n            services.AddPluginType<TType>();\n\n            return services;\n        }\n\n        /// <summary>\n        /// Add plugins from the IConfiguration.\n        /// </summary>\n        /// <param name=\"services\">The <see cref=\"IServiceCollection\"/> on which the plugins will be added.</param>\n        /// <returns>This <see cref=\"IServiceCollection\"/>.</returns>\n        private static IServiceCollection AddConfiguration(this IServiceCollection services)\n        {\n            services.TryAddSingleton<IPluginCatalog>(serviceProvider =>\n            {\n                var options = serviceProvider.GetService<IOptions<PluginFrameworkOptions>>().Value;\n\n                if (options.UseConfiguration == false)\n                {\n                    return new EmptyPluginCatalog();\n                }\n                \n                // Grab all the IPluginCatalogConfigurationLoader implementations to load catalog configurations.\n                var loaders = serviceProvider\n                    .GetServices<IPluginCatalogConfigurationLoader>()\n                    .ToList();\n\n                var configuration = serviceProvider.GetService<IConfiguration>();\n\n                var converters = serviceProvider.GetServices<IConfigurationToCatalogConverter>().ToList();\n                var catalogs = new List<IPluginCatalog>();\n\n                foreach (var loader in loaders)\n                {\n                    // Load the catalog configurations.\n                    var catalogConfigs = loader.GetCatalogConfigurations(configuration);\n\n                    if (catalogConfigs?.Any() != true)\n                    {\n                        continue;\n                    }\n\n                    for (var i = 0; i < catalogConfigs.Count; i++)\n                    {\n                        var item = catalogConfigs[i];\n                        var key = $\"{options.ConfigurationSection}:{loader.CatalogsKey}:{i}\";\n\n                        // Check if a type is provided.\n                        if (string.IsNullOrWhiteSpace(item.Type))\n                        {\n                            throw new ArgumentException($\"A type must be provided for catalog at position {i + 1}\");\n                        }\n\n                        // Try to find any registered converter that can convert the specified type.\n                        var foundConverter = converters.FirstOrDefault(converter => converter.CanConvert(item.Type));\n\n                        if (foundConverter == null)\n                        {\n                            throw new ArgumentException($\"The type provided for Plugin catalog at position {i + 1} is unknown.\");\n                        }\n\n                        var catalog = foundConverter.Convert(configuration.GetSection(key));\n\n                        catalogs.Add(catalog);\n                    }\n                }\n\n                return new CompositePluginCatalog(catalogs.ToArray());\n            });\n\n            return services;\n        }\n\n        public static IServiceCollection AddPluginCatalog(this IServiceCollection services, IPluginCatalog pluginCatalog)\n        {\n            services.TryAddEnumerable(ServiceDescriptor.Singleton(typeof(IPluginCatalog), pluginCatalog));\n\n            return services;\n        }\n\n        public static IServiceCollection AddPluginType<T>(this IServiceCollection services, ServiceLifetime serviceLifetime = ServiceLifetime.Transient,\n            Action<DefaultPluginOption> configureDefault = null)\n            where T : class\n        {\n            var serviceDescriptorEnumerable = new ServiceDescriptor(typeof(IEnumerable<T>), sp =>\n            {\n                var pluginProvider = sp.GetService<PluginProvider>();\n                var result = pluginProvider.GetTypes<T>();\n\n                return result.AsEnumerable();\n            }, serviceLifetime);\n\n            var serviceDescriptorSingle = new ServiceDescriptor(typeof(T), sp =>\n            {\n                var defaultPluginOption = GetDefaultPluginOptions<T>(configureDefault, sp);\n\n                var pluginProvider = sp.GetService<PluginProvider>();\n                var result = pluginProvider.GetTypes<T>();\n\n                var defaultType = defaultPluginOption.DefaultType(sp, result.Select(r => r.GetType()));\n\n                return result.FirstOrDefault(r => r.GetType() == defaultType);\n            }, serviceLifetime);\n\n            services.Add(serviceDescriptorEnumerable);\n            services.Add(serviceDescriptorSingle);\n\n            return services;\n        }\n\n        private static DefaultPluginOption GetDefaultPluginOptions<T>(Action<DefaultPluginOption> configureDefault, IServiceProvider sp) where T : class\n        {\n            var defaultPluginOption = new DefaultPluginOption();\n\n            // If no configuration is provided though action try to get configuration from named options\n            if (configureDefault == null)\n            {\n                var optionsFromMonitor =\n                    sp.GetService<IOptionsMonitor<DefaultPluginOption>>().Get(typeof(T).Name);\n\n                if (optionsFromMonitor != null)\n                {\n                    defaultPluginOption = optionsFromMonitor;\n                }\n            }\n            else\n            {\n                configureDefault(defaultPluginOption);\n            }\n\n            return defaultPluginOption;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework.AspNetCore/ServiceProviderExtensions.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Weikio.PluginFramework.Abstractions;\n\n// ReSharper disable once CheckNamespace\nnamespace Microsoft.Extensions.DependencyInjection\n{\n    public static class ServiceProviderExtensions\n    {\n        public static object Create(this IServiceProvider serviceProvider, Plugin plugin)\n        {\n            return ActivatorUtilities.CreateInstance(serviceProvider, plugin);\n        }\n        \n        public static T Create<T>(this IServiceProvider serviceProvider, Plugin plugin) where T : class\n        {\n            return ActivatorUtilities.CreateInstance(serviceProvider, plugin) as T;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework.AspNetCore/Weikio.PluginFramework.AspNetCore.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFrameworks>netcoreapp3.1;net6.0</TargetFrameworks>\n    <IsPackable>true</IsPackable>\n    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>\n    <Description>Plugin Framework for ASP.NET Core.</Description>\n    <PackageDescription>Plugin Framework for ASP.NET Core.</PackageDescription>\n    <PackageId>Weikio.PluginFramework.AspNetCore</PackageId>\n    <Product>Weikio.PluginFramework.AspNetCore</Product>\n    <AssemblyName>Weikio.PluginFramework.AspNetCore</AssemblyName>\n    <PackageTags>plugins;addons;aspnetextensions;plugin framework</PackageTags>\n    <PackageIcon>logo_transparent_color_256.png</PackageIcon>\n    <Title>Plugin Framework for ASP.NET Core</Title>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <FrameworkReference Include=\"Microsoft.AspNetCore.App\" />\n  </ItemGroup>\n  \n  <ItemGroup>\n    <None Include=\"../../docs/logo_transparent_color_256.png\" Pack=\"true\" Visible=\"false\" PackagePath=\"\" />\n    <None Include=\"../../readme.md\" Pack=\"true\" Visible=\"false\" PackagePath=\"\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"MinVer\" Version=\"2.0.*\" PrivateAssets=\"all\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Weikio.PluginFramework.Abstractions\\Weikio.PluginFramework.Abstractions.csproj\" />\n    <ProjectReference Include=\"..\\Weikio.PluginFramework.Configuration\\Weikio.PluginFramework.Configuration.csproj\" />\n    <ProjectReference Include=\"..\\Weikio.PluginFramework\\Weikio.PluginFramework.csproj\" />\n  </ItemGroup>\n  \n</Project>"
  },
  {
    "path": "src/Weikio.PluginFramework.Catalogs.NuGet/NugetFeedPluginCatalog.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Weikio.NugetDownloader;\nusing Weikio.PluginFramework.Abstractions;\nusing Weikio.PluginFramework.Catalogs.NuGet;\nusing Weikio.PluginFramework.TypeFinding;\n\n// ReSharper disable once CheckNamespace\nnamespace Weikio.PluginFramework.Catalogs\n{\n    public class NugetFeedPluginCatalog : IPluginCatalog\n    {\n        private readonly NuGetFeed _packageFeed;\n        private readonly string _searchTerm;\n        private readonly int _maxPackages;\n        private readonly bool _includePrereleases;\n\n        private readonly HashSet<string> _pluginAssemblyNames = new HashSet<string>();\n\n        private List<NugetPackagePluginCatalog> _pluginCatalogs = new List<NugetPackagePluginCatalog>();\n        private readonly NugetFeedPluginCatalogOptions _options;\n\n        public string PackagesFolder { get; }\n\n        public NugetFeedPluginCatalog(NuGetFeed packageFeed, string searchTerm = null,\n            bool includePrereleases = false, int maxPackages = 128,\n            string packagesFolder = null, Action<TypeFinderCriteriaBuilder> configureFinder = null, Dictionary<string, TypeFinderCriteria> criterias = null,\n            NugetFeedPluginCatalogOptions options = null)\n        {\n            _packageFeed = packageFeed;\n            _searchTerm = searchTerm;\n            _includePrereleases = includePrereleases;\n            _maxPackages = maxPackages;\n\n            PackagesFolder = packagesFolder ?? Path.Combine(Path.GetTempPath(), \"NugetFeedPluginCatalog\", Path.GetRandomFileName());\n\n            if (!Directory.Exists(PackagesFolder))\n            {\n                Directory.CreateDirectory(PackagesFolder);\n            }\n\n            if (criterias == null)\n            {\n                criterias = new Dictionary<string, TypeFinderCriteria>();\n            }\n\n            _options = options ?? new NugetFeedPluginCatalogOptions();\n\n            if (configureFinder != null)\n            {\n                var builder = new TypeFinderCriteriaBuilder();\n                configureFinder(builder);\n\n                var criteria = builder.Build();\n\n                _options.TypeFinderOptions.TypeFinderCriterias.Add(criteria);\n            }\n\n            foreach (var finderCriteria in criterias)\n            {\n                finderCriteria.Value.Tags = new List<string>() { finderCriteria.Key };\n\n                _options.TypeFinderOptions.TypeFinderCriterias.Add(finderCriteria.Value);\n            }\n        }\n\n        Plugin IPluginCatalog.Get(string name, Version version)\n        {\n            foreach (var pluginCatalog in _pluginCatalogs)\n            {\n                var result = pluginCatalog.Get(name, version);\n\n                if (result == null)\n                {\n                    continue;\n                }\n\n                return result;\n            }\n\n            return null;\n        }\n\n        public bool IsInitialized { get; private set; }\n\n        public async Task Initialize()\n        {\n            var nuGetDownloader = new NuGetDownloader(_options.LoggerFactory());\n\n            var packages = await nuGetDownloader.SearchPackagesAsync(_packageFeed, _searchTerm, maxResults: _maxPackages);\n\n            foreach (var packageAndRepo in packages)\n            {\n                var options = new NugetPluginCatalogOptions()\n                {\n                    TypeFinderOptions = _options.TypeFinderOptions,\n                    PluginNameOptions = _options.PluginNameOptions,\n                    ForcePackageCaching = _options.ForcePackageCaching,\n                    AutoRetryPackageDownload = _options.AutoRetryPackageDownload\n                };\n\n                var packageCatalog = new NugetPackagePluginCatalog(packageAndRepo.Package.Identity.Id, packageAndRepo.Package.Identity.Version.ToString(),\n                    _includePrereleases, _packageFeed, PackagesFolder, options: options);\n\n                await packageCatalog.Initialize();\n\n                _pluginCatalogs.Add(packageCatalog);\n            }\n\n            IsInitialized = true;\n        }\n\n        public List<Plugin> GetPlugins()\n        {\n            return _pluginCatalogs.SelectMany(x => x.GetPlugins()).ToList();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework.Catalogs.NuGet/NugetFeedPluginCatalogOptions.cs",
    "content": "using System;\nusing NuGet.Common;\nusing Weikio.NugetDownloader;\nusing Weikio.PluginFramework.Abstractions;\nusing Weikio.PluginFramework.Catalogs.NuGet;\nusing Weikio.PluginFramework.TypeFinding;\n\nnamespace Weikio.PluginFramework.Catalogs.NuGet\n{\n    public class NugetFeedPluginCatalogOptions\n    {\n        /// <summary>\n        /// Gets or sets the function which is used to create the logger for Nuget activities\n        /// </summary>\n        public Func <ILogger> LoggerFactory { get; set; } = Defaults.LoggerFactory;\n        \n        /// <summary>\n        /// Gets or sets the <see cref=\"TypeFinderOptions\"/>. \n        /// </summary>\n        public TypeFinderOptions TypeFinderOptions { get; set; } = new TypeFinderOptions();\n\n        /// <summary>\n        /// Gets or sets how the plugin names and version should be defined. <seealso cref=\"PluginNameOptions\"/>.\n        /// </summary>\n        public PluginNameOptions PluginNameOptions { get; set; } = Defaults.PluginNameOptions;\n        \n        /// <summary>\n        /// Gets or sets if Plugin Framework should take care of package caching. In some cases Nuget will download already downloaded package. This flag\n        /// tries to make sure that the package is downloaded only once. Note: Requires that PackagesFolder is set\n        /// </summary>\n        public bool ForcePackageCaching { get; set; } = false;\n        \n        /// <summary>\n        /// 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,\n        /// Plugin Framework will clear the Nuget cache and then tries again.\n        /// </summary>\n        public bool AutoRetryPackageDownload { get; set; } = false;\n        \n        public static class Defaults\n        {\n            /// <summary>\n            /// Gets or sets the default function which is used to create the logger for PluginLoadContextOptions\n            /// </summary>\n            public static Func<ILogger> LoggerFactory { get; set; } = () => new ConsoleLogger();\n            \n            public static PluginNameOptions PluginNameOptions { get; set; } = new PluginNameOptions();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework.Catalogs.NuGet/NugetPackagePluginCatalog.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Newtonsoft.Json;\nusing Weikio.NugetDownloader;\nusing Weikio.PluginFramework.Abstractions;\nusing Weikio.PluginFramework.Catalogs.NuGet;\nusing Weikio.PluginFramework.Context;\nusing Weikio.PluginFramework.TypeFinding;\n\n// ReSharper disable once CheckNamespace\nnamespace Weikio.PluginFramework.Catalogs\n{\n    public class NugetPackagePluginCatalog : IPluginCatalog\n    {\n        private readonly NuGetFeed _packageFeed;\n        private readonly string _packageName;\n        private readonly string _packageVersion;\n        private readonly bool _includePrerelease;\n\n        private readonly HashSet<string> _pluginAssemblyFilePaths = new HashSet<string>();\n        private readonly List<AssemblyPluginCatalog> _pluginCatalogs = new List<AssemblyPluginCatalog>();\n        private readonly NugetPluginCatalogOptions _options;\n\n        public string PackagesFolder { get; }\n\n        private bool HasCustomPackagesFolder\n        {\n            get\n            {\n                return string.IsNullOrWhiteSpace(PackagesFolder) == false;\n            }\n        }\n        \n        private bool ForcePackageCache\n        {\n            get\n            {\n                if (HasCustomPackagesFolder == false)\n                {\n                    return false;\n                }\n\n                if (_options?.ForcePackageCaching != true)\n                {\n                    return false;\n                }\n\n                return true;\n            }\n        }\n\n        private string NugetDownloadResultFilePath\n        {\n            get\n            {\n                if (string.IsNullOrWhiteSpace(PackagesFolder))\n                {\n                    return null;\n                }\n\n                var result = Path.Combine(PackagesFolder, \".nugetDownloadResult.json\");\n\n                return result;\n            }\n        }\n\n        public NugetPackagePluginCatalog(string packageName, string packageVersion = null, bool includePrerelease = false, NuGetFeed packageFeed = null,\n            string packagesFolder = null, Action<TypeFinderCriteriaBuilder> configureFinder = null, Dictionary<string, TypeFinderCriteria> criterias = null,\n            NugetPluginCatalogOptions options = null)\n        {\n            _packageName = packageName;\n            _packageVersion = packageVersion;\n            _includePrerelease = includePrerelease;\n            _packageFeed = packageFeed;\n\n            PackagesFolder = packagesFolder ?? options?.CustomPackagesFolder;\n\n            if (string.IsNullOrWhiteSpace(PackagesFolder))\n            {\n                PackagesFolder = Path.Combine(Path.GetTempPath(), \"NugetPackagePluginCatalog\", Path.GetRandomFileName());\n            }\n\n            if (!Directory.Exists(PackagesFolder))\n            {\n                Directory.CreateDirectory(PackagesFolder);\n            }\n\n            if (criterias == null)\n            {\n                criterias = new Dictionary<string, TypeFinderCriteria>();\n            }\n\n            _options = options ?? new NugetPluginCatalogOptions();\n\n            if (configureFinder != null)\n            {\n                var builder = new TypeFinderCriteriaBuilder();\n                configureFinder(builder);\n\n                var criteria = builder.Build();\n\n                _options.TypeFinderOptions.TypeFinderCriterias.Add(criteria);\n            }\n\n            foreach (var finderCriteria in criterias)\n            {\n                finderCriteria.Value.Tags = new List<string>() { finderCriteria.Key };\n\n                _options.TypeFinderOptions.TypeFinderCriterias.Add(finderCriteria.Value);\n            }\n        }\n\n        public bool IsInitialized { get; private set; }\n\n        public List<Plugin> GetPlugins()\n        {\n            return _pluginCatalogs.SelectMany(x => x.GetPlugins()).ToList();\n        }\n\n        public Plugin Get(string name, Version version)\n        {\n            foreach (var assemblyPluginCatalog in _pluginCatalogs)\n            {\n                var result = assemblyPluginCatalog.Get(name, version);\n\n                if (result == null)\n                {\n                    continue;\n                }\n\n                return result;\n            }\n\n            return null;\n        }\n\n        public async Task Initialize()\n        {\n            NugetDownloadResult nugetDownloadResult = null;\n\n            var logger = _options.LoggerFactory();\n\n            if (ForcePackageCache && File.Exists(NugetDownloadResultFilePath))\n            {\n                try\n                {\n                    var jsonFromDisk = await File.ReadAllTextAsync(NugetDownloadResultFilePath);\n\n                    nugetDownloadResult = JsonConvert.DeserializeObject<NugetDownloadResult>(jsonFromDisk);\n                    \n                    logger?.LogDebug($\"Using previously downloaded package from {PackagesFolder}\");\n                }\n                catch (Exception e)\n                {\n                    logger?.LogError($\"Failed to deserialize nuget download result from path {NugetDownloadResultFilePath}: {e}\");\n                }\n            }\n\n            if (nugetDownloadResult == null)\n            {\n                var nuGetDownloader = new NuGetDownloader(_options.LoggerFactory());\n\n                nugetDownloadResult = await nuGetDownloader.DownloadAsync(PackagesFolder, _packageName, _packageVersion, _includePrerelease, _packageFeed,\n                    includeSecondaryRepositories: _options.IncludeSystemFeedsAsSecondary, targetFramework: _options.TargetFramework, autoRetryOnFail: _options.AutoRetryPackageDownload, targetRid: _options.TargetRid).ConfigureAwait(false);\n            }\n\n            foreach (var f in nugetDownloadResult.PackageAssemblyFiles)\n            {\n                _pluginAssemblyFilePaths.Add(Path.Combine(PackagesFolder, f));\n            }\n\n            foreach (var pluginAssemblyFilePath in _pluginAssemblyFilePaths)\n            {\n                var options = new AssemblyPluginCatalogOptions\n                {\n                    TypeFinderOptions = _options.TypeFinderOptions,\n                    PluginNameOptions = _options.PluginNameOptions\n                };\n\n                var downloadedRuntimeDlls = nugetDownloadResult.RunTimeDlls.Where(x => x.IsRecommended).ToList();\n\n                var runtimeAssemblyHints = new List<RuntimeAssemblyHint>();\n\n                foreach (var runTimeDll in downloadedRuntimeDlls)\n                {\n                    var runtimeAssembly = new RuntimeAssemblyHint(runTimeDll.FileName, runTimeDll.FullFilePath, runTimeDll.IsNative);\n                    runtimeAssemblyHints.Add(runtimeAssembly);\n                }\n\n                options.PluginLoadContextOptions.RuntimeAssemblyHints = runtimeAssemblyHints;\n\n                var assemblyCatalog = new AssemblyPluginCatalog(pluginAssemblyFilePath, options);\n                await assemblyCatalog.Initialize();\n\n                _pluginCatalogs.Add(assemblyCatalog);\n            }\n\n            IsInitialized = true;\n\n            if (ForcePackageCache)\n            {\n                try\n                {\n                    var jsonToWrite = JsonConvert.SerializeObject(nugetDownloadResult, Formatting.Indented);\n\n                    await File.WriteAllTextAsync(NugetDownloadResultFilePath, jsonToWrite);\n                    \n                    logger?.LogDebug($\"Stored downloaded package details to {NugetDownloadResultFilePath}\");\n                }\n                catch (Exception e)\n                {\n                    logger?.LogError($\"Failed to store downloaded package details to {NugetDownloadResultFilePath}: {e}\");\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework.Catalogs.NuGet/NugetPluginCatalogOptions.cs",
    "content": "using System;\nusing NuGet.Common;\nusing Weikio.PluginFramework.Abstractions;\nusing Weikio.PluginFramework.Catalogs.NuGet;\nusing Weikio.NugetDownloader;\nusing Weikio.PluginFramework.TypeFinding;\n\nnamespace Weikio.PluginFramework.Catalogs.NuGet\n{\n    public class NugetPluginCatalogOptions\n    {\n        /// <summary>\n        /// Gets or sets the function which is used to create the logger for Nuget activities\n        /// </summary>\n        public Func <ILogger> LoggerFactory { get; set; } = Defaults.LoggerFactory;\n        \n        /// <summary>\n        /// Gets or sets the <see cref=\"TypeFinderOptions\"/>. \n        /// </summary>\n        public TypeFinderOptions TypeFinderOptions { get; set; } = new TypeFinderOptions();\n\n        /// <summary>\n        /// Gets or sets how the plugin names and version should be defined. <seealso cref=\"PluginNameOptions\"/>.\n        /// </summary>\n        public PluginNameOptions PluginNameOptions { get; set; } = Defaults.PluginNameOptions;\n\n        /// <summary>\n        /// Gets or sets if system feeds should be used as secondary feeds for finding packages when feed url is defined.\n        /// </summary>\n        public bool IncludeSystemFeedsAsSecondary { get; set; } = false;\n\n        /// <summary>\n        /// Gets or sets the target platform. If not set, EntryAssembly's target framework is used.\n        /// </summary>\n        public string TargetFramework { get; set; } = Defaults.TargetFramework;\n\n        /// <summary>\n        /// Gets or sets if Plugin Framework should take care of package caching. In some cases Nuget will download already downloaded package. This flag\n        /// tries to make sure that the package is downloaded only once. Note: Requires that PackagesFolder is set\n        /// </summary>\n        public bool ForcePackageCaching { get; set; } = false;\n\n        /// <summary>\n        /// Gets or sets the folder where package is installed. Defaults to unique random temp path.\n        /// </summary>\n        public string CustomPackagesFolder { get; set; } = string.Empty;\n        \n        /// <summary>\n        /// 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,\n        /// Plugin Framework will clear the Nuget cache and then tries again.\n        /// </summary>\n        public bool AutoRetryPackageDownload { get; set; } = false;\n        \n        /// <summary>\n        /// Gets or sets the target rid. If not set, RuntimeInformation.RuntimeIdentifier is used.\n        /// </summary>\n        public string TargetRid { get; set; } = Defaults.TargetRid;\n        \n        public static class Defaults\n        {\n            /// <summary>\n            /// Gets or sets the default function which is used to create the logger for PluginLoadContextOptions\n            /// </summary>\n            public static Func<ILogger> LoggerFactory { get; set; } = () => new ConsoleLogger();\n            \n            /// <summary>\n            /// Gets or sets the default of how the plugin names and version should be defined. <seealso cref=\"PluginNameOptions\"/>.\n            /// </summary>\n            public static PluginNameOptions PluginNameOptions { get; set; } = new PluginNameOptions();\n            \n            /// <summary>\n            /// Gets or sets the default target platform. If not set, EntryAssembly's target framework is used.\n            /// </summary>\n            public static string TargetFramework { get; set; } = string.Empty;\n            \n            /// <summary>\n            /// Gets or sets the default target rid. If not set, RuntimeInformation.RuntimeIdentifier is used.\n            /// </summary>\n            public static string TargetRid { get; set; } = string.Empty;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework.Catalogs.NuGet/Weikio.PluginFramework.Catalogs.NuGet.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFrameworks>netcoreapp3.1;net6.0</TargetFrameworks>\n    <IsPackable>true</IsPackable>\n    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>\n    <Description>NuGet catalog for Plugin Framework allows you to use NuGet packages as plugins with Plugin Framework.</Description>\n    <PackageDescription>NuGet catalog for Plugin Framework allows you to use NuGet packages as plugins with Plugin Framework.</PackageDescription>\n    <PackageId>Weikio.PluginFramework.Catalogs.NuGet</PackageId>\n    <Product>Weikio.PluginFramework.Catalogs.NuGet</Product>\n    <AssemblyName>Weikio.PluginFramework.Catalogs.NuGet</AssemblyName>\n    <PackageTags>nuget;plugins;addons;extensions;plugin framework</PackageTags>\n    <PackageIcon>logo_transparent_color_256.png</PackageIcon>\n    <Title>NuGet Catalog for Plugin Framework</Title>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"MinVer\" Version=\"2.0.*\" PrivateAssets=\"all\" />\n    <PackageReference Include=\"Weikio.NugetDownloader\" Version=\"2.2.0\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Weikio.PluginFramework.Abstractions\\Weikio.PluginFramework.Abstractions.csproj\" />\n    <ProjectReference Include=\"..\\Weikio.PluginFramework\\Weikio.PluginFramework.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"../../docs/logo_transparent_color_256.png\" Pack=\"true\" Visible=\"false\" PackagePath=\"\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Weikio.PluginFramework.Catalogs.Roslyn/InvalidCodeException.cs",
    "content": "﻿using System;\n\nnamespace Weikio.PluginFramework.Catalogs.Roslyn\n{\n    public class InvalidCodeException : Exception\n    {\n        public InvalidCodeException(Exception exception) : this(\"\", exception)\n        {\n        }\n\n        public InvalidCodeException(string message, Exception exception) : base(message, exception)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework.Catalogs.Roslyn/RegularInitializer.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing System.Reflection;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Weikio.TypeGenerator;\n\nnamespace Weikio.PluginFramework.Catalogs.Roslyn\n{\n    /// <summary>\n    /// Initializer which can handle regular C#\n    /// </summary>\n    public class RegularInitializer\n    {\n        private readonly string _code;\n        private readonly RoslynPluginCatalogOptions _options;\n\n        public RegularInitializer(string code, RoslynPluginCatalogOptions options)\n        {\n            if (string.IsNullOrWhiteSpace(code))\n            {\n                throw new ArgumentOutOfRangeException(nameof(code), code, \"Script can not be null or empty\");\n            }\n\n            _code = code;\n            _options = options ?? new RoslynPluginCatalogOptions();\n        }\n\n        public Task<Assembly> CreateAssembly()\n        {\n            try\n            {\n                var generator = new CodeToAssemblyGenerator();\n                generator.ReferenceAssemblyContainingType<Action>();\n\n                if (_options.AdditionalReferences?.Any() == true)\n                {\n                    foreach (var assembly in _options.AdditionalReferences)\n                    {\n                        generator.ReferenceAssembly(assembly);\n                    }\n                }\n\n                var code = new StringBuilder();\n                code.AppendLine(\"using System;\");\n                code.AppendLine(\"using System.Diagnostics;\");\n                code.AppendLine(\"using System.Threading.Tasks;\");\n                code.AppendLine(\"using System.Text;\");\n                code.AppendLine(\"using System.Collections;\");\n                code.AppendLine(\"using System.Collections.Generic;\");\n                \n                if (_options.AdditionalNamespaces?.Any() == true)\n                {\n                    foreach (var ns in _options.AdditionalNamespaces)\n                    {\n                        code.AppendLine($\"using {ns};\");\n                    }\n                }\n\n                code.AppendLine(_code);\n                var assemblySourceCode = code.ToString();\n\n                var result = generator.GenerateAssembly(assemblySourceCode);\n\n                return Task.FromResult(result);\n            }\n            catch (Exception e)\n            {\n                throw new InvalidCodeException(\"Failed to create assembly from regular code. Code: \" + _code, e);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework.Catalogs.Roslyn/RoslynPluginCatalog.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing System.Threading.Tasks;\nusing Microsoft.CodeAnalysis.CSharp.Scripting;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing Microsoft.CodeAnalysis.Scripting;\nusing Weikio.PluginFramework.Abstractions;\nusing Weikio.PluginFramework.Catalogs.Roslyn;\nusing Weikio.PluginFramework.TypeFinding;\n\n// ReSharper disable once CheckNamespace\nnamespace Weikio.PluginFramework.Catalogs\n{\n    public class RoslynPluginCatalog : IPluginCatalog\n    {\n        private readonly RoslynPluginCatalogOptions _options;\n        private readonly string _code;\n\n        private Assembly _assembly;\n\n        // private Plugin _plugin;\n        private AssemblyPluginCatalog _catalog;\n\n        public RoslynPluginCatalog(string code, RoslynPluginCatalogOptions options = null, string description = null, string productVersion = null)\n        {\n            if (string.IsNullOrWhiteSpace(code))\n            {\n                throw new ArgumentOutOfRangeException(nameof(code), code, \"Code can not be null or empty\");\n            }\n\n            _code = code;\n            _options = options ?? new RoslynPluginCatalogOptions();\n\n            _options.PluginNameOptions.PluginDescriptionGenerator = (nameOptions, type) => description;\n            _options.PluginNameOptions.PluginProductVersionGenerator = (nameOptions, type) => productVersion;\n        }\n\n        public Plugin Get(string name, Version version)\n        {\n            return _catalog.Get(name, version);\n        }\n\n        public bool IsInitialized { get; private set; }\n\n        private async Task<bool> IsScript()\n        {\n            try\n            {\n                var csharScript = CSharpScript.Create(_code, ScriptOptions.Default);\n\n                var compilation = csharScript.GetCompilation();\n\n                var syntaxTree = compilation.SyntaxTrees.Single();\n\n                var descendants = (await syntaxTree.GetRootAsync())\n                    .DescendantNodes().ToList();\n\n                var classDeclarations = descendants.OfType<ClassDeclarationSyntax>().FirstOrDefault();\n\n                if (classDeclarations == null)\n                {\n                    return true;\n                }\n\n                return false;\n            }\n            catch (Exception e)\n            {\n                throw new InvalidCodeException(\"Failed to determine if code is script or regular. Code: \" + _code, e);\n            }\n        }\n\n        public async Task Initialize()\n        {\n            try\n            {\n                var isScript = await IsScript();\n\n                if (isScript)\n                {\n                    var scriptInitializer = new ScriptInitializer(_code, _options);\n                    _assembly = await scriptInitializer.CreateAssembly();\n                }\n                else\n                {\n                    var regularInitializer = new RegularInitializer(_code, _options);\n                    _assembly = await regularInitializer.CreateAssembly();\n                }\n\n                var assemblyCatalogOptions = new AssemblyPluginCatalogOptions { PluginNameOptions = _options.PluginNameOptions};\n\n                if (_options.Tags?.Any() == true)\n                {\n                    assemblyCatalogOptions.TypeFinderOptions = new TypeFinderOptions() { TypeFinderCriterias = new List<TypeFinderCriteria>()\n                    {\n                        new TypeFinderCriteria()\n                        {\n                            Query = (context, type) => true,\n                            Tags = _options.Tags\n                        }\n                    } };\n                }\n\n                _catalog = new AssemblyPluginCatalog(_assembly, assemblyCatalogOptions);\n                await _catalog.Initialize();\n\n                IsInitialized = true;\n            }\n            catch (Exception e)\n            {\n                throw new InvalidCodeException($\"Failed to initialize catalog with code: {Environment.NewLine}{_code}\", e);\n            }\n        }\n\n        public List<Plugin> GetPlugins()\n        {\n            return _catalog.GetPlugins();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework.Catalogs.Roslyn/RoslynPluginCatalogOptions.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Reflection;\nusing Weikio.PluginFramework.Abstractions;\n\nnamespace Weikio.PluginFramework.Catalogs.Roslyn\n{\n    public class RoslynPluginCatalogOptions\n    {\n        private string _pluginName = \"RoslynCode\";\n        private Version _pluginVersion = new Version(1, 0, 0);\n\n        public string PluginName\n        {\n            get => _pluginName;\n            set\n            {\n                _pluginName = value;\n\n                PluginNameOptions.PluginNameGenerator = (options, type) => _pluginName;\n            }\n        }\n\n        public Version PluginVersion\n        {\n            get => _pluginVersion;\n            set\n            {\n                _pluginVersion = value;\n\n                PluginNameOptions.PluginVersionGenerator = (options, type) => _pluginVersion;\n            }\n        }\n\n        public string TypeName { get; set; } = \"GeneratedType\";\n        public string NamespaceName { get; set; } = \"GeneratedNamespace\";\n        public string MethodName { get; set; } = \"Run\";\n        public bool ReturnsTask { get; set; } = true;\n        public Func<RoslynPluginCatalogOptions, string> TypeNameGenerator { get; set; } = options => options.TypeName;\n        public Func<RoslynPluginCatalogOptions, string> NamespaceNameGenerator { get; set; } = options => options.NamespaceName;\n        public Func<RoslynPluginCatalogOptions, string> MethodNameGenerator { get; set; } = options => options.MethodName;\n        public List<Assembly> AdditionalReferences { get; set; } = new List<Assembly>();\n        public List<string> AdditionalNamespaces { get; set; } = new List<string>();\n        public PluginNameOptions PluginNameOptions { get; set; } = new PluginNameOptions();\n        \n        /// <summary>\n        /// Gets or sets the tags assigned to plugin\n        /// </summary>\n        public List<string> Tags { get; set; } = new List<string>();\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework.Catalogs.Roslyn/ScriptInitializer.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Microsoft.CodeAnalysis;\nusing Microsoft.CodeAnalysis.CSharp;\nusing Microsoft.CodeAnalysis.CSharp.Scripting;\nusing Microsoft.CodeAnalysis.CSharp.Syntax;\nusing Microsoft.CodeAnalysis.Scripting;\nusing Weikio.TypeGenerator;\n\nnamespace Weikio.PluginFramework.Catalogs.Roslyn\n{\n    /// <summary>\n    /// Initializer which can handle C# script\n    /// </summary>\n    public class ScriptInitializer\n    {\n        private readonly string _code;\n        private readonly RoslynPluginCatalogOptions _options;\n\n        public ScriptInitializer(string code, RoslynPluginCatalogOptions options)\n        {\n            if (string.IsNullOrWhiteSpace(code))\n            {\n                throw new ArgumentOutOfRangeException(nameof(code), code, \"Script can not be null or empty\");\n            }\n\n            _code = code;\n            _options = options;\n\n            _options = options ?? new RoslynPluginCatalogOptions();\n\n            if (_options.TypeNameGenerator is null)\n            {\n                throw new ArgumentNullException(nameof(_options.TypeNameGenerator));\n            }\n\n            if (_options.NamespaceNameGenerator is null)\n            {\n                throw new ArgumentNullException(nameof(_options.NamespaceNameGenerator));\n            }\n            \n            if (_options.MethodNameGenerator is null)\n            {\n                throw new ArgumentNullException(nameof(_options.MethodNameGenerator));\n            }\n        }\n\n        public async Task<Assembly> CreateAssembly()\n        {\n            try\n            {\n                var returnType = await GetReturnType();\n                var parameters = await GetParameters();\n                var updatedScript = await RemoveProperties(_code);\n\n                var generator = new CodeToAssemblyGenerator();\n                generator.ReferenceAssemblyContainingType<Action>();\n\n                var code = new StringBuilder();\n                code.AppendLine(\"using System;\");\n                code.AppendLine(\"using System.Diagnostics;\");\n                code.AppendLine(\"using System.Threading.Tasks;\");\n                code.AppendLine(\"using System.Text;\");\n                code.AppendLine(\"using System.Collections;\");\n                code.AppendLine(\"using System.Collections.Generic;\");\n                code.AppendLine(\"using System.Reflection;\");\n                code.AppendLine(\"[assembly: AssemblyFileVersion(\\\"1.0.0.0\\\")]\");\n                \n                if (_options.AdditionalNamespaces?.Any() == true)\n                {\n                    foreach (var ns in _options.AdditionalNamespaces)\n                    {\n                        code.AppendLine($\"using {ns};\");\n                    }\n                }\n\n                code.AppendLine($\"namespace {_options.NamespaceNameGenerator(_options)}\");\n                code.AppendLine(\"{\");\n                code.AppendLine($\"public class {_options.TypeNameGenerator(_options)}\");\n                code.AppendLine(\"{\");\n                if (returnType == null)\n                {\n                    if (_options.ReturnsTask)\n                    {\n                        code.AppendLine($\"public async Task {_options.MethodNameGenerator(_options)}({GetParametersString(parameters)})\");\n                    }\n                    else\n                    {\n                        code.AppendLine($\"public void {_options.MethodNameGenerator(_options)}({GetParametersString(parameters)})\");\n                    }\n                }\n                else\n                {\n                    if (_options.ReturnsTask)\n                    {\n                        code.AppendLine($\"public async Task<{returnType.FullName}> {_options.MethodNameGenerator(_options)}({GetParametersString(parameters)})\");\n                    }\n                    else\n                    {\n                        code.AppendLine($\"public {returnType.FullName} {_options.MethodNameGenerator(_options)}({GetParametersString(parameters)})\");\n                    }\n                }\n\n                code.AppendLine(\"{\"); // Start method\n                code.AppendLine(updatedScript);\n                code.AppendLine(\"}\"); // End method\n                code.AppendLine(\"}\"); // End class\n                code.AppendLine(\"}\"); // End namespace\n\n                var assemblySourceCode = code.ToString();\n\n                var result = generator.GenerateAssembly(assemblySourceCode);\n\n                return result;\n            }\n            catch (Exception e)\n            {\n                throw new InvalidCodeException(\"Failed to create assembly from script. Code: \" + _code, e);\n            }\n        }\n\n        private async Task<string> RemoveProperties(string currentScript)\n        {\n            var tree = CSharpSyntaxTree.ParseText(currentScript);\n            var root = await tree.GetRootAsync();\n\n            var descendants = root\n                .DescendantNodes().ToList();\n\n            var declarations = descendants.OfType<PropertyDeclarationSyntax>().ToList();\n\n            if (declarations?.Any() != true)\n            {\n                return currentScript;\n            }\n\n            var firstProperty = declarations.First();\n            root = root.RemoveNode(firstProperty, SyntaxRemoveOptions.KeepEndOfLine);\n\n            var updatedScript = root.GetText();\n            var result = updatedScript.ToString();\n\n            return await RemoveProperties(result);\n        }\n\n        private async Task<List<(string, Type)>> GetParameters()\n        {\n            var csharScript = CSharpScript.Create(_code, ScriptOptions.Default);\n\n            var compilation = csharScript.GetCompilation();\n\n            var syntaxTree = compilation.SyntaxTrees.Single();\n            var semanticModel = compilation.GetSemanticModel(syntaxTree);\n\n            var descendants = (await syntaxTree.GetRootAsync())\n                .DescendantNodes().ToList();\n\n            var declarations = descendants.OfType<PropertyDeclarationSyntax>().ToList();\n            var result = new List<(string, Type)>();\n\n            if (declarations?.Any() != true)\n            {\n                return result;\n            }\n\n            var symbolDisplayFormat =\n                new SymbolDisplayFormat(typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces);\n\n            foreach (var propertyDeclaration in declarations)\n            {\n                var name = propertyDeclaration.Identifier.Text;\n                var typeInfo = semanticModel.GetTypeInfo(propertyDeclaration.Type);\n\n                var typeName = typeInfo.Type.ToDisplayString(symbolDisplayFormat);\n                var type = Type.GetType(typeName, true);\n\n                result.Add((name, type));\n            }\n\n            return result;\n        }\n\n        private async Task<Type> GetReturnType()\n        {\n            var csharScript = CSharpScript.Create(_code, ScriptOptions.Default);\n\n            var compilation = csharScript.GetCompilation();\n\n            var syntaxTree = compilation.SyntaxTrees.Single();\n            var semanticModel = compilation.GetSemanticModel(syntaxTree);\n\n            var descendants = (await syntaxTree.GetRootAsync())\n                .DescendantNodes().ToList();\n\n            var returnSyntax = descendants.OfType<ReturnStatementSyntax>().FirstOrDefault();\n\n            if (returnSyntax == null)\n            {\n                return null;\n            }\n\n            var expr = returnSyntax.Expression;\n\n            var typeInfo = semanticModel.GetTypeInfo(expr);\n\n            var symbolDisplayFormat =\n                new SymbolDisplayFormat(typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces);\n\n            string fullyQualifiedName;\n\n            if (typeInfo.Type is INamedTypeSymbol mySymbol)\n            {\n                fullyQualifiedName = mySymbol.ToDisplayString(symbolDisplayFormat);\n            }\n            else\n            {\n                fullyQualifiedName = typeInfo.Type.ToDisplayString(symbolDisplayFormat);\n            }\n\n            try\n            {\n                var result = Type.GetType(fullyQualifiedName, true);\n\n                return result;\n            }\n            catch (Exception e)\n            {\n                throw new NotSupportedException($\"{fullyQualifiedName} is not supported return type of a script.\", e);\n            }\n        }\n\n        private string GetParametersString(List<(string, Type)> parameters)\n        {\n            if (parameters?.Any() != true)\n            {\n                return \"\";\n            }\n\n            var result = string.Join(\", \", parameters.Select(x => $\"{x.Item2.FullName} {x.Item1}\"));\n\n            return result;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework.Catalogs.Roslyn/Weikio.PluginFramework.Catalogs.Roslyn.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFrameworks>netcoreapp3.1;net6.0</TargetFrameworks>\n    <IsPackable>true</IsPackable>\n    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>\n    <Description>Roslyn catalog for Plugin Framework allows you to use Roslyn scripts as plugins with Plugin Framework.</Description>\n    <PackageDescription>Roslyn catalog for Plugin Framework allows you to use Roslyn scripts as plugins with Plugin Framework.</PackageDescription>\n    <PackageId>Weikio.PluginFramework.Catalogs.Roslyn</PackageId>\n    <Product>Weikio.PluginFramework.Catalogs.Roslyn</Product>\n    <AssemblyName>Weikio.PluginFramework.Catalogs.Roslyn</AssemblyName>\n    <PackageTags>roslyn;plugins;addons;extensions;plugin framework</PackageTags>\n    <PackageIcon>logo_transparent_color_256.png</PackageIcon>\n    <Title>Roslyn Catalog for Plugin Framework</Title>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"MinVer\" Version=\"2.0.*\" PrivateAssets=\"all\" />\n    <PackageReference Include=\"Microsoft.CodeAnalysis.Scripting\" Version=\"3.6.0\" />\n    <PackageReference Include=\"Microsoft.CodeAnalysis.CSharp\" Version=\"3.6.0\" />\n    <PackageReference Include=\"Weikio.TypeGenerator\" Version=\"1.4.1\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Weikio.PluginFramework.Abstractions\\Weikio.PluginFramework.Abstractions.csproj\" />\n    <ProjectReference Include=\"..\\Weikio.PluginFramework\\Weikio.PluginFramework.csproj\" />\n  </ItemGroup>\n  \n  <ItemGroup>\n    <None Include=\"../../docs/logo_transparent_color_256.png\" Pack=\"true\" Visible=\"false\" PackagePath=\"\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Weikio.PluginFramework.Configuration/CatalogConfiguration.cs",
    "content": "namespace Weikio.PluginFramework.Configuration\n{\n    /// <summary>\n    /// Base configuration class for catalogs.\n    /// </summary>\n    public class CatalogConfiguration\n    {\n        /// <summary>\n        /// The type of the catalog this configuration section represents.\n        /// </summary>\n        public string? Type { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework.Configuration/Converters/AssemblyCatalogConfigurationCoverter.cs",
    "content": "using System;\nusing Microsoft.Extensions.Configuration;\nusing Weikio.PluginFramework.Abstractions;\nusing Weikio.PluginFramework.Catalogs;\n\nnamespace Weikio.PluginFramework.Configuration.Converters\n{\n    /// <summary>\n    /// Converter implementation for the <see cref=\"AssemblyPluginCatalog\"/>.\n    /// </summary>\n    public class AssemblyCatalogConfigurationCoverter : IConfigurationToCatalogConverter\n    {\n        ///<inheritdoc/>\n        public bool CanConvert(string type)\n        {\n            return string.Equals(type, \"Assembly\", StringComparison.InvariantCultureIgnoreCase);\n        }\n\n        ///<inheritdoc/>\n        public IPluginCatalog Convert(IConfigurationSection section)\n        {\n            var path = section.GetValue<string>(\"Path\");\n\n            return new AssemblyPluginCatalog(path);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework.Configuration/Converters/FolderCatalogConfigurationConverter.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing Microsoft.Extensions.Configuration;\nusing Weikio.PluginFramework.Abstractions;\nusing Weikio.PluginFramework.Catalogs;\n\nnamespace Weikio.PluginFramework.Configuration.Converters\n{\n    /// <summary>\n    /// Converter implementation for the <see cref=\"FolderPluginCatalog\"/>.\n    /// </summary>\n    public class FolderCatalogConfigurationConverter : IConfigurationToCatalogConverter\n    {\n        ///<inheritdoc/>\n        public bool CanConvert(string type)\n        {\n            return string.Equals(type, \"Folder\", StringComparison.InvariantCultureIgnoreCase);\n        }\n\n        ///<inheritdoc/>\n        public IPluginCatalog Convert(IConfigurationSection configuration)\n        {\n            var path = configuration.GetValue<string>(\"Path\")\n                ?? throw new ArgumentException(\"Plugin Framework's FolderCatalog requires a Path.\");\n\n            var options = new CatalogFolderOptions();\n            configuration.Bind($\"Options\", options);\n\n            var folderOptions = new FolderPluginCatalogOptions();\n\n            folderOptions.IncludeSubfolders = options.IncludeSubfolders ?? folderOptions.IncludeSubfolders;\n            folderOptions.SearchPatterns = options.SearchPatterns ?? folderOptions.SearchPatterns;\n\n            return new FolderPluginCatalog(path, folderOptions);\n        }\n\n        private class CatalogFolderOptions\n        {\n            public bool? IncludeSubfolders { get; set; }\n\n            public List<string>? SearchPatterns { get; set; }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework.Configuration/Converters/IConfigurationToCatalogConverter.cs",
    "content": "using Microsoft.Extensions.Configuration;\nusing Weikio.PluginFramework.Abstractions;\n\nnamespace Weikio.PluginFramework.Configuration.Converters\n{\n    /// <summary>\n    /// Interface that specifies the methods a ConfigurationConverter needs.\n    /// </summary>\n    public interface IConfigurationToCatalogConverter\n    {\n        /// <summary>\n        /// Determines if the converter can convert the provided type.\n        /// True if it can, false otherwise.\n        /// </summary>\n        /// <param name=\"type\"></param>\n        /// <returns>True if the type can be converted.</returns>\n        bool CanConvert(string type);\n\n        /// <summary>\n        /// Convert a Catalog Configuration to it's equivalent <see cref=\"IPluginCatalog\"/> object.\n        /// </summary>\n        /// <param name=\"section\">The section that contains the catalog configuration.</param>\n        /// <returns>An equivalent <see cref=\"IPluginCatalog\"/> object.</returns>\n        IPluginCatalog Convert(IConfigurationSection section);\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework.Configuration/Providers/IPluginCatalogConfigurationLoader.cs",
    "content": "using System.Collections.Generic;\nusing Microsoft.Extensions.Configuration;\n\nnamespace Weikio.PluginFramework.Configuration.Providers\n{\n    /// <summary>\n    /// Interface that specified the methods a PluginCatalogConfigurationProvider needs.\n    /// </summary>\n    public interface IPluginCatalogConfigurationLoader\n    {\n        /// <summary>\n        /// The key of the catalogs section inside the parent configuration section (<see cref=\"SectionKey\"/>).\n        /// </summary>\n        string CatalogsKey { get; }\n\n        /// <summary>\n        /// Returns a list that contains catalog configurations.\n        /// </summary>\n        /// <param name=\"configuration\">The configuration to use.</param>\n        /// <returns>A list that contains catalog configurations.</returns>\n        List<CatalogConfiguration> GetCatalogConfigurations(IConfiguration configuration);\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework.Configuration/Providers/PluginCatalogConfigurationLoader.cs",
    "content": "using System.Collections.Generic;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Options;\nusing Weikio.PluginFramework.Abstractions;\n\nnamespace Weikio.PluginFramework.Configuration.Providers\n{\n    /// <summary>\n    /// Implementation of <see cref=\"IPluginCatalogConfigurationLoader\"/> that\n    /// loads a list of <see cref=\"CatalogConfiguration\"/> objects from the <see cref=\"IConfiguration\"/> object.\n    /// </summary>\n    public class PluginCatalogConfigurationLoader : IPluginCatalogConfigurationLoader\n    {\n        private PluginFrameworkOptions _options;\n\n        ///<inheritdoc/>\n        public virtual string CatalogsKey => \"Catalogs\";\n\n        public PluginCatalogConfigurationLoader(IOptions<PluginFrameworkOptions> options)\n        {\n            _options = options.Value;\n        }\n\n        ///<inheritdoc/>\n        public List<CatalogConfiguration> GetCatalogConfigurations(IConfiguration configuration)\n        {\n            var catalogs = new List<CatalogConfiguration>();\n\n            configuration.Bind($\"{_options.ConfigurationSection}:{CatalogsKey}\", catalogs);\n\n            return catalogs;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Weikio.PluginFramework.Configuration/Weikio.PluginFramework.Configuration.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFrameworks>netcoreapp3.1;net6.0</TargetFrameworks>\n    <nullable>enable</nullable>\n    <IsPackable>true</IsPackable>\n    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>\n    <Description>IConfiguration support for Plugin Framework.</Description>\n    <PackageDescription>IConfiguration support for Plugin Framework.</PackageDescription>\n    <PackageId>Weikio.PluginFramework.Configuration</PackageId>\n    <Product>Weikio.PluginFramework.Configuration</Product>\n    <AssemblyName>Weikio.PluginFramework.Configuration</AssemblyName>\n    <PackageTags>plugins;addons;aspnetextensions;plugin framework;configuration</PackageTags>\n    <PackageIcon>logo_transparent_color_256.png</PackageIcon>\n    <Title>IConfiguration support for Plugin Framework</Title>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"MinVer\" Version=\"2.0.*\" PrivateAssets=\"all\" />\n  </ItemGroup>\n  \n  <ItemGroup>\n    <None Include=\"../../docs/logo_transparent_color_256.png\" Pack=\"true\" Visible=\"false\" PackagePath=\"\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Weikio.PluginFramework\\Weikio.PluginFramework.csproj\" />\n  </ItemGroup>\n  \n</Project>\n"
  },
  {
    "path": "tests/Assemblies/JsonNetNew/JsonNetNew.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>netstandard2.0</TargetFramework>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <OutputPath>..\\bin\\JsonNew</OutputPath>\n  </PropertyGroup>\n  \n  <ItemGroup>\n    <PackageReference Include=\"Newtonsoft.Json\" Version=\"10.0.3\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\TestIntefaces\\TestIntefaces.csproj\" />\n  </ItemGroup>\n  \n</Project>\n"
  },
  {
    "path": "tests/Assemblies/JsonNetNew/NewJsonResolver.cs",
    "content": "﻿using Newtonsoft.Json;\nusing TestIntefaces;\n\nnamespace JsonNetNew\n{\n    public class NewJsonResolver : IJsonVersionResolver\n    {\n        public string GetVersion()\n        {\n            var result = typeof(JsonConvert).Assembly.GetName().Version.ToString();\n\n            return result;\n        }\n    }\n}\n"
  },
  {
    "path": "tests/Assemblies/JsonNetOld/JsonNetOld.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>netstandard2.0</TargetFramework>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <OutputPath>..\\bin\\JsonOld</OutputPath>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Newtonsoft.Json\" Version=\"9.0.1\"/>\n    <PackageReference Include=\"Microsoft.Extensions.Logging\" Version=\"2.2.0\"/>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\TestIntefaces\\TestIntefaces.csproj\"/>\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "tests/Assemblies/JsonNetOld/OldJsonResolver.cs",
    "content": "﻿using System;\nusing Newtonsoft.Json;\nusing TestIntefaces;\n\nnamespace JsonNetOld\n{\n    public class OldJsonResolver : IJsonVersionResolver\n    {\n        public string GetVersion()\n        {\n            var result = typeof(JsonConvert).Assembly.GetName().Version.ToString();\n\n            return result;\n        }\n        \n        public string GetLoggingVersion()\n        {\n            var logging = new Microsoft.Extensions.Logging.LoggerFactory();\n            Console.WriteLine(logging.ToString());\n            \n            var result = typeof(Microsoft.Extensions.Logging.LoggerFactory).Assembly.GetName().Version.ToString();\n\n            return result;\n        }\n    }\n}\n"
  },
  {
    "path": "tests/Assemblies/TestAssembly1/FirstPlugin.cs",
    "content": "﻿using TestIntefaces;\n\nnamespace TestAssembly1\n{\n    public class FirstPlugin : ICommand\n    {\n        public string RunMe()\n        {\n            return \"Hello from RunMe\";\n        }\n    }\n}\n"
  },
  {
    "path": "tests/Assemblies/TestAssembly1/INotPluginInterface.cs",
    "content": "﻿namespace TestAssembly1\n{\n    public interface INotPluginInterface\n    {\n        \n    }\n}\n"
  },
  {
    "path": "tests/Assemblies/TestAssembly1/NotAPlugin.cs",
    "content": "﻿namespace TestAssembly1\n{\n    public abstract class NotAPlugin\n    {\n        \n    }\n}\n"
  },
  {
    "path": "tests/Assemblies/TestAssembly1/TestAssembly1.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>netstandard2.0</TargetFramework>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <OutputPath>..\\bin</OutputPath>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\TestIntefaces\\TestIntefaces.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "tests/Assemblies/TestAssembly2/SecondPlugin.cs",
    "content": "﻿using System;\n\nnamespace TestAssembly2\n{\n    public class SecondPlugin\n    {\n        \n    }\n}\n"
  },
  {
    "path": "tests/Assemblies/TestAssembly2/TestAssembly2.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>netstandard2.0</TargetFramework>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <OutputPath>..\\bin</OutputPath>\n  </PropertyGroup>\n\n\n</Project>\n"
  },
  {
    "path": "tests/Assemblies/TestAssembly3/TestAssembly3.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>netstandard2.0</TargetFramework>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <OutputPath>..\\bin</OutputPath>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\TestIntefaces\\TestIntefaces.csproj\" />\n  </ItemGroup>\n  \n</Project>\n"
  },
  {
    "path": "tests/Assemblies/TestAssembly3/ThirdAddon.cs",
    "content": "﻿using TestIntefaces;\n\nnamespace TestAssembly3\n{\n    public class ThirdAddon : ICommand\n    {\n    }\n}\n"
  },
  {
    "path": "tests/Assemblies/TestIntefaces/ICommand.cs",
    "content": "﻿using System;\n\nnamespace TestIntefaces\n{\n    public interface ICommand\n    {\n    }\n}\n"
  },
  {
    "path": "tests/Assemblies/TestIntefaces/IJsonVersionResolver.cs",
    "content": "﻿namespace TestIntefaces\n{\n    public interface IJsonVersionResolver\n    {\n        string GetVersion();\n    }\n}\n"
  },
  {
    "path": "tests/Assemblies/TestIntefaces/TestIntefaces.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>netstandard2.0</TargetFramework>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <OutputPath>..\\bin</OutputPath>\n  </PropertyGroup>\n  \n</Project>\n"
  },
  {
    "path": "tests/integration/WebSites/PluginFrameworkTestBed/Controllers/WeatherForecastController.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.Extensions.Logging;\n\nnamespace PluginFrameworkTestBed.Controllers\n{\n    [ApiController]\n    [Route(\"[controller]\")]\n    public class WeatherForecastController : ControllerBase\n    {\n        private static readonly string[] Summaries = new[]\n        {\n            \"Freezing\", \"Bracing\", \"Chilly\", \"Cool\", \"Mild\", \"Warm\", \"Balmy\", \"Hot\", \"Sweltering\", \"Scorching\"\n        };\n\n        private readonly ILogger<WeatherForecastController> _logger;\n\n        public WeatherForecastController(ILogger<WeatherForecastController> logger)\n        {\n            _logger = logger;\n        }\n\n        [HttpGet]\n        public IEnumerable<WeatherForecast> Get()\n        {\n            var rng = new Random();\n\n            return Enumerable.Range(1, 5).Select(index => new WeatherForecast\n                {\n                    Date = DateTime.Now.AddDays(index), TemperatureC = rng.Next(-20, 55), Summary = Summaries[rng.Next(Summaries.Length)]\n                })\n                .ToArray();\n        }\n    }\n}\n"
  },
  {
    "path": "tests/integration/WebSites/PluginFrameworkTestBed/PluginFrameworkTestBed.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n    <PropertyGroup>\n        <TargetFramework>netcoreapp3.1</TargetFramework>\n    </PropertyGroup>\n\n\n</Project>\n"
  },
  {
    "path": "tests/integration/WebSites/PluginFrameworkTestBed/Program.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.Logging;\n\nnamespace PluginFrameworkTestBed\n{\n    public class Program\n    {\n        public static void Main(string[] args)\n        {\n            CreateHostBuilder(args).Build().Run();\n        }\n\n        public static IHostBuilder CreateHostBuilder(string[] args) =>\n            Host.CreateDefaultBuilder(args)\n                .ConfigureWebHostDefaults(webBuilder =>\n                {\n                    webBuilder.UseStartup<Startup>();\n                });\n    }\n}\n"
  },
  {
    "path": "tests/integration/WebSites/PluginFrameworkTestBed/Startup.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.AspNetCore.HttpsPolicy;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.Logging;\n\nnamespace PluginFrameworkTestBed\n{\n    public class Startup\n    {\n        public Startup(IConfiguration configuration)\n        {\n            Configuration = configuration;\n        }\n\n        public IConfiguration Configuration { get; }\n\n        // This method gets called by the runtime. Use this method to add services to the container.\n        public void ConfigureServices(IServiceCollection services)\n        {\n            services.AddControllers();\n        }\n\n        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.\n        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)\n        {\n            if (env.IsDevelopment())\n            {\n                app.UseDeveloperExceptionPage();\n            }\n\n            app.UseHttpsRedirection();\n\n            app.UseRouting();\n\n            app.UseAuthorization();\n\n            app.UseEndpoints(endpoints =>\n            {\n                endpoints.MapControllers();\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "tests/integration/WebSites/PluginFrameworkTestBed/WeatherForecast.cs",
    "content": "using System;\n\nnamespace PluginFrameworkTestBed\n{\n    public class WeatherForecast\n    {\n        public DateTime Date { get; set; }\n\n        public int TemperatureC { get; set; }\n\n        public int TemperatureF => 32 + (int) (TemperatureC / 0.5556);\n\n        public string Summary { get; set; }\n    }\n}\n"
  },
  {
    "path": "tests/integration/WebSites/PluginFrameworkTestBed/appsettings.Development.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft\": \"Warning\",\n      \"Microsoft.Hosting.Lifetime\": \"Information\"\n    }\n  }\n}\n"
  },
  {
    "path": "tests/integration/WebSites/PluginFrameworkTestBed/appsettings.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft\": \"Warning\",\n      \"Microsoft.Hosting.Lifetime\": \"Information\"\n    }\n  },\n  \"AllowedHosts\": \"*\"\n}\n"
  },
  {
    "path": "tests/integration/Weikio.PluginFramework.AspNetCore.IntegrationTests/DefaultPluginTypeTests.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Linq;\nusing Microsoft.AspNetCore.Mvc.Testing;\nusing Microsoft.Extensions.DependencyInjection;\nusing PluginFrameworkTestBed;\nusing Weikio.PluginFramework.Samples.Shared;\nusing Weikio.PluginFramework.Samples.SharedPlugins;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Weikio.PluginFramework.AspNetCore.IntegrationTests\n{\n    public class DefaultPluginTypeTests : TestBase\n    {\n        public DefaultPluginTypeTests(WebApplicationFactory<Startup> factory, ITestOutputHelper output) : base(factory, output)\n        {\n        }\n        \n        [Fact]\n        public void DefaultsToFirstPluginType()\n        {\n            var sp = Init(services =>\n            {\n                services.AddPluginType<IOperator>();\n            });\n\n            var operators = sp.GetRequiredService<IEnumerable<IOperator>>();\n            var defaultOperator = sp.GetRequiredService<IOperator>();\n            \n            Assert.Equal(operators.First().GetType(), defaultOperator.GetType());\n        }\n        \n        [Fact]\n        public void CanConfigureUsingAction()\n        {\n            var sp = Init(services =>\n            {\n                services.AddPluginType<IOperator>(configureDefault: option =>\n                {\n                    option.DefaultType = (provider, types) => typeof(SumOperator);\n                });\n            });\n\n            var defaultOperator = sp.GetRequiredService<IOperator>();\n            \n            Assert.Equal(typeof(SumOperator), defaultOperator.GetType());\n        }\n        \n        [Fact]\n        public void CanConfigureUsingOptions()\n        {\n            var sp = Init(services =>\n            {\n                services.AddPluginType<IOperator>();\n                \n                services.Configure<DefaultPluginOption>(nameof(IOperator), option =>\n                    option.DefaultType = (serviceProvider, implementingTypes) => typeof(MultiplyOperator));\n            });\n\n            var defaultOperator = sp.GetRequiredService<IOperator>();\n            \n            Assert.Equal(typeof(MultiplyOperator), defaultOperator.GetType());\n        }\n    }\n}\n"
  },
  {
    "path": "tests/integration/Weikio.PluginFramework.AspNetCore.IntegrationTests/TestBase.cs",
    "content": "﻿using System;\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.AspNetCore.Mvc.Testing;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing PluginFrameworkTestBed;\nusing Weikio.PluginFramework.Catalogs;\nusing Weikio.PluginFramework.Samples.Shared;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Weikio.PluginFramework.AspNetCore.IntegrationTests\n{\n    public class TestBase : IClassFixture<WebApplicationFactory<Startup>>\n    {\n        private readonly WebApplicationFactory<Startup> _factory;\n        public ITestOutputHelper Output { get; set; }\n\n        protected TestBase(WebApplicationFactory<Startup> factory, ITestOutputHelper output)\n        {\n            Output = output;\n            _factory = factory;\n        }  \n        \n        protected IServiceProvider Init(Action<IServiceCollection> action = null)\n        {\n            var folderPluginCatalog = new FolderPluginCatalog(@\"..\\..\\..\\..\\..\\..\\Samples\\Shared\\Weikio.PluginFramework.Samples.SharedPlugins\\bin\\debug\\netcoreapp3.1\", type =>\n            {\n                type.Implements<IOperator>();\n            });\n            \n            var server = _factory.WithWebHostBuilder(builder =>\n            {\n                builder.ConfigureServices(services =>\n                {\n                    services.AddPluginFramework()\n                        .AddPluginCatalog(folderPluginCatalog);\n                    \n                    action?.Invoke(services);\n                });\n                \n                builder.ConfigureLogging(logging =>\n                {\n                    logging.ClearProviders(); // Remove other loggers\n                    XUnitLoggerExtensions.AddXUnit((ILoggingBuilder) logging, Output); // Use the ITestOutputHelper instance\n                });\n                \n            });\n\n            return server.Services;\n        }\n    }\n}\n"
  },
  {
    "path": "tests/integration/Weikio.PluginFramework.AspNetCore.IntegrationTests/Weikio.PluginFramework.AspNetCore.IntegrationTests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n    <PropertyGroup>\n        <TargetFramework>netcoreapp3.1</TargetFramework>\n    </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.AspNetCore.Mvc.Testing\" Version=\"3.1.0\" />\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"16.4.0\" />\n    <PackageReference Include=\"xunit\" Version=\"2.4.1\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"2.4.1\" />\n    <PackageReference Include=\"NLog\" Version=\"4.7.0\" />\n    <PackageReference Include=\"MartinCostello.Logging.XUnit\" Version=\"0.1.0\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Content Update=\"xunit.runner.json\">\n      <ExcludeFromSingleFile>true</ExcludeFromSingleFile>\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n      <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>\n    </Content>\n  </ItemGroup>\n    <ItemGroup>\n      <ProjectReference Include=\"..\\..\\..\\samples\\Shared\\Weikio.PluginFramework.Samples.SharedPlugins\\Weikio.PluginFramework.Samples.SharedPlugins.csproj\" />\n      <ProjectReference Include=\"..\\..\\..\\samples\\Shared\\Weikio.PluginFramework.Samples.Shared\\Weikio.PluginFramework.Samples.Shared.csproj\" />\n      <ProjectReference Include=\"..\\..\\..\\src\\Weikio.PluginFramework.AspNetCore\\Weikio.PluginFramework.AspNetCore.csproj\" />\n      <ProjectReference Include=\"..\\WebSites\\PluginFrameworkTestBed\\PluginFrameworkTestBed.csproj\" />\n    </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "tests/integration/Weikio.PluginFramework.AspNetCore.IntegrationTests/xunit.runner.json",
    "content": "{\n  \"shadowCopy\": false\n}\n"
  },
  {
    "path": "tests/integration/Weikio.PluginFramework.Catalogs.NuGet.Tests/NotThreadSafeResourceCollection.cs",
    "content": "﻿using Xunit;\n\nnamespace PluginFramework.Catalogs.NuGet.Tests\n{\n    [CollectionDefinition(nameof(NotThreadSafeResourceCollection), DisableParallelization = true)]\n    public class NotThreadSafeResourceCollection { }\n}\n"
  },
  {
    "path": "tests/integration/Weikio.PluginFramework.Catalogs.NuGet.Tests/NuGet.Config",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n  <packageSources>\n    <add key=\"nuget.org_test\" value=\"https://api.nuget.org/v3/index.json\" protocolVersion=\"3\" />\n  </packageSources>\n</configuration>"
  },
  {
    "path": "tests/integration/Weikio.PluginFramework.Catalogs.NuGet.Tests/NugetFeedPluginCatalogTests.cs",
    "content": "using System;\nusing System.IO;\nusing System.Linq;\nusing System.Reflection;\nusing System.Runtime.Versioning;\nusing System.Threading.Tasks;\nusing Weikio.NugetDownloader;\nusing Weikio.PluginFramework.Abstractions;\nusing Weikio.PluginFramework.Catalogs;\nusing Weikio.PluginFramework.Catalogs.NuGet;\nusing Xunit;\n\nnamespace PluginFramework.Catalogs.NuGet.Tests\n{\n    public class NugetFeedPluginCatalogTests\n    {\n        // this folder is defined in test project's bin so that NuGet implementation\n        // will use the NuGet.Config defined in the test project root.\n        private readonly string _packagesFolderInTestsBin;\n\n        public NugetFeedPluginCatalogTests()\n        {\n            var executingAssemblyDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);\n            _packagesFolderInTestsBin = Path.Combine(executingAssemblyDir, \"FeedTestPackages\");\n        }\n\n        private void AssertAssemblyFrameWork(string targetFramework, Assembly assembly)\n        {\n            var assemblyFramework = assembly\n                .GetCustomAttribute<TargetFrameworkAttribute>()?\n                .FrameworkName;\n\n            Assert.Equal(targetFramework, assemblyFramework);\n        }\n\n        [Fact]\n        public async Task InstallUsingTagFilter()\n        {\n            // Arrange\n            var feed = new NuGetFeed(\"nuget.org\", \"https://api.nuget.org/v3/index.json\");\n            var catalog = new NugetFeedPluginCatalog(feed, searchTerm: \"tags:mocking\", maxPackages: 1, configureFinder: configure =>\n            {\n                configure.HasName(\"Moq.Range\");\n            });\n\n            // Act\n            await catalog.Initialize();\n            var plugins = catalog.GetPlugins();\n\n            // Assert\n            Assert.Single(plugins);\n            Assert.Equal(\"Moq.Range\", plugins[0].Name);\n            Assert.StartsWith(\"4.\", plugins[0].Version.ToString());\n            AssertAssemblyFrameWork(\".NETStandard,Version=v2.1\", plugins.Single().Assembly);\n        }\n        \n        [Fact]\n        public async Task CanTag()\n        {\n            // Arrange\n            var feed = new NuGetFeed(\"nuget.org\", \"https://api.nuget.org/v3/index.json\");\n            var catalog = new NugetFeedPluginCatalog(feed, searchTerm: \"tags:mocking\", maxPackages: 1, configureFinder: configure =>\n            {\n                configure.HasName(\"Moq.Range\")\n                    .Tag(\"MockSolutions\");\n            });\n\n            // Act\n            await catalog.Initialize();\n            var plugin = catalog.Single();\n\n            // Assert\n            Assert.Equal(\"MockSolutions\", plugin.Tag);\n        }\n        \n        [Fact]\n        public async Task CanConfigureNamingOptions()\n        {\n            var options = new NugetFeedPluginCatalogOptions()\n            {\n                PluginNameOptions = new PluginNameOptions() { PluginNameGenerator = (nameOptions, type) => type.FullName + \"Modified\" }\n            };\n\n            // Arrange\n            var feed = new NuGetFeed(\"nuget.org\", \"https://api.nuget.org/v3/index.json\");\n            var catalog = new NugetFeedPluginCatalog(feed, searchTerm: \"tags:mocking\", maxPackages: 1, configureFinder: configure =>\n            {\n                configure.HasName(\"Moq.Range\");\n            }, options: options);\n\n            // Act\n            await catalog.Initialize();\n            var plugin = catalog.Single();\n\n            // Assert\n            Assert.EndsWith(\"Modified\", plugin.Name);\n        }\n \n        [Collection(nameof(NotThreadSafeResourceCollection))]\n        public class DefaultOptions : IDisposable\n        {\n            public DefaultOptions()\n            {\n                NugetFeedPluginCatalogOptions.Defaults.PluginNameOptions = new PluginNameOptions()\n                {\n                    PluginNameGenerator = (nameOptions, type) => type.FullName + \"Modified\"\n                };\n            }\n            \n            [Fact]\n            public async Task CanConfigureDefaultNamingOptions()\n            {\n\n                // Arrange\n                var feed = new NuGetFeed(\"nuget.org\", \"https://api.nuget.org/v3/index.json\");\n                var catalog = new NugetFeedPluginCatalog(feed, searchTerm: \"tags:mocking\", maxPackages: 1, configureFinder: configure =>\n                {\n                    configure.HasName(\"Moq.Range\");\n                });\n\n                // Act\n                await catalog.Initialize();\n                var plugin = catalog.Single();\n\n                // Assert\n                Assert.EndsWith(\"Modified\", plugin.Name);\n            } \n            \n            public void Dispose()\n            {\n                NugetFeedPluginCatalogOptions.Defaults.PluginNameOptions = new PluginNameOptions();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "tests/integration/Weikio.PluginFramework.Catalogs.NuGet.Tests/NugetPackagePluginCatalogTests.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Reflection;\nusing System.Runtime.Versioning;\nusing System.Threading.Tasks;\nusing Weikio.NugetDownloader;\nusing Weikio.PluginFramework.Abstractions;\nusing Weikio.PluginFramework.Catalogs;\nusing Weikio.PluginFramework.Catalogs.NuGet;\nusing Weikio.PluginFramework.TypeFinding;\nusing Xunit;\n\nnamespace PluginFramework.Catalogs.NuGet.Tests\n{\n    public class NugetPackagePluginCatalogTests\n    {\n        // this folder is defined in test project's bin so that NuGet implementation\n        // will use the NuGet.Config defined in the test project root.\n        private readonly string _packagesFolderInTestsBin;\n\n        public NugetPackagePluginCatalogTests()\n        {\n            var executingAssemblyDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);\n            _packagesFolderInTestsBin = Path.Combine(executingAssemblyDir, \"TestPackages\");\n        }\n\n        private void AssertAssemblyFrameWork(string targetFramework, Assembly assembly)\n        {\n            var assemblyFramework = assembly\n                .GetCustomAttribute<TargetFrameworkAttribute>()?\n                .FrameworkName;\n\n            Assert.Equal(targetFramework, assemblyFramework);\n        }\n\n        [Fact]\n        public async Task InstallPackageWithoutDepencencies()\n        {\n            // Arrange\n            var catalog = new NugetPackagePluginCatalog(\"Serilog\", \"2.9.0\", configureFinder: configure =>\n            {\n                configure.HasName(\"Serilog.Core.Logger\");\n            });\n\n            // Act\n            await catalog.Initialize();\n            var plugins = catalog.GetPlugins();\n\n            // Assert\n            Assert.Single(plugins);\n            Assert.Equal(\"Serilog.Core.Logger\", plugins[0].Name);\n            Assert.StartsWith(\"2.9.0\", plugins[0].Version.ToString());\n            AssertAssemblyFrameWork(\".NETStandard,Version=v2.0\", catalog.Single().Assembly);\n        }\n\n        [Fact]\n        public async Task CanTag()\n        {\n            // Arrange\n            var catalog = new NugetPackagePluginCatalog(\"Serilog\", \"2.9.0\", configureFinder: configure =>\n            {\n                configure.HasName(\"Serilog.Core.Logger\")\n                    .Tag(\"CustomTag\");\n            });\n\n            // Act\n            await catalog.Initialize();\n            var plugin = catalog.Single();\n\n            // Assert\n            Assert.Equal(\"CustomTag\", plugin.Tag);\n        }\n\n        [Fact]\n        public async Task CanConfigureNamingOptions()\n        {\n            var options = new NugetPluginCatalogOptions()\n            {\n                PluginNameOptions = new PluginNameOptions() { PluginNameGenerator = (nameOptions, type) => type.FullName + \"Modified\" }\n            };\n\n            // Arrange\n            var catalog = new NugetPackagePluginCatalog(\"Serilog\", \"2.9.0\", configureFinder: configure =>\n            {\n                configure.HasName(\"Serilog.Core.Logger\");\n            }, options: options);\n\n            // Act\n            await catalog.Initialize();\n            var plugin = catalog.Single();\n\n            // Assert\n            Assert.EndsWith(\"Modified\", plugin.Name);\n        }\n\n        [Fact]\n        public async Task InstallPackageWithDepencencies()\n        {\n            // Arrange\n            var catalog = new NugetPackagePluginCatalog(\"Moq\", \"4.13.1\");\n\n            // Act\n            await catalog.Initialize();\n            var pluginAssemblies = catalog.GetPlugins().GroupBy(x => x.Assembly).ToList();\n\n            // Assert\n            Assert.Single(pluginAssemblies);\n            Assert.EndsWith(\"Moq.dll\", pluginAssemblies.Single().Key.Location);\n            Assert.StartsWith(\"4.13.1\", catalog.GetPlugins().First().Version.ToString());\n            AssertAssemblyFrameWork(\".NETStandard,Version=v2.0\", pluginAssemblies.Single().Key);\n        }\n\n        [Fact]\n        public async Task InstallPackageWithVersionWildcard()\n        {\n            // Arrange\n            var catalog = new NugetPackagePluginCatalog(\"Polly\", \"7.0.*\");\n\n            // Act\n            await catalog.Initialize();\n            var plugins = catalog.GetPlugins();\n\n            // Assert\n            Assert.NotEmpty(plugins);\n        }\n\n        [Fact]\n        public async Task InstallPreReleasePackageWithVersionWildcard()\n        {\n            // Arrange\n            var catalog = new NugetPackagePluginCatalog(\"Serilog\", \"2.9.1-dev*\", includePrerelease: true, configureFinder: configure =>\n            {\n                configure.HasName(\"Serilog.Core.Logger\");\n            });\n\n            // Act\n            await catalog.Initialize();\n            var plugins = catalog.GetPlugins();\n\n            // Assert\n            Assert.Single(plugins);\n            Assert.Equal(\"Serilog.Core.Logger\", plugins[0].Name);\n            Assert.StartsWith(\"2.9.1\", plugins[0].Version.ToString());\n            Assert.StartsWith(\"2.9.1-dev\", plugins[0].ProductVersion);\n            AssertAssemblyFrameWork(\".NETStandard,Version=v2.0\", catalog.Single().Assembly);\n        }\n\n        [Fact]\n        public async Task InstallPackageFromFeed()\n        {\n            // Arrange\n            var feed = new NuGetFeed(\"nuget.org\", \"https://api.nuget.org/v3/index.json\");\n            var catalog = new NugetPackagePluginCatalog(\"Serilog\", \"2.9.0\", packageFeed: feed);\n\n            // Act\n            await catalog.Initialize();\n            var plugins = catalog.GetPlugins();\n\n            // Assert\n            Assert.NotEmpty(plugins);\n        }\n\n        [Fact]\n        public async Task InstallPackageFromFeedUsingFeedName()\n        {\n            // Arrange\n            var catalog = new NugetPackagePluginCatalog(\"Serilog\", \"2.9.0\", packageFeed: new NuGetFeed(\"nuget.org\"));\n\n            // Act\n            await catalog.Initialize();\n            var plugins = catalog.GetPlugins();\n\n            // Assert\n            Assert.NotEmpty(plugins);\n        }\n\n        [Fact]\n        public async Task InstallPackageFromFeedUsingCustomNuGetConfig()\n        {\n            // Arrange\n            var catalog = new NugetPackagePluginCatalog(\"Serilog\", \"2.9.0\", packageFeed: new NuGetFeed(\"nuget.org_test\"),\n                packagesFolder: _packagesFolderInTestsBin);\n\n            // Act\n            await catalog.Initialize();\n            var plugins = catalog.GetPlugins();\n\n            // Assert\n            Assert.NotEmpty(plugins);\n        }\n\n        [Collection(nameof(NotThreadSafeResourceCollection))]\n        public class DefaultOptions : IDisposable\n        {\n            public DefaultOptions()\n            {\n                NugetPluginCatalogOptions.Defaults.PluginNameOptions =\n                    new PluginNameOptions() { PluginNameGenerator = (nameOptions, type) => type.FullName + \"Modified\" };\n            }\n\n            [Fact]\n            public async Task CanConfigureDefaultNamingOptions()\n            {\n                // Arrange\n                var catalog = new NugetPackagePluginCatalog(\"Serilog\", \"2.9.0\", configureFinder: configure =>\n                {\n                    configure.HasName(\"Serilog.Core.Logger\");\n                });\n\n                // Act\n                await catalog.Initialize();\n                var plugin = catalog.Single();\n\n                // Assert\n                Assert.EndsWith(\"Modified\", plugin.Name);\n            }\n\n            public void Dispose()\n            {\n                NugetPluginCatalogOptions.Defaults.PluginNameOptions = new PluginNameOptions();\n            }\n        }\n\n        [Collection(nameof(NotThreadSafeResourceCollection))]\n        public class NugetDownloadResultsSerialisation : IDisposable\n        {\n            private string _packagesFolderInTestsBin;\n\n            public NugetDownloadResultsSerialisation()\n            {\n                var executingAssemblyDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);\n                _packagesFolderInTestsBin = Path.Combine(executingAssemblyDir, \"TestPackagesDownloadResult\");\n            }\n\n            [Fact]\n            public async Task SaveDownloadResultIfGivenCustomPackagesPath()\n            {\n                var options = new NugetPluginCatalogOptions()\n                {\n                    TypeFinderOptions = new TypeFinderOptions()\n                    {\n                        TypeFinderCriterias = new List<TypeFinderCriteria>()\n                    {\n                        new TypeFinderCriteria()\n                        {\n                            Query = (context, type) =>\n                            {\n                                if (string.Equals(type.Name, \"SqlConnection\"))\n                                {\n                                    return true;\n                                }\n\n                                return false;\n                            }\n                        }\n                    }\n                    }\n                };\n\n                // Arrange\n                var catalog = new NugetPackagePluginCatalog(\"Microsoft.Data.SqlClient\", \"2.1.2\", options: options, packagesFolder: _packagesFolderInTestsBin);\n\n                // Act\n                await catalog.Initialize();\n\n                var plugin = catalog.Single();\n\n                // This is the connection string part of the Weik.io docs. It provides readonly access to the Adventureworks database sample.\n                // So it should be ok to have it here.\n                dynamic conn = Activator.CreateInstance(plugin, \"Server=tcp:adafydevtestdb001.database.windows.net,1433;User ID=docs;Password=3h1@*6PXrldU4F95;Integrated Security=false;Initial Catalog=adafyweikiodevtestdb001;\");\n\n                conn.Open();\n\n                var cmd = conn.CreateCommand();\n                cmd.CommandText = \"select top 1 * from SalesLT.Customer\";\n\n                var reader = cmd.ExecuteReader();\n                while (reader.Read())\n                {\n                    Console.WriteLine(String.Format(\"{0}\", reader[0]));\n                }\n\n                conn.Dispose();\n\n                Assert.True(File.Exists(_packagesFolderInTestsBin + \"/.nugetDownloadResult.json\"));\n            }\n\n            public void Dispose()\n            {\n                File.Delete(_packagesFolderInTestsBin + \"/nugetDownloadResult.json\");\n            }\n        }\n\n        [Fact]\n        public async Task CanInstallPackageWithNativeDepencencies()\n        {\n            var options = new NugetPluginCatalogOptions()\n            {\n                TypeFinderOptions = new TypeFinderOptions()\n                {\n                    TypeFinderCriterias = new List<TypeFinderCriteria>()\n                    {\n                        new TypeFinderCriteria()\n                        {\n                            Query = (context, type) =>\n                            {\n                                if (string.Equals(type.Name, \"SqlConnection\"))\n                                {\n                                    return true;\n                                }\n\n                                return false;\n                            }\n                        }\n                    }\n                }\n            };\n            // Arrange\n            var catalog = new NugetPackagePluginCatalog(\"Microsoft.Data.SqlClient\", \"2.1.2\", options: options);\n\n            // Act\n            await catalog.Initialize();\n\n            var plugin = catalog.Single();\n\n            // This is the connection string part of the Weik.io docs. It provides readonly access to the Adventureworks database sample.\n            // So it should be ok to have it here.\n            dynamic conn = Activator.CreateInstance(plugin, \"Server=tcp:adafydevtestdb001.database.windows.net,1433;User ID=docs;Password=3h1@*6PXrldU4F95;Integrated Security=false;Initial Catalog=adafyweikiodevtestdb001;\");\n\n            conn.Open();\n\n            var cmd = conn.CreateCommand();\n            cmd.CommandText = \"select top 1 * from SalesLT.Customer\";\n\n            var reader = cmd.ExecuteReader();\n            while (reader.Read())\n            {\n                Console.WriteLine(String.Format(\"{0}\", reader[0]));\n            }\n\n            conn.Dispose();\n        }\n    }\n}\n"
  },
  {
    "path": "tests/integration/Weikio.PluginFramework.Catalogs.NuGet.Tests/Weikio.PluginFramework.Catalogs.NuGet.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>netcoreapp3.1</TargetFramework>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"16.4.0\" />\n    <PackageReference Include=\"xunit\" Version=\"2.4.1\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"2.4.1\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\src\\Weikio.PluginFramework.Catalogs.NuGet\\Weikio.PluginFramework.Catalogs.NuGet.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "tests/unit/Weikio.PluginFramework.Catalogs.Roslyn.Tests/RegularInitializerTests.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Reflection;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Weikio.PluginFramework.Catalogs.Roslyn.Tests\n{\n    public class RegularInitializerTests\n    {\n        [Fact]\n        public async Task ThrowsWithInvalidCode()\n        {\n            // Arrange\n            var invalidCode = @\"public class MyClass\n                   {\n                       public void RunThings // <- missing parentheses\n                       {\n                           var y = 0;\n                           var a = 1;\n           \n                           a = y + 10;\n                       \n                           Debug.WriteLine(y + a);\n                       }\n                   }\";\n\n            // Assert\n            await Assert.ThrowsAsync<InvalidCodeException>(async () => await TestHelpers.CompileRegular(invalidCode));\n        }\n\n        [Fact]\n        public async Task ThrowsWithEmptyScript()\n        {\n            // Arrange\n            var invalidCode = \"\";\n\n            // Assert: Throws\n            await Assert.ThrowsAsync<ArgumentOutOfRangeException>(async () => await TestHelpers.CompileRegular(invalidCode));\n        }\n\n        [Fact]\n        public async Task CanCompileCode()\n        {\n            // Arrange\n            var code = @\"public class MyClass\n                   {\n                       public void RunThings()\n                       {\n                           var y = 0;\n                           var a = 1;\n           \n                           a = y + 10;\n                       \n                           Debug.WriteLine(y + a);\n                       }\n                   }\";\n\n            // Assert: Does not throw\n            await TestHelpers.CompileRegular(code);\n        }\n\n        [Fact]\n        public async Task CanAddReference()\n        {\n            // Arrange\n            var code = @\"public class MyClass\n                   {\n                       public void RunThings()\n                       {\n                            Newtonsoft.Json.JsonConvert.SerializeObject(15);\n                       }\n                   }\";\n\n            var options = new RoslynPluginCatalogOptions() { AdditionalReferences = new List<Assembly>() { typeof(Newtonsoft.Json.JsonConvert).Assembly } };\n\n            await TestHelpers.CompileRegular(code, options);\n        }\n\n        [Fact]\n        public async Task CanAddNamespace()\n        {\n            // Arrange\n            var code = @\"public class MyClass\n                   {\n                       public void RunThings()\n                       {\n                            JsonConvert.SerializeObject(15);\n                       }\n                   }\";\n\n            var options = new RoslynPluginCatalogOptions()\n            {\n                AdditionalReferences = new List<Assembly>() { typeof(Newtonsoft.Json.JsonConvert).Assembly },\n                AdditionalNamespaces = new List<string>() { \"Newtonsoft.Json\" }\n            };\n\n            await TestHelpers.CompileRegular(code, options);\n        }\n    }\n}\n"
  },
  {
    "path": "tests/unit/Weikio.PluginFramework.Catalogs.Roslyn.Tests/RoslynPluginCatalogTests.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Weikio.PluginFramework.Abstractions;\nusing Xunit;\nusing IPluginCatalogExtensions = Weikio.PluginFramework.Abstractions.IPluginCatalogExtensions;\n\nnamespace Weikio.PluginFramework.Catalogs.Roslyn.Tests\n{\n    public class RoslynPluginCatalogTests\n    {\n        [Fact]\n        public async Task ThrowsWithInvalidCode()\n        {\n            // Arrange\n            var invalidCode = @\"public class MyClass\n                   {\n                       public void RunThings // <- missing parentheses\n                       {\n                           var y = 0;\n                           var a = 1;\n           \n                           a = y + 10;\n                       \n                           Debug.WriteLine(y + a);\n                       }\n                   }\";\n\n            // Assert\n            await Assert.ThrowsAsync<InvalidCodeException>(async () => await TestHelpers.CreateCatalog(invalidCode));\n        }\n\n        [Fact]\n        public async Task ThrowsWithEmptyScript()\n        {\n            // Arrange\n            var invalidCode = \"\";\n\n            // Assert: Throws\n            await Assert.ThrowsAsync<ArgumentOutOfRangeException>(async () => await TestHelpers.CreateCatalog(invalidCode));\n        }\n\n        [Fact]\n        public async Task CanHandleScript()\n        {\n            // Arrange\n            var code = \"Debug.WriteLine(\\\"Hello world!\\\");\";\n\n            // Act\n            var types = await TestHelpers.CreateCatalog(code);\n\n            // Assert\n            Assert.Single(types);\n\n            var method = types.First().GetMethods().First();\n            Assert.Equal(typeof(Task), method.ReturnParameter.ParameterType);\n        }\n\n        [Fact]\n        public async Task ScriptAssemblyContainsValidVersion()\n        {\n            // Arrange\n            var code = \"Debug.WriteLine(\\\"Hello world!\\\");\";\n\n            // Act\n            var type = (await TestHelpers.CreateCatalog(code)).Single();\n\n            // Assert\n            var versionInfo = FileVersionInfo.GetVersionInfo(type.Assembly.Location);\n            var fileVersion = versionInfo.FileVersion;\n            Assert.NotNull(fileVersion);\n        }\n\n        [Fact]\n        public async Task ScriptContainsVersion1000ByDefault()\n        {\n            // Arrange\n            var code = \"Debug.WriteLine(\\\"Hello world!\\\");\";\n\n            // Act\n            var type = (await TestHelpers.CreateCatalog(code)).Single();\n\n            // Assert\n            var versionInfo = FileVersionInfo.GetVersionInfo(type.Assembly.Location);\n            var fileVersion = versionInfo.FileVersion;\n            Assert.Equal(\"1.0.0.0\", fileVersion);\n        }\n\n        [Fact]\n        public async Task CanHandleRegular()\n        {\n            // Arrange\n            var code = @\"public class MyClass\n                   {\n                       public void RunThings()\n                       {\n                           var y = 0;\n                           var a = 1;\n           \n                           a = y + 10;\n                       \n                           Debug.WriteLine(y + a);\n                       }\n                   }\";\n\n            // Act\n            var types = await TestHelpers.CompileRegular(code);\n\n            // Assert\n            Assert.Single(types);\n\n            var method = types.First().GetMethods().First();\n            Assert.Equal(typeof(void), method.ReturnParameter.ParameterType);\n        }\n\n        [Fact]\n        public async Task CanCreatePluginWithoutName()\n        {\n            // Arrange\n            var code = @\"public class MyClass\n                   {\n                       public void RunThings()\n                       {\n                           var y = 0;\n                           var a = 1;\n           \n                           a = y + 10;\n                       \n                           Debug.WriteLine(y + a);\n                       }\n                   }\";\n\n            var catalog = new RoslynPluginCatalog(code);\n\n            // Act\n            await catalog.Initialize();\n            var plugins = catalog.GetPlugins();\n            var firstPluginName = plugins.First().Name;\n\n            // Assert\n            Assert.NotEmpty(firstPluginName);\n        }\n\n        [Fact]\n        public async Task CanCreatePluginWithName()\n        {\n            // Arrange\n            var code = @\"public class MyClass\n                   {\n                       public void RunThings()\n                       {\n                           var y = 0;\n                           var a = 1;\n           \n                           a = y + 10;\n                       \n                           Debug.WriteLine(y + a);\n                       }\n                   }\";\n\n            var options = new RoslynPluginCatalogOptions() { PluginName = \"MyPlugin\", };\n\n            // Act\n            var catalog = new RoslynPluginCatalog(code, options);\n            await catalog.Initialize();\n\n            var plugin = catalog.Get(\"MyPlugin\", new Version(1, 0, 0, 0));\n\n            // Assert\n            Assert.NotNull(plugin);\n        }\n\n        [Fact]\n        public async Task PluginDefaultsToVersion100()\n        {\n            // Arrange\n            var code = @\"public class MyClass\n                   {\n                       public void RunThings()\n                       {\n                           var y = 0;\n                           var a = 1;\n           \n                           a = y + 10;\n                       \n                           Debug.WriteLine(y + a);\n                       }\n                   }\";\n\n            var options = new RoslynPluginCatalogOptions() { PluginName = \"MyPlugin\", };\n\n            var catalog = new RoslynPluginCatalog(code, options);\n\n            // Act\n            await catalog.Initialize();\n            var plugin = catalog.Get(\"MyPlugin\", new Version(1, 0, 0, 0));\n\n            // Assert\n            Assert.Equal(new Version(1, 0, 0, 0), plugin.Version);\n        }\n\n        [Fact]\n        public async Task CanCreatePluginWithNameAndVersion()\n        {\n            // Arrange\n            var code = @\"public class MyClass\n                   {\n                       public void RunThings()\n                       {\n                           var y = 0;\n                           var a = 1;\n           \n                           a = y + 10;\n                       \n                           Debug.WriteLine(y + a);\n                       }\n                   }\";\n\n            var options = new RoslynPluginCatalogOptions() { PluginName = \"MyPlugin\", PluginVersion = new Version(1, 1) };\n\n            var catalog = new RoslynPluginCatalog(code, options);\n\n            // Act\n            await catalog.Initialize();\n            var plugin = catalog.Get(\"MyPlugin\", new Version(1, 1));\n\n            // Assert\n            Assert.NotNull(plugin);\n        }\n\n        [Fact]\n        public async Task CanGetAllFromCatalog()\n        {\n            // Arrange\n            var code = @\"public class MyClass\n                   {\n                       public void RunThings()\n                       {\n                           var y = 0;\n                           var a = 1;\n           \n                           a = y + 10;\n                       \n                           Debug.WriteLine(y + a);\n                       }\n                   }\";\n\n            var catalog = new RoslynPluginCatalog(code);\n\n            // Act\n            await catalog.Initialize();\n            var plugins = catalog.GetPlugins();\n            var plugin = plugins.FirstOrDefault();\n\n            // Assert\n            Assert.NotNull(plugin);\n        }\n\n        [Fact]\n        public async Task CanCreatePluginNameWithGenerator()\n        {\n            // Arrange\n            var code = @\"public class MyClass\n                   {\n                       public void RunThings()\n                       {\n                           var y = 0;\n                           var a = 1;\n           \n                           a = y + 10;\n                       \n                           Debug.WriteLine(y + a);\n                       }\n                   }\";\n\n            var options = new RoslynPluginCatalogOptions()\n            {\n                PluginNameOptions = new PluginNameOptions() { PluginNameGenerator = (nameOptions, type) => \"HelloThereFromGenerator\" },\n            };\n\n            var catalog = new RoslynPluginCatalog(code, options);\n\n            // Act\n            await catalog.Initialize();\n\n            // Assert\n            var plugin = catalog.Get(\"HelloThereFromGenerator\", Version.Parse(\"1.0.0.0\"));\n            Assert.NotNull(plugin);\n        }\n\n        [Fact]\n        public async Task CanCreatePluginVersionWithGenerator()\n        {\n            // Arrange\n            var code = @\"public class MyClass\n                   {\n                       public void RunThings()\n                       {\n                           var y = 0;\n                           var a = 1;\n           \n                           a = y + 10;\n                       \n                           Debug.WriteLine(y + a);\n                       }\n                   }\";\n\n            var options = new RoslynPluginCatalogOptions()\n            {\n                PluginNameOptions = new PluginNameOptions() { PluginVersionGenerator = (nameOptions, type) => new Version(2, 0, 0) }\n            };\n\n            var catalog = new RoslynPluginCatalog(code, options);\n\n            // Act\n            await catalog.Initialize();\n            var plugin = catalog.Single();\n\n            // Assert\n            Assert.Equal(new Version(2, 0, 0), plugin.Version);\n        }\n\n        [Fact]\n        public async Task CanTagCode()\n        {\n            // Arrange\n            var code = @\"public class MyClass\n                   {\n                       public void RunThings()\n                       {\n                           var y = 0;\n                           var a = 1;\n           \n                           a = y + 10;\n                       \n                           Debug.WriteLine(y + a);\n                       }\n                   }\";\n\n            var catalog = new RoslynPluginCatalog(code, new RoslynPluginCatalogOptions() { Tags = new List<string>() { \"CustomTag\" } });\n\n            await catalog.Initialize();\n            var plugin = catalog.Single();\n\n            Assert.Equal(\"CustomTag\", plugin.Tag);\n        }\n\n        [Fact]\n        public async Task CanTagScript()\n        {\n            // Arrange\n            var code = \"Debug.WriteLine(\\\"Hello world!\\\");\";\n\n            var catalog = new RoslynPluginCatalog(code, new RoslynPluginCatalogOptions() { Tags = new List<string>() { \"CustomTag\" } });\n\n            await catalog.Initialize();\n\n            var plugin = catalog.Single();\n\n            Assert.Equal(\"CustomTag\", plugin.Tag);\n        }\n    }\n}\n"
  },
  {
    "path": "tests/unit/Weikio.PluginFramework.Catalogs.Roslyn.Tests/ScriptInitializerTests.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Weikio.PluginFramework.Catalogs.Roslyn.Tests\n{\n    public class ScriptInitializerTests\n    {\n        [Fact]\n        public async Task ThrowsWithInvalidScript()\n        {\n            // Arrange\n            var invalidCode = \"not c#\";\n\n            // Assert\n            await Assert.ThrowsAsync<InvalidCodeException>(async () => await TestHelpers.CompileScript(invalidCode));\n        }\n\n        [Fact]\n        public async Task ThrowsWithEmptyScript()\n        {\n            // Arrange\n            var invalidCode = \"\";\n\n            // Assert: Throws\n            await Assert.ThrowsAsync<ArgumentOutOfRangeException>(async () => await TestHelpers.CompileScript(invalidCode));\n        }\n\n        [Fact]\n        public async Task CanInitVoid()\n        {\n            // Arrange\n            var code = \"Debug.WriteLine(\\\"Hello world!\\\");\";\n\n            // Act\n            var types = await TestHelpers.CompileScript(code);\n\n            // Assert\n            Assert.Single(types);\n\n            var method = types.First().GetMethods().First();\n            Assert.True(method.ReturnParameter.ParameterType == typeof(Task));\n        }\n\n        [Fact]\n        public async Task CanInitVoidWithParameter()\n        {\n            // Arrange\n            var code = \"string dah {get;set;} = \\\"hello\\\"; var i = 5; Debug.WriteLine(dah);\";\n\n            // Act\n            var types = await TestHelpers.CompileScript(code);\n\n            // Assert\n            Assert.Single(types);\n\n            var method = types.First().GetMethods().First();\n            var methodParameters = method.GetParameters().ToList();\n            Assert.Single(methodParameters);\n            Assert.True(methodParameters.Single().ParameterType == typeof(string));\n        }\n\n        [Fact]\n        public async Task CanInitVoidWithMultipleParameters()\n        {\n            // Arrange\n            var code = \"int y {get;set;} = 5; int x {get;set;} = 20; x = y + 20; Debug.WriteLine(x);\";\n\n            // Act\n            var types = await TestHelpers.CompileScript(code);\n\n            // Assert\n            Assert.Single(types);\n\n            var method = types.First().GetMethods().First();\n            var methodParameters = method.GetParameters().ToList();\n            Assert.Equal(2, methodParameters.Count);\n            Assert.True(methodParameters.First().ParameterType == typeof(int));\n        }\n\n        [Fact]\n        public async Task CanInitReturnString()\n        {\n            // Arrange\n            var code = \"var i = 15; var x = \\\"hello\\\"; return x;\";\n\n            // Act\n            var types = await TestHelpers.CompileScript(code);\n\n            // Assert: doesn't throw\n            Assert.Single(types);\n\n            var method = types.First().GetMethods().First();\n            var returnParameter = method.ReturnParameter;\n\n            Assert.NotNull(returnParameter);\n            Assert.Equal(typeof(Task<string>), returnParameter.ParameterType);\n        }\n\n        [Fact]\n        public async Task CanInitReturnStringWithParameters()\n        {\n            // Arrange\n            var code = \"int y {get;set;} = 5; int x {get;set;} = 20; x = y + 20; Debug.WriteLine(x); return x.ToString();\";\n\n            // Act\n            var types = await TestHelpers.CompileScript(code);\n\n            // Assert\n            var method = types.First().GetMethods().First();\n            var returnParameter = method.ReturnParameter;\n\n            Assert.NotNull(returnParameter);\n            Assert.Equal(typeof(Task<string>), returnParameter.ParameterType);\n        }\n\n        [Fact]\n        public async Task CanNotInitReturnValueTuple()\n        {\n            var code = \"var i = 15; var x = \\\"hello\\\"; return (i,x);\";\n\n            await Assert.ThrowsAsync<InvalidCodeException>(async () => await TestHelpers.CompileScript(code));\n        }\n        \n        [Fact]\n        public async Task ThrowsWithMissingTypeNameGenerator()\n        {\n            var code = \"var x = \\\"hello\\\"; return x;\";\n            var options = new RoslynPluginCatalogOptions() { TypeNameGenerator = null };\n\n            await Assert.ThrowsAsync<ArgumentNullException>(async () => await TestHelpers.CompileScript(code, options));\n        }\n\n        [Fact]\n        public async Task ThrowsWithMissingNamespaceNameGenerator()\n        {\n            var code = \"var x = \\\"hello\\\"; return x;\";\n            var options = new RoslynPluginCatalogOptions() { NamespaceNameGenerator = null };\n\n            await Assert.ThrowsAsync<ArgumentNullException>(async () => await TestHelpers.CompileScript(code, options));\n        }\n\n        [Fact]\n        public async Task HasDefaultTypeName()\n        {\n            // Arrange\n            var code = \"var x = \\\"hello\\\"; return x;\";\n\n            // Act\n            var type = (await TestHelpers.CompileScript(code)).First();\n\n            // Assert\n            var defaultOptions = new RoslynPluginCatalogOptions();\n\n            Assert.Equal(defaultOptions.TypeName, type.Name);\n        }\n\n        [Fact]\n        public async Task HasDefaultNamespace()\n        {\n            // Arrange\n            var code = \"var x = \\\"hello\\\"; return x;\";\n\n            // Act\n            var type = (await TestHelpers.CompileScript(code)).First();\n\n            // Assert\n            var defaultOptions = new RoslynPluginCatalogOptions();\n\n            Assert.Equal(defaultOptions.NamespaceName, type.Namespace);\n        }\n\n        [Fact]\n        public async Task DefaultsToReturningTask()\n        {\n            // Arrange\n            var code = \"var x = \\\"hello\\\"; return x;\";\n\n            // Act\n            var type = (await TestHelpers.CompileScript(code)).First();\n            var method = type.GetMethods().First();\n\n            // Assert\n            Assert.Equal(typeof(Task<string>), method.ReturnParameter.ParameterType);\n        }\n        \n        [Fact]\n        public async Task HasDefaultMethodName()\n        {\n            // Arrange\n            var code = \"var x = \\\"hello\\\"; return x;\";\n\n            // Act\n            var type = (await TestHelpers.CompileScript(code)).First();\n            var method = type.GetMethods().First();\n\n            // Assert\n            Assert.Equal(\"Run\", method.Name);\n        }\n        \n        [Fact]\n        public async Task CanConfigureMethodName()\n        {\n            // Arrange\n            var code = \"var x = \\\"hello\\\"; return x;\";\n            var options = new RoslynPluginCatalogOptions() { MethodName = \"Execute\" };\n\n            // Act\n            var type = (await TestHelpers.CompileScript(code, options)).First();\n            var method = type.GetMethods().First();\n\n            // Assert\n            Assert.Equal(\"Execute\", method.Name);\n        }\n        \n        [Fact]\n        public async Task CanConfigureMethodNameGenerator()\n        {\n            // Arrange\n            var code = \"var x = \\\"hello\\\"; return x;\";\n            var options = new RoslynPluginCatalogOptions() { MethodNameGenerator = catalogOptions => \"MyMethod\" };\n\n            // Act\n            var type = (await TestHelpers.CompileScript(code, options)).First();\n            var method = type.GetMethods().First();\n\n            // Assert\n            Assert.Equal(\"MyMethod\", method.Name);\n        }\n\n        [Fact]\n        public async Task CanConfigureTypeName()\n        {\n            // Arrange\n            var code = \"var x = \\\"hello\\\"; return x;\";\n            var options = new RoslynPluginCatalogOptions() { TypeName = \"MyTest\" };\n\n            // Act\n            var type = (await TestHelpers.CompileScript(code, options)).First();\n\n            // Assert\n            Assert.Equal(\"MyTest\", type.Name);\n        }\n\n        [Fact]\n        public async Task CanConfigureTypeNameGenerator()\n        {\n            // Arrange\n            var code = \"var x = \\\"hello\\\"; return x;\";\n\n            var typeName = \"MyTestTypeName\";\n            var options = new RoslynPluginCatalogOptions() { TypeNameGenerator = catalogOptions => typeName + \"15\" };\n\n            // Act\n            var type = (await TestHelpers.CompileScript(code, options)).First();\n\n            // Assert\n            Assert.Equal(\"MyTestTypeName15\", type.Name);\n        }\n\n        [Fact]\n        public async Task CanConfigureNamespace()\n        {\n            // Arrange\n            var code = \"var x = \\\"hello\\\"; return x;\";\n            var options = new RoslynPluginCatalogOptions() { NamespaceName = \"MyTestNamespace\" };\n\n            // Act\n            var type = (await TestHelpers.CompileScript(code, options)).First();\n\n            // Assert\n            Assert.Equal(\"MyTestNamespace\", type.Namespace);\n        }\n\n        [Fact]\n        public async Task CanConfigureNamespaceGenerator()\n        {\n            // Arrange\n            var code = \"var x = \\\"hello\\\"; return x;\";\n\n            var namespaceName = \"MyTestNamespace\";\n            var options = new RoslynPluginCatalogOptions() { NamespaceNameGenerator = catalogOptions => namespaceName + \"10\" };\n\n            // Act\n            var type = (await TestHelpers.CompileScript(code, options)).First();\n\n            // Assert\n            Assert.Equal(\"MyTestNamespace10\", type.Namespace);\n        }\n\n        [Fact]\n        public async Task CanConfigureReturnsTask()\n        {\n            // Arrange\n            var code = \"var x = \\\"hello\\\"; return x;\";\n            var options = new RoslynPluginCatalogOptions() { ReturnsTask = false };\n\n            // Act\n            var type = (await TestHelpers.CompileScript(code, options)).First();\n            var method = type.GetMethods().First();\n\n            // Assert\n            Assert.Equal(typeof(string), method.ReturnParameter.ParameterType);\n        }\n\n        [Fact]\n        public async Task CanConfigureToHaveUniqueTypeNames()\n        {\n            // Arrange\n            var code = \"var i = 15; var x = \\\"hello\\\"; return x;\";\n            var code2 = \"var i = 15; var x = \\\"hello\\\"; return x;\";\n\n            var randomGenerator = new Random(Guid.NewGuid().GetHashCode());\n\n            var options = new RoslynPluginCatalogOptions()\n            {\n                TypeNameGenerator = catalogOptions =>\n                {\n                    var defaultTypeName = catalogOptions.TypeName;\n                    var result = $\"{defaultTypeName}{randomGenerator.Next(int.MaxValue)}\";\n\n                    return result;\n                }\n            };\n\n            // Act\n            var types = await TestHelpers.CompileScript(code, options);\n            var types2 = await TestHelpers.CompileScript(code2, options);\n\n            // Assert\n            var firstType = types.First();\n            var secondType = types2.First();\n\n            Assert.NotEqual(firstType.Name, secondType.Name);\n        }        \n    }\n}\n"
  },
  {
    "path": "tests/unit/Weikio.PluginFramework.Catalogs.Roslyn.Tests/TestHelpers.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Threading.Tasks;\nusing Weikio.PluginFramework.Abstractions;\n\nnamespace Weikio.PluginFramework.Catalogs.Roslyn.Tests\n{\n    public static class TestHelpers\n    {\n        public static async Task<List<Type>> CompileScript(string code, RoslynPluginCatalogOptions options = null)\n        {\n            var catalog = new ScriptInitializer(code, options);\n            var assembly = await catalog.CreateAssembly();\n\n            var result = assembly.GetTypes().Where(x => x.GetCustomAttribute(typeof(CompilerGeneratedAttribute), true) == null).ToList();\n\n            return result;\n        }\n\n        public static async Task<List<Type>> CompileRegular(string code, RoslynPluginCatalogOptions options = null)\n        {\n            var catalog = new RegularInitializer(code, options);\n            var assembly = await catalog.CreateAssembly();\n\n            var result = assembly.GetTypes().Where(x => x.GetCustomAttribute(typeof(CompilerGeneratedAttribute), true) == null).ToList();\n\n            return result;\n        }\n\n        public static async Task<List<Type>> CreateCatalog(string code, RoslynPluginCatalogOptions options = null)\n        {\n            var catalog = new RoslynPluginCatalog(code, options);\n            await catalog.Initialize();\n\n            return catalog.GetPlugins().Select(x => x.Type).ToList();\n        }\n    }\n}\n"
  },
  {
    "path": "tests/unit/Weikio.PluginFramework.Catalogs.Roslyn.Tests/Weikio.PluginFramework.Catalogs.Roslyn.Tests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>netcoreapp3.1</TargetFramework>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"16.3.*\" />\n    <PackageReference Include=\"xunit\" Version=\"2.4.*\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"2.*\" />\n    <PackageReference Include=\"Newtonsoft.Json\" Version=\"12.0.3\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\src\\Weikio.PluginFramework.Catalogs.Roslyn\\Weikio.PluginFramework.Catalogs.Roslyn.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "tests/unit/Weikio.PluginFramework.Tests/AssemblyPluginCatalogTests.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing System.Threading.Tasks;\nusing Weikio.PluginFramework.Abstractions;\nusing Weikio.PluginFramework.Catalogs;\nusing Weikio.PluginFramework.Context;\nusing Weikio.PluginFramework.TypeFinding;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Weikio.PluginFramework.Tests\n{\n    public class AssemblyPluginCatalogTests\n    {\n        private readonly ITestOutputHelper _testOutputHelper;\n\n        public AssemblyPluginCatalogTests(ITestOutputHelper testOutputHelper)\n        {\n            _testOutputHelper = testOutputHelper;\n        }\n\n        [Fact]\n        public async Task CanInitialize()\n        {\n            var catalog = new AssemblyPluginCatalog(@\"..\\..\\..\\..\\..\\Assemblies\\bin\\netstandard2.0\\TestAssembly1.dll\");\n            await catalog.Initialize();\n\n            var allPlugins = catalog.GetPlugins();\n\n            Assert.NotEmpty(allPlugins);\n        }\n\n        [Fact]\n        public async Task CanInitializeWithCriteria()\n        {\n            var catalog = new AssemblyPluginCatalog(@\"..\\..\\..\\..\\..\\Assemblies\\bin\\netstandard2.0\\TestAssembly1.dll\", configure =>\n            {\n                configure.HasName(\"*Plugin\");\n            });\n\n            await catalog.Initialize();\n\n            var allPlugins = catalog.GetPlugins();\n\n            Assert.Single(allPlugins);\n        }\n\n        [Fact]\n        public async Task CanConfigureNamingOptions()\n        {\n            var options = new AssemblyPluginCatalogOptions()\n            {\n                PluginNameOptions = new PluginNameOptions() { PluginNameGenerator = (nameOptions, type) => type.FullName + \"Modified\" }\n            };\n\n            var catalog = new AssemblyPluginCatalog(@\"..\\..\\..\\..\\..\\Assemblies\\bin\\netstandard2.0\\TestAssembly1.dll\", options);\n\n            await catalog.Initialize();\n\n            var allPlugins = catalog.GetPlugins();\n\n            foreach (var plugin in allPlugins)\n            {\n                Assert.EndsWith(\"Modified\", plugin.Name);\n            }\n        }\n\n        [Fact]\n        public async Task ByDefaultOnlyContainsPublicNonAbstractClasses()\n        {\n            var catalog = new AssemblyPluginCatalog(@\"..\\..\\..\\..\\..\\Assemblies\\bin\\netstandard2.0\\TestAssembly1.dll\");\n            await catalog.Initialize();\n\n            var allPlugins = catalog.GetPlugins();\n\n            var plugin = allPlugins.Single();\n            Assert.False(plugin.Type.IsAbstract);\n            Assert.False(plugin.Type.IsInterface);\n        }\n\n        [Fact]\n        public async Task CanIncludeAbstractClassesUsingCriteria()\n        {\n            var catalog = new AssemblyPluginCatalog(@\"..\\..\\..\\..\\..\\Assemblies\\bin\\netstandard2.0\\TestAssembly1.dll\", builder =>\n            {\n                builder.IsAbstract(true);\n            });\n\n            await catalog.Initialize();\n\n            var allPlugins = catalog.GetPlugins();\n\n            var plugin = allPlugins.Single();\n            Assert.True(plugin.Type.IsAbstract);\n        }\n\n        [Fact]\n        public async Task ThrowsIfAssemblyNotFound()\n        {\n            var catalog = new AssemblyPluginCatalog(@\"..\\..\\..\\..\\..\\Assemblies\\bin\\netstandard2.0\\notexists.dll\");\n\n            await Assert.ThrowsAsync<ArgumentException>(async () => await catalog.Initialize());\n        }\n\n        [Fact]\n        public void ThrowsIfAssemblyPathMissing()\n        {\n            Assert.Throws<ArgumentNullException>(() => new AssemblyPluginCatalog(\"\"));\n\n            string path = null;\n            Assert.Throws<ArgumentNullException>(() => new AssemblyPluginCatalog(path));\n        }\n\n        [Fact]\n        public async Task CanUseReferencedDependencies()\n        {\n            // Make sure that the referenced version of JSON.NET is loaded into memory\n            var json = Newtonsoft.Json.JsonConvert.SerializeObject(1);\n            _testOutputHelper.WriteLine(json);\n\n            var options = new AssemblyPluginCatalogOptions()\n            {\n                PluginLoadContextOptions = new PluginLoadContextOptions() { UseHostApplicationAssemblies = UseHostApplicationAssembliesEnum.Never }\n            };\n\n            var assemblyCatalog1 = new AssemblyPluginCatalog(@\"..\\..\\..\\..\\..\\Assemblies\\bin\\JsonNew\\netstandard2.0\\JsonNetNew.dll\", options);\n            await assemblyCatalog1.Initialize();\n\n            var assemblyCatalog2 = new AssemblyPluginCatalog(@\"..\\..\\..\\..\\..\\Assemblies\\bin\\JsonOld\\netstandard2.0\\JsonNetOld.dll\", options);\n            await assemblyCatalog2.Initialize();\n\n            var newPlugin = assemblyCatalog1.Single();\n            var oldPlugin = assemblyCatalog2.Single();\n\n            dynamic newPluginJsonResolver = Activator.CreateInstance(newPlugin);\n            var newPluginVersion = newPluginJsonResolver.GetVersion();\n\n            dynamic oldPluginJsonResolver = Activator.CreateInstance(oldPlugin);\n            var oldPluginVersion = oldPluginJsonResolver.GetVersion();\n\n            Assert.Equal(\"10.0.0.0\", newPluginVersion);\n            Assert.Equal(\"9.0.0.0\", oldPluginVersion);\n        }\n\n        [Fact]\n        public async Task CanUseHostsDependencies()\n        {\n            // Make sure that the referenced version of JSON.NET is loaded into memory\n            var json = Newtonsoft.Json.JsonConvert.SerializeObject(1);\n            _testOutputHelper.WriteLine(json);\n\n            var options = new AssemblyPluginCatalogOptions\n            {\n                PluginLoadContextOptions = new PluginLoadContextOptions() { UseHostApplicationAssemblies = UseHostApplicationAssembliesEnum.Always }\n            };\n\n            var folder1Catalog = new AssemblyPluginCatalog(@\"..\\..\\..\\..\\..\\Assemblies\\bin\\JsonNew\\netstandard2.0\\JsonNetNew.dll\", options);\n            await folder1Catalog.Initialize();\n\n            var folder2Catalog = new AssemblyPluginCatalog(@\"..\\..\\..\\..\\..\\Assemblies\\bin\\JsonOld\\netstandard2.0\\JsonNetOld.dll\", options);\n            await folder2Catalog.Initialize();\n\n            var newPlugin = folder1Catalog.Single();\n            var oldPlugin = folder2Catalog.Single();\n\n            dynamic newPluginJsonResolver = Activator.CreateInstance(newPlugin);\n            var newPluginVersion = newPluginJsonResolver.GetVersion();\n\n            dynamic oldPluginJsonResolver = Activator.CreateInstance(oldPlugin);\n            var oldPluginVersion = oldPluginJsonResolver.GetVersion();\n\n            Assert.Equal(\"12.0.0.0\", newPluginVersion);\n            Assert.Equal(\"12.0.0.0\", oldPluginVersion);\n        }\n\n        [Fact]\n        public async Task CanUseSelectedHostsDependencies()\n        {\n            // Make sure that the referenced version of JSON.NET is loaded into memory\n            var json = Newtonsoft.Json.JsonConvert.SerializeObject(1);\n\n            // Make sure that the referenced version of Microsoft.Extensions.Logging is loaded into memory\n            var logging = new Microsoft.Extensions.Logging.LoggerFactory();\n\n            var options = new AssemblyPluginCatalogOptions();\n            ;\n\n            options.PluginLoadContextOptions = new PluginLoadContextOptions()\n            {\n                UseHostApplicationAssemblies = UseHostApplicationAssembliesEnum.Selected,\n                HostApplicationAssemblies = new List<AssemblyName>() { typeof(Microsoft.Extensions.Logging.LoggerFactory).Assembly.GetName() }\n            };\n\n            var catalog = new AssemblyPluginCatalog(@\"..\\..\\..\\..\\..\\Assemblies\\bin\\JsonOld\\netstandard2.0\\JsonNetOld.dll\", options);\n            await catalog.Initialize();\n\n            var oldPlugin = catalog.Single();\n\n            dynamic oldPluginJsonResolver = Activator.CreateInstance(oldPlugin);\n            var oldPluginVersion = oldPluginJsonResolver.GetVersion();\n            var loggerVersion = oldPluginJsonResolver.GetLoggingVersion();\n\n            Assert.Equal(\"3.1.2.0\", loggerVersion);\n            Assert.Equal(\"9.0.0.0\", oldPluginVersion);\n        }\n\n        [Collection(nameof(NotThreadSafeResourceCollection))]\n        public class DefaultOptions : IDisposable\n        {\n            public DefaultOptions()\n            {\n                AssemblyPluginCatalogOptions.Defaults.PluginNameOptions = new PluginNameOptions()\n                {\n                    PluginNameGenerator = (nameOptions, type) => type.FullName + \"Modified\"\n                };\n            }\n\n            [Fact]\n            public async Task CanConfigureDefaultNamingOptions()\n            {\n                var catalog = new AssemblyPluginCatalog(@\"..\\..\\..\\..\\..\\Assemblies\\bin\\netstandard2.0\\TestAssembly1.dll\");\n\n                await catalog.Initialize();\n\n                var allPlugins = catalog.GetPlugins();\n\n                foreach (var plugin in allPlugins)\n                {\n                    Assert.EndsWith(\"Modified\", plugin.Name);\n                }\n            }\n\n            [Fact]\n            public async Task CanOverrideDefaultNamingOptions()\n            {\n                var options = new AssemblyPluginCatalogOptions()\n                {\n                    PluginNameOptions = new PluginNameOptions() { PluginNameGenerator = (nameOptions, type) => type.FullName + \"Overridden\" }\n                };\n\n                var catalog = new AssemblyPluginCatalog(@\"..\\..\\..\\..\\..\\Assemblies\\bin\\netstandard2.0\\TestAssembly1.dll\");\n                var catalog2 = new AssemblyPluginCatalog(@\"..\\..\\..\\..\\..\\Assemblies\\bin\\netstandard2.0\\TestAssembly2.dll\", options);\n\n                await catalog.Initialize();\n                await catalog2.Initialize();\n\n                var catalog1Plugins = catalog.GetPlugins();\n\n                foreach (var plugin in catalog1Plugins)\n                {\n                    Assert.EndsWith(\"Modified\", plugin.Name);\n                }\n\n                var catalog2Plugins = catalog2.GetPlugins();\n\n                foreach (var plugin in catalog2Plugins)\n                {\n                    Assert.EndsWith(\"Overridden\", plugin.Name);\n                }\n            }\n\n            public void Dispose()\n            {\n                AssemblyPluginCatalogOptions.Defaults.PluginNameOptions = new PluginNameOptions();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "tests/unit/Weikio.PluginFramework.Tests/DefaultOptionsTests.cs",
    "content": "﻿using System;\nusing System.Threading.Tasks;\nusing Weikio.PluginFramework.Abstractions;\nusing Weikio.PluginFramework.Catalogs;\nusing Weikio.PluginFramework.Context;\nusing Weikio.PluginFramework.TypeFinding;\nusing Xunit;\n\nnamespace Weikio.PluginFramework.Tests\n{\n    public class DefaultOptionsTests\n    {\n        [Fact]\n        public async Task CanConfigureDefaultOptions()\n        {\n            // Make sure that the referenced version of JSON.NET is loaded into memory\n            var json = Newtonsoft.Json.JsonConvert.SerializeObject(1);\n            PluginLoadContextOptions.Defaults.UseHostApplicationAssemblies = UseHostApplicationAssembliesEnum.Always;\n\n            Action<TypeFinderCriteriaBuilder> configureFinder = configure =>\n            {\n                configure.HasName(\"*JsonResolver\");\n            };\n            \n            var assemblyPluginCatalog = new AssemblyPluginCatalog(@\"..\\..\\..\\..\\..\\Assemblies\\bin\\JsonNew\\netstandard2.0\\JsonNetNew.dll\", configureFinder);\n            var folderPluginCatalog = new FolderPluginCatalog(@\"..\\..\\..\\..\\..\\Assemblies\\bin\\JsonOld\\netstandard2.0\", configureFinder);\n            \n            await assemblyPluginCatalog.Initialize();\n            await folderPluginCatalog.Initialize();\n            \n            var newPlugin = assemblyPluginCatalog.Single();\n            var oldPlugin = folderPluginCatalog.Single();\n            \n            dynamic newPluginJsonResolver = Activator.CreateInstance(newPlugin);\n            var newPluginVersion = newPluginJsonResolver.GetVersion();\n            \n            dynamic oldPluginJsonResolver = Activator.CreateInstance(oldPlugin);\n            var oldPluginVersion = oldPluginJsonResolver.GetVersion();\n            \n            Assert.Equal(\"12.0.0.0\", newPluginVersion);\n            Assert.Equal(\"12.0.0.0\", oldPluginVersion);\n        }\n    }\n}\n"
  },
  {
    "path": "tests/unit/Weikio.PluginFramework.Tests/DelegateCatalogTests.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing System.Threading.Tasks;\nusing Weikio.PluginFramework.Abstractions;\nusing Weikio.PluginFramework.Catalogs.Delegates;\nusing Xunit;\nusing Xunit.Abstractions;\n\nnamespace Weikio.PluginFramework.Tests\n{\n    public class DelegateCatalogTests\n    {\n        private readonly ITestOutputHelper _testOutputHelper;\n\n        public DelegateCatalogTests(ITestOutputHelper testOutputHelper)\n        {\n            _testOutputHelper = testOutputHelper;\n        }\n\n        [Fact]\n        public async Task CanInitialize()\n        {\n            var catalog = new DelegatePluginCatalog(new Action(() =>\n            {\n                _testOutputHelper.WriteLine(\"Hello from test\");\n            }));\n\n            await catalog.Initialize();\n\n            var allPlugins = catalog.GetPlugins();\n\n            Assert.NotEmpty(allPlugins);\n        }\n\n        [Fact]\n        public async Task CanInitializeFunc()\n        {\n            var catalog = new DelegatePluginCatalog(new Func<int, bool>(i => true));\n\n            await catalog.Initialize();\n\n            var allPlugins = catalog.GetPlugins();\n\n            Assert.NotEmpty(allPlugins);\n        }\n\n        [Fact]\n        public async Task CanInitializeAsyncAction()\n        {\n            var catalog = new DelegatePluginCatalog(new Action<int>(async i =>\n            {\n                await Task.Delay(TimeSpan.FromMilliseconds(100));\n                _testOutputHelper.WriteLine(\"Hello from test\");\n            }));\n\n            await catalog.Initialize();\n\n            var allPlugins = catalog.GetPlugins();\n\n            Assert.NotEmpty(allPlugins);\n        }\n\n        [Fact]\n        public async Task CanInitializeAsyncFunc()\n        {\n            var catalog = new DelegatePluginCatalog(new Func<int, Task<bool>>(async i =>\n            {\n                await Task.Delay(TimeSpan.FromMilliseconds(100));\n                _testOutputHelper.WriteLine(\"Hello from test\");\n\n                return true;\n            }));\n\n            await catalog.Initialize();\n\n            var allPlugins = catalog.GetPlugins();\n\n            Assert.NotEmpty(allPlugins);\n        }\n\n        [Fact]\n        public async Task ByDefaultNoProperties()\n        {\n            var catalog = new DelegatePluginCatalog(new Func<int, Task<bool>>(async i =>\n            {\n                await Task.Delay(TimeSpan.FromMilliseconds(100));\n                _testOutputHelper.WriteLine(\"Hello from test\");\n\n                return true;\n            }));\n\n            await catalog.Initialize();\n\n            var pluginType = catalog.Single().Type;\n            Assert.Empty(pluginType.GetProperties());\n        }\n        \n        [Fact]\n        public async Task ByDefaultRunMethod()\n        {\n            var catalog = new DelegatePluginCatalog(new Func<int, Task<bool>>(async i =>\n            {\n                await Task.Delay(TimeSpan.FromMilliseconds(100));\n                _testOutputHelper.WriteLine(\"Hello from test\");\n\n                return true;\n            }));\n\n            await catalog.Initialize();\n\n            var pluginType = catalog.Single().Type;\n            var methodInfos = pluginType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);\n            Assert.Single(methodInfos);\n            Assert.Equal(\"Run\", methodInfos.Single().Name);\n        }\n        \n        [Fact]\n        public async Task ByDefaultGeneratedNamespace()\n        {\n            var catalog = new DelegatePluginCatalog(new Func<int, Task<bool>>(async i =>\n            {\n                await Task.Delay(TimeSpan.FromMilliseconds(100));\n                _testOutputHelper.WriteLine(\"Hello from test\");\n\n                return true;\n            }));\n\n            await catalog.Initialize();\n\n            var pluginType = catalog.Single().Type;\n            Assert.Equal(\"GeneratedNamespace\", pluginType.Namespace);\n        }\n        \n        [Fact]\n        public async Task CanConfigurePluginNameFromConstructor()\n        {\n            var catalog = new DelegatePluginCatalog(new Func<int, Task<bool>>(async i =>\n            {\n                await Task.Delay(TimeSpan.FromMilliseconds(100));\n                _testOutputHelper.WriteLine(\"Hello from test\");\n\n                return true;\n            }), \"HelloPlugin\");\n\n            await catalog.Initialize();\n\n            Assert.Equal(\"HelloPlugin\", catalog.Single().Name);\n        }\n        \n        [Fact]\n        public async Task CanConfigureNamespace()\n        {\n            var catalog = new DelegatePluginCatalog(new Func<int, Task<bool>>(async i =>\n            {\n                await Task.Delay(TimeSpan.FromMilliseconds(100));\n                _testOutputHelper.WriteLine(\"Hello from test\");\n\n                return true;\n            }), new DelegatePluginCatalogOptions()\n            {\n                NamespaceName = \"HelloThereNs\"\n            });\n\n            await catalog.Initialize();\n\n            var pluginType = catalog.Single().Type;\n            Assert.Equal(\"HelloThereNs\", pluginType.Namespace);\n        }\n        \n        [Fact]\n        public async Task CanConfigureNamespaceUsinGenerator()\n        {\n            var catalog = new DelegatePluginCatalog(new Func<int, Task<bool>>(async i =>\n            {\n                await Task.Delay(TimeSpan.FromMilliseconds(100));\n                _testOutputHelper.WriteLine(\"Hello from test\");\n\n                return true;\n            }), new DelegatePluginCatalogOptions()\n                {\n                    NamespaceNameGenerator = options => \"GeneratorNS\"\n                }\n           );\n\n            await catalog.Initialize();\n\n            var pluginType = catalog.Single().Type;\n            Assert.Equal(\"GeneratorNS\", pluginType.Namespace);\n        }\n        \n        [Fact]\n        public async Task ByDefaultGeneratedTypeName()\n        {\n            var catalog = new DelegatePluginCatalog(new Func<int, Task<bool>>(async i =>\n            {\n                await Task.Delay(TimeSpan.FromMilliseconds(100));\n                _testOutputHelper.WriteLine(\"Hello from test\");\n\n                return true;\n            }));\n\n            await catalog.Initialize();\n\n            var pluginType = catalog.Single().Type;\n            Assert.Equal(\"GeneratedType\", pluginType.Name);\n        }\n        \n        [Fact]\n        public async Task CanConfigureTypename()\n        {\n            var catalog = new DelegatePluginCatalog(new Func<int, Task<bool>>(async i =>\n            {\n                await Task.Delay(TimeSpan.FromMilliseconds(100));\n                _testOutputHelper.WriteLine(\"Hello from test\");\n\n                return true;\n            }), new DelegatePluginCatalogOptions()\n            {\n                TypeName = \"HelloThereType\"\n            });\n\n            await catalog.Initialize();\n\n            var pluginType = catalog.Single().Type;\n            Assert.Equal(\"HelloThereType\", pluginType.Name);\n        }\n        \n        [Fact]\n        public async Task CanConfigureTypenameUsinGenerator()\n        {\n            var catalog = new DelegatePluginCatalog(new Func<int, Task<bool>>(async i =>\n                {\n                    await Task.Delay(TimeSpan.FromMilliseconds(100));\n                    _testOutputHelper.WriteLine(\"Hello from test\");\n\n                    return true;\n                }), new DelegatePluginCatalogOptions()\n                {\n                    TypeNameGenerator = options => \"GeneratorTypeName\"\n                }\n            );\n\n            await catalog.Initialize();\n\n            var pluginType = catalog.Single().Type;\n            Assert.Equal(\"GeneratorTypeName\", pluginType.Name);\n        }\n        \n        [Fact]\n        public async Task CanConfigureGeneratedMethodName()\n        {\n            var options = new DelegatePluginCatalogOptions()\n            {\n                MethodName = \"HelloMethod\"\n            };\n            \n            var catalog = new DelegatePluginCatalog(new Func<int, Task<bool>>(async i =>\n            {\n                await Task.Delay(TimeSpan.FromMilliseconds(100));\n                _testOutputHelper.WriteLine(\"Hello from test\");\n\n                return true;\n            }), options);\n\n            await catalog.Initialize();\n\n            var pluginType = catalog.Single().Type;\n            var methodInfos = pluginType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);\n            Assert.Equal(\"HelloMethod\", methodInfos.Single().Name);\n        }\n        \n        [Fact]\n        public async Task CanConfigureGeneratedMethodNameUsingGenerator()\n        {\n            var options = new DelegatePluginCatalogOptions()\n            {\n                MethodNameGenerator = catalogOptions => \"MethodGeneratorName\"\n            };\n            \n            var catalog = new DelegatePluginCatalog(new Func<int, Task<bool>>(async i =>\n            {\n                await Task.Delay(TimeSpan.FromMilliseconds(100));\n                _testOutputHelper.WriteLine(\"Hello from test\");\n\n                return true;\n            }), options);\n\n            await catalog.Initialize();\n\n            var pluginType = catalog.Single().Type;\n            var methodInfos = pluginType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);\n            Assert.Equal(\"MethodGeneratorName\", methodInfos.Single().Name);\n        }\n\n        [Fact]\n        public async Task ByDefaultNoConstructorParameters()\n        {\n            var catalog = new DelegatePluginCatalog(new Func<int, Task<bool>>(async i =>\n            {\n                await Task.Delay(TimeSpan.FromMilliseconds(100));\n                _testOutputHelper.WriteLine(\"Hello from test\");\n\n                return true;\n            }));\n\n            await catalog.Initialize();\n\n            var pluginType = catalog.Single().Type;\n            Assert.Single(pluginType.GetConstructors());\n\n            foreach (var constructorInfo in pluginType.GetConstructors())\n            {\n                Assert.Empty(constructorInfo.GetParameters());\n            }\n        }\n\n        [Fact]\n        public async Task CanConvertParameterToProperty()\n        {\n            var rules = new List<DelegateConversionRule>()\n            {\n                new DelegateConversionRule(info => info.ParameterType == typeof(int), nfo => new ParameterConversion() { ToPublicProperty = true }),\n            };\n\n            var catalog = new DelegatePluginCatalog(new Func<int, Task<bool>>(async i =>\n            {\n                await Task.Delay(TimeSpan.FromMilliseconds(100));\n                _testOutputHelper.WriteLine(\"Hello from test\");\n\n                return true;\n            }), rules);\n\n            await catalog.Initialize();\n\n            var pluginType = catalog.Single().Type;\n            Assert.Single(pluginType.GetProperties());\n        }\n        \n        [Fact]\n        public async Task CanConvertParameterToConstructorParameter()\n        {\n            var rules = new List<DelegateConversionRule>()\n            {\n                new DelegateConversionRule(info => info.ParameterType == typeof(int), nfo => new ParameterConversion() { ToConstructor = true })\n            };\n\n            var catalog = new DelegatePluginCatalog(new Func<int, Task<bool>>(async i =>\n            {\n                await Task.Delay(TimeSpan.FromMilliseconds(100));\n                _testOutputHelper.WriteLine(\"Hello from test\");\n\n                return true;\n            }), rules);\n\n            await catalog.Initialize();\n\n            var pluginType = catalog.Single().Type;\n            Assert.Single(pluginType.GetConstructors());\n            Assert.Single(pluginType.GetConstructors().Single().GetParameters());\n        }\n        \n        [Fact]\n        public async Task CanConvertMultipleParametersToConstructorAndPropertyParameters()\n        {\n            var rules = new List<DelegateConversionRule>()\n            {\n                new DelegateConversionRule(info => info.ParameterType == typeof(int), nfo => new ParameterConversion() { ToConstructor = true }),\n                new DelegateConversionRule(info => info.ParameterType == typeof(string), nfo => new ParameterConversion() { ToPublicProperty = true }),\n                new DelegateConversionRule(info => info.ParameterType == typeof(bool), nfo => new ParameterConversion() { ToPublicProperty = true }),\n                new DelegateConversionRule(info => info.ParameterType == typeof(decimal), nfo => new ParameterConversion() { ToConstructor = true }),\n            };\n\n            var catalog = new DelegatePluginCatalog(new Func<int, string, bool, decimal, char, bool>( (i, s, arg3, arg4, c) => \n            {\n                _testOutputHelper.WriteLine(\"Hello from test\");\n\n                return true;\n            }), rules);\n\n            await catalog.Initialize();\n\n            var pluginType = catalog.Single().Type;\n            Assert.Single(pluginType.GetConstructors());\n            Assert.Equal(2, pluginType.GetConstructors().Single().GetParameters().Length);\n            \n            Assert.Equal(2, pluginType.GetProperties().Length);\n\n            dynamic obj = Activator.CreateInstance(pluginType, new object[]{30, new decimal(22)});\n            obj.S = \"hello\";\n            obj.Arg3 = true;\n\n            var res = obj.Run('g');\n            Assert.True(res);\n        }\n        \n        [Fact]\n        public async Task CanSetPluginName()\n        {\n            var catalog = new DelegatePluginCatalog(new Action(() =>\n            {\n                _testOutputHelper.WriteLine(\"Hello from test\");\n            }), nameOptions: new PluginNameOptions()\n            {\n                PluginNameGenerator = (options, type) => \"CustomPlugin\"\n            });\n\n            await catalog.Initialize();\n\n            var plugin = catalog.Single();\n            Assert.Equal(\"CustomPlugin\", plugin.Name);\n        }\n        \n        [Fact]\n        public async Task CanSetPluginNameAndVersion()\n        {\n            var catalog = new DelegatePluginCatalog(new Action(() =>\n            {\n                _testOutputHelper.WriteLine(\"Hello from test\");\n            }), nameOptions: new PluginNameOptions()\n            {\n                PluginNameGenerator = (options, type) => \"CustomPlugin\",\n                PluginVersionGenerator = (options, type) => new Version(2, 3, 5)\n            });\n\n            await catalog.Initialize();\n\n            var plugin = catalog.Single();\n            Assert.Equal(\"CustomPlugin\", plugin.Name);\n            Assert.Equal(new Version(2, 3, 5), plugin.Version);\n        }\n        \n        [Fact]\n        public async Task CanConfigurePluginsHaveUniqueNames()\n        {\n            var randomGenerator = new Random(Guid.NewGuid().GetHashCode());\n            var nameOptions = new PluginNameOptions() { PluginNameGenerator = (options, type) => $\"CustomPlugin{randomGenerator.Next(int.MaxValue)}\" };\n            \n            var catalog = new DelegatePluginCatalog(new Action(() =>\n            {\n                _testOutputHelper.WriteLine(\"Hello from test\");\n            }), nameOptions: nameOptions);\n\n            var catalog2 = new DelegatePluginCatalog(new Action(() =>\n            {\n                _testOutputHelper.WriteLine(\"Hello from test\");\n            }), nameOptions: nameOptions);\n            \n            await catalog.Initialize();\n            await catalog2.Initialize();\n\n            var firstPlugin = catalog.Single();\n            var secondPlugin = catalog2.Single();\n            \n            Assert.NotEqual(firstPlugin.Name, secondPlugin.Name);\n        } \n    }\n}\n"
  },
  {
    "path": "tests/unit/Weikio.PluginFramework.Tests/FolderCatalogTests.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Reflection;\nusing System.Threading.Tasks;\nusing Weikio.PluginFramework.Abstractions;\nusing Weikio.PluginFramework.Catalogs;\nusing Weikio.PluginFramework.Context;\nusing Weikio.PluginFramework.TypeFinding;\nusing Xunit;\n\nnamespace Weikio.PluginFramework.Tests\n{\n    public class FolderCatalogTests\n    {\n        private const string _pluginFolder = @\"..\\..\\..\\..\\..\\Assemblies\\bin\\netstandard2.0\";\n\n        [Fact]\n        public async Task CanInitialize()\n        {\n            var catalog = new FolderPluginCatalog(_pluginFolder);\n            await catalog.Initialize();\n\n            var plugins = catalog.GetPlugins();\n\n            Assert.NotEmpty(plugins);\n        }\n\n        [Fact]\n        public async Task CanInitializeWithCriteria()\n        {\n            var catalog = new FolderPluginCatalog(_pluginFolder, configure =>\n            {\n                configure.HasName(\"*Plugin\");\n            });\n\n            await catalog.Initialize();\n\n            var pluginCount = catalog.GetPlugins().Count;\n\n            Assert.Equal(2, pluginCount);\n        }\n\n        [Fact]\n        public async Task CanUseFolderOptions()\n        {\n            var options = new FolderPluginCatalogOptions\n            {\n                TypeFinderOptions = new TypeFinderOptions()\n                {\n                    TypeFinderCriterias = new List<TypeFinderCriteria>()\n                    {\n                        TypeFinderCriteriaBuilder\n                            .Create()\n                            .HasName(\"SecondPlugin\")\n                            .Tag(\"MyPlugin\"),\n                    }\n                }\n            };\n\n            var catalog = new FolderPluginCatalog(_pluginFolder, options);\n\n            await catalog.Initialize();\n\n            var pluginCount = catalog.GetPlugins().Count;\n\n            Assert.Equal(1, pluginCount);\n            Assert.Equal(\"SecondPlugin\", catalog.Single().Type.Name);\n        }\n\n        [Fact]\n        public async Task FolderOptionsAreUsedToLimitLoadedAssemblies()\n        {\n            var options = new FolderPluginCatalogOptions\n            {\n                TypeFinderOptions = new TypeFinderOptions()\n                {\n                    TypeFinderCriterias = new List<TypeFinderCriteria>()\n                    {\n                        TypeFinderCriteriaBuilder\n                            .Create()\n                            .HasName(\"SecondPlugin\")\n                            .Tag(\"MyPlugin\"),\n                    }\n                }\n            };\n\n            var catalog = new FolderPluginCatalog(_pluginFolder, options);\n\n            await catalog.Initialize();\n\n            var field = catalog.GetType().GetField(\"_catalogs\", BindingFlags.Instance | BindingFlags.NonPublic);\n            // ReSharper disable once PossibleNullReferenceException\n            var loadedAssemblies = (List<AssemblyPluginCatalog>) field.GetValue(catalog);\n\n            // ReSharper disable once AssignNullToNotNullAttribute\n            Assert.Single(loadedAssemblies);\n        }\n\n        [Fact]\n        public async Task CanConfigureNamingOptions()\n        {\n            var options = new FolderPluginCatalogOptions()\n            {\n                PluginNameOptions = new PluginNameOptions() { PluginNameGenerator = (nameOptions, type) => type.FullName + \"Modified\" }\n            };\n\n            var catalog = new FolderPluginCatalog(_pluginFolder, options);\n            await catalog.Initialize();\n\n            var plugins = catalog.GetPlugins();\n\n            foreach (var plugin in plugins)\n            {\n                Assert.EndsWith(\"Modified\", plugin.Name);\n            }\n        }\n\n        [Fact]\n        public async Task CanUseReferencedDependencies()\n        {\n            PluginLoadContextOptions.Defaults.UseHostApplicationAssemblies = UseHostApplicationAssembliesEnum.Never;\n\n            Action<TypeFinderCriteriaBuilder> configureFinder = configure =>\n            {\n                configure.HasName(\"*JsonResolver\");\n            };\n\n            var folder1Catalog = new FolderPluginCatalog(@\"..\\..\\..\\..\\..\\Assemblies\\bin\\JsonNew\\netstandard2.0\", configureFinder);\n            var folder2Catalog = new FolderPluginCatalog(@\"..\\..\\..\\..\\..\\Assemblies\\bin\\JsonOld\\netstandard2.0\", configureFinder);\n\n            await folder1Catalog.Initialize();\n            await folder2Catalog.Initialize();\n\n            var newPlugin = folder1Catalog.Single();\n            var oldPlugin = folder2Catalog.Single();\n\n            dynamic newPluginJsonResolver = Activator.CreateInstance(newPlugin);\n            var newPluginVersion = newPluginJsonResolver.GetVersion();\n\n            dynamic oldPluginJsonResolver = Activator.CreateInstance(oldPlugin);\n            var oldPluginVersion = oldPluginJsonResolver.GetVersion();\n\n            Assert.Equal(\"10.0.0.0\", newPluginVersion);\n            Assert.Equal(\"9.0.0.0\", oldPluginVersion);\n        }\n\n        [Fact]\n        public async Task CanUseSelectedHoststDependencies()\n        {\n            // Make sure that the referenced version of JSON.NET is loaded into memory\n            var json = Newtonsoft.Json.JsonConvert.SerializeObject(1);\n\n            // Make sure that the referenced version of Microsoft.Extensions.Logging is loaded into memory\n            var logging = new Microsoft.Extensions.Logging.LoggerFactory();\n\n            var options = new FolderPluginCatalogOptions\n            {\n                TypeFinderCriteria = new TypeFinderCriteria() { Name = \"*JsonResolver\" },\n                PluginLoadContextOptions = new PluginLoadContextOptions()\n                {\n                    UseHostApplicationAssemblies = UseHostApplicationAssembliesEnum.Selected,\n                    HostApplicationAssemblies = new List<AssemblyName>() { typeof(Microsoft.Extensions.Logging.LoggerFactory).Assembly.GetName() }\n                }\n            };\n\n            var catalog = new FolderPluginCatalog(@\"..\\..\\..\\..\\..\\Assemblies\\bin\\JsonOld\\netstandard2.0\", options);\n            await catalog.Initialize();\n\n            var oldPlugin = catalog.Single();\n\n            dynamic oldPluginJsonResolver = Activator.CreateInstance(oldPlugin);\n            var oldPluginVersion = oldPluginJsonResolver.GetVersion();\n            var loggerVersion = oldPluginJsonResolver.GetLoggingVersion();\n\n            Assert.Equal(\"3.1.2.0\", loggerVersion);\n            Assert.Equal(\"9.0.0.0\", oldPluginVersion);\n        }\n\n        [Collection(nameof(NotThreadSafeResourceCollection))]\n        public class DefaultOptions : IDisposable\n        {\n            public DefaultOptions()\n            {\n                FolderPluginCatalogOptions.Defaults.PluginNameOptions = new PluginNameOptions()\n                {\n                    PluginNameGenerator = (nameOptions, type) => type.FullName + \"Modified\"\n                };\n            }\n\n            [Fact]\n            public async Task CanConfigureDefaultNamingOptions()\n            {\n                var catalog = new FolderPluginCatalog(_pluginFolder);\n                await catalog.Initialize();\n\n                var plugins = catalog.GetPlugins();\n\n                foreach (var plugin in plugins)\n                {\n                    Assert.EndsWith(\"Modified\", plugin.Name);\n                }\n            }\n\n            [Fact]\n            public async Task DefaultAssemblyNamingOptionsDoesntAffectFolderCatalogs()\n            {\n                AssemblyPluginCatalogOptions.Defaults.PluginNameOptions = new PluginNameOptions()\n                {\n                    PluginNameGenerator = (nameOptions, type) => type.FullName + \"ModifiedAssembly\"\n                };\n\n                var catalog = new FolderPluginCatalog(_pluginFolder);\n                await catalog.Initialize();\n\n                var plugins = catalog.GetPlugins();\n\n                foreach (var plugin in plugins)\n                {\n                    Assert.False(plugin.Name.EndsWith(\"ModifiedAssembly\"));\n                }\n            }\n\n            public void Dispose()\n            {\n                AssemblyPluginCatalogOptions.Defaults.PluginNameOptions = new PluginNameOptions();\n                FolderPluginCatalogOptions.Defaults.PluginNameOptions = new PluginNameOptions();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "tests/unit/Weikio.PluginFramework.Tests/NotThreadSafeResourceCollection.cs",
    "content": "﻿using Xunit;\n\nnamespace Weikio.PluginFramework.Tests\n{\n    [CollectionDefinition(nameof(NotThreadSafeResourceCollection), DisableParallelization = true)]\n    public class NotThreadSafeResourceCollection\n    {\n    }\n}\n"
  },
  {
    "path": "tests/unit/Weikio.PluginFramework.Tests/Plugins/AbstractPluginWithAttribute.cs",
    "content": "﻿namespace Weikio.PluginFramework.Tests.Plugins\n{\n    [MyPlugin]\n    public abstract class AbstractPluginWithAttribute\n    {\n        \n    }\n}\n"
  },
  {
    "path": "tests/unit/Weikio.PluginFramework.Tests/Plugins/AnotherPluginWithAttribute.cs",
    "content": "﻿namespace Weikio.PluginFramework.Tests.Plugins\n{\n    [MyPlugin]\n    public class AnotherPluginWithAttribute\n    {\n        \n    }\n}"
  },
  {
    "path": "tests/unit/Weikio.PluginFramework.Tests/Plugins/MyPluginAttribute.cs",
    "content": "﻿using System;\n\nnamespace Weikio.PluginFramework.Tests.Plugins\n{\n    [AttributeUsage(AttributeTargets.Class)]\n    public class MyPluginAttribute : Attribute\n    {\n        \n    }\n}\n"
  },
  {
    "path": "tests/unit/Weikio.PluginFramework.Tests/Plugins/PluginWithAttribute.cs",
    "content": "﻿namespace Weikio.PluginFramework.Tests.Plugins\n{\n    [MyPlugin]\n    public class PluginWithAttribute\n    {\n        \n    }\n}"
  },
  {
    "path": "tests/unit/Weikio.PluginFramework.Tests/Plugins/TypePlugin.cs",
    "content": "﻿namespace Weikio.PluginFramework.Tests.Plugins\n{\n    public class TypePlugin\n    {\n    }\n}\n"
  },
  {
    "path": "tests/unit/Weikio.PluginFramework.Tests/Plugins/TypePluginWithName.cs",
    "content": "﻿using System.ComponentModel;\n\nnamespace Weikio.PluginFramework.Tests.Plugins\n{\n    [DisplayName(\"MyCustomName\")]\n    public class TypePluginWithName\n    {\n    }\n}\n"
  },
  {
    "path": "tests/unit/Weikio.PluginFramework.Tests/TagTests.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Weikio.PluginFramework.Abstractions;\nusing Weikio.PluginFramework.Catalogs;\nusing Weikio.PluginFramework.Catalogs.Delegates;\nusing Weikio.PluginFramework.Tests.Plugins;\nusing Weikio.PluginFramework.TypeFinding;\nusing Xunit;\n\nnamespace Weikio.PluginFramework.Tests\n{\n    public class TagTests\n    {\n        [Fact]\n        public async Task CanTagTypePlugin()\n        {\n            var catalog = new TypePluginCatalog(typeof(TypePlugin),\n                new TypePluginCatalogOptions()\n                {\n                    TypeFinderOptions = new TypeFinderOptions()\n                    {\n                        TypeFinderCriterias = new List<TypeFinderCriteria>()\n                        {\n                            TypeFinderCriteriaBuilder.Create().Tag(\"MyTag_1\"),\n                            TypeFinderCriteriaBuilder.Create().Tag(\"AnotherTag\")\n                        }\n                    }\n                });\n\n            await catalog.Initialize();\n\n            var plugin = catalog.Single();\n            Assert.Equal(\"MyTag_1\", plugin.Tag);\n        }\n\n        [Fact]\n        public async Task CanTagAssemblyPlugin()\n        {\n            var catalog = new AssemblyPluginCatalog(@\"..\\..\\..\\..\\..\\Assemblies\\bin\\netstandard2.0\\TestAssembly1.dll\", null,\n                taggedFilters: new Dictionary<string, Predicate<Type>>() { { \"CustomTag\", type => true } });\n\n            await catalog.Initialize();\n\n            var allPlugins = catalog.GetPlugins();\n\n            foreach (var plugin in allPlugins)\n            {\n                Assert.Equal(\"CustomTag\", plugin.Tag);\n            }\n        }\n\n        [Fact]\n        public async Task CanTagAssemblyPluginUsingBuilder()\n        {\n            var catalog = new AssemblyPluginCatalog(typeof(TypePlugin).Assembly, builder =>\n            {\n                builder.AssignableTo(typeof(TypePlugin))\n                    .Tag(\"operator\");\n            });\n            \n            await catalog.Initialize();\n            \n            var allPlugins = catalog.GetPlugins();\n\n            foreach (var plugin in allPlugins)\n            {\n                Assert.Equal(\"operator\", plugin.Tag);\n            }\n        }\n        \n        [Fact]\n        public async Task CanTagFolderPlugin()\n        {\n            var _pluginFolder = @\"..\\..\\..\\..\\..\\Assemblies\\bin\\netstandard2.0\";\n            var catalog = new FolderPluginCatalog(_pluginFolder, builder =>\n            {\n                builder.Tag(\"test_folder_tag\");\n            });\n            \n            await catalog.Initialize();\n            \n            var allPlugins = catalog.GetPlugins();\n\n            foreach (var plugin in allPlugins)\n            {\n                Assert.Equal(\"test_folder_tag\", plugin.Tag);\n            }\n        }\n        \n        [Fact]\n        public async Task CanTagDelegate()\n        {\n            var catalog = new DelegatePluginCatalog(new Func<int, bool>(i => true), options: new DelegatePluginCatalogOptions()\n            {\n                Tags = new List<string>(){\"CustomTagDelegate\"}\n            });\n\n            await catalog.Initialize();\n\n            var allPlugins = catalog.GetPlugins();\n\n            foreach (var plugin in allPlugins)\n            {\n                Assert.Equal(\"CustomTagDelegate\", plugin.Tag);\n            }\n        }\n                \n        [Fact]\n        public async Task PluginCanContainManyTags()\n        {\n            var catalog = new TypePluginCatalog(typeof(TypePlugin),\n                new TypePluginCatalogOptions()\n                {\n                    TypeFinderOptions = new TypeFinderOptions()\n                    {\n                        TypeFinderCriterias = new List<TypeFinderCriteria>()\n                        {\n                            TypeFinderCriteriaBuilder.Create().Tag(\"MyTag_1\"),\n                            TypeFinderCriteriaBuilder.Create().Tag(\"AnotherTag\")\n                        }\n                    }\n                });\n\n            await catalog.Initialize();\n\n            var plugin = catalog.Single();\n            \n            var coll = new List<string>(){\"MyTag_1\", \"AnotherTag\"};\n            Assert.Equal(coll, plugin.Tags);\n        }\n        \n        [Collection(nameof(NotThreadSafeResourceCollection))]\n        public class DefaultOptions : IDisposable\n        {\n            public DefaultOptions()\n            {\n                TypeFinderOptions.Defaults.TypeFinderCriterias.Add(TypeFinderCriteriaBuilder.Create().Tag(\"CustomTag\"));\n                TypeFinderOptions.Defaults.TypeFinderCriterias.Add(TypeFinderCriteriaBuilder.Create().HasName(nameof(TypePlugin)).Tag(\"MyTag_1\"));\n                TypeFinderOptions.Defaults.TypeFinderCriterias.Add(TypeFinderCriteriaBuilder.Create().HasName(\"*Json*\").Tag(\"MyTag_1\"));\n            }\n\n            [Fact]\n            public async Task CanTagUsingDefaultOptions()\n            {\n                var assemblyPluginCatalog = new AssemblyPluginCatalog(@\"..\\..\\..\\..\\..\\Assemblies\\bin\\netstandard2.0\\TestAssembly1.dll\");\n                var typePluginCatalog = new TypePluginCatalog(typeof(TypePlugin));\n\n                var compositeCatalog = new CompositePluginCatalog(assemblyPluginCatalog, typePluginCatalog);\n\n                await compositeCatalog.Initialize();\n\n                var customTaggedPlugins = compositeCatalog.GetByTag(\"CustomTag\");\n                Assert.Equal(2, customTaggedPlugins.Count);\n\n                var myTaggedPlugins = compositeCatalog.GetByTag(\"MyTag_1\");\n                Assert.Single(myTaggedPlugins);\n                \n                TypeFinderOptions.Defaults.TypeFinderCriterias.Clear();\n            }\n            \n            [Fact]\n            public async Task TypeCatalogCanTagUsingDefaultOptions()\n            {\n                var typePluginCatalog = new TypePluginCatalog(typeof(TypePlugin));\n\n                await typePluginCatalog.Initialize();\n\n                var myTaggedPlugins = typePluginCatalog.GetByTag(\"MyTag_1\");\n                Assert.Single(myTaggedPlugins);\n                \n                TypeFinderOptions.Defaults.TypeFinderCriterias.Clear();\n            }\n\n            [Fact]\n            public async Task DefaultTagsWithFolderCatalogTypeShouldNotDuplicatePlugins()\n            {\n                var catalog = new FolderPluginCatalog(@\"..\\..\\..\\..\\..\\Assemblies\\bin\\JsonNew\\netstandard2.0\");\n                await catalog.Initialize();\n\n                Assert.Single(catalog.GetPlugins());\n                var plugin = catalog.Get();\n                \n                Assert.Equal(2, plugin.Tags.Count);\n                TypeFinderOptions.Defaults.TypeFinderCriterias.Clear();\n            }\n            \n            [Fact]\n            public async Task DefaultTagsWithAssemblyCatalogTypeShouldNotDuplicatePlugins()\n            {\n                var catalog = new AssemblyPluginCatalog(@\"..\\..\\..\\..\\..\\Assemblies\\bin\\JsonNew\\netstandard2.0\\JsonNetNew.dll\");\n                await catalog.Initialize();\n\n                Assert.Single(catalog.GetPlugins());\n                var plugin = catalog.Get();\n                \n                Assert.Equal(2, plugin.Tags.Count);\n                TypeFinderOptions.Defaults.TypeFinderCriterias.Clear();\n            }\n            \n            public void Dispose()\n            {\n                TypeFinderOptions.Defaults.TypeFinderCriterias.Clear();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "tests/unit/Weikio.PluginFramework.Tests/TypeFinderTests.cs",
    "content": "﻿using System.Threading.Tasks;\nusing Weikio.PluginFramework.Catalogs;\nusing Weikio.PluginFramework.Tests.Plugins;\nusing Xunit;\n\nnamespace Weikio.PluginFramework.Tests\n{\n    public class TypeFinderTests\n    {\n        [Fact]\n        public async Task CanGetPluginsByAttribute()\n        {\n            var catalog = new AssemblyPluginCatalog(typeof(TypeFinderTests).Assembly, configure =>\n            {\n                configure.HasAttribute(typeof(MyPluginAttribute));\n            });\n\n            await catalog.Initialize();\n            \n            Assert.Equal(2, catalog.GetPlugins().Count);\n        }\n        \n        [Fact]\n        public async Task CanGetPluginsByMultipleCriteria()\n        {\n            var catalog = new AssemblyPluginCatalog(typeof(TypeFinderTests).Assembly, configure =>\n            {\n                configure.HasAttribute(typeof(MyPluginAttribute))\n                    .IsAbstract(true)\n                    .HasName(nameof(AbstractPluginWithAttribute));\n            });\n\n            await catalog.Initialize();\n            \n            Assert.Single(catalog.GetPlugins());\n        }\n    }\n}\n"
  },
  {
    "path": "tests/unit/Weikio.PluginFramework.Tests/TypePluginCatalogTests.cs",
    "content": "﻿using System.Threading.Tasks;\nusing Weikio.PluginFramework.Abstractions;\nusing Weikio.PluginFramework.Catalogs;\nusing Weikio.PluginFramework.Tests.Plugins;\nusing Xunit;\n\nnamespace Weikio.PluginFramework.Tests\n{\n    public class TypePluginCatalogTests\n    {\n        [Fact]\n        public async Task CanInitialize()\n        {\n            var catalog = new TypePluginCatalog(typeof(TypePlugin));\n            await catalog.Initialize();\n\n            var plugins = catalog.GetPlugins();\n            Assert.Single(plugins);\n        }\n\n        [Fact]\n        public async Task NameIsTypeFullName()\n        {\n            var catalog = new TypePluginCatalog(typeof(TypePlugin));\n            await catalog.Initialize();\n\n            var thePlugin = catalog.Single();\n        \n            Assert.Equal(\"Weikio.PluginFramework.Tests.Plugins.TypePlugin\", thePlugin.Name);\n        }\n        \n        [Fact]\n        public async Task CanConfigureNameResolver()\n        {\n            var catalog = new TypePluginCatalog(typeof(TypePlugin), configure =>\n            {\n                configure.PluginNameGenerator = (opt, type) => \"HelloOptions\";\n            });\n        \n            await catalog.Initialize();\n\n            var thePlugin = catalog.Single();\n        \n            Assert.Equal(\"HelloOptions\", thePlugin.Name);\n        }\n        \n        \n        [Fact]\n        public async Task CanSetNameByAttribute()\n        {\n            var catalog = new TypePluginCatalog(typeof(TypePluginWithName));\n            await catalog.Initialize();\n\n            var thePlugin = catalog.Single();\n        \n            Assert.Equal(\"MyCustomName\", thePlugin.Name);\n        }\n        \n        \n        [Fact]\n        public async Task CanConfigureNamingOptions()\n        {\n            var options = new TypePluginCatalogOptions()\n            {\n                PluginNameOptions = new PluginNameOptions() { PluginNameGenerator = (opt, type) => \"HelloOptions\" }\n            };\n            \n            var catalog = new TypePluginCatalog(typeof(TypePlugin), options);\n        \n            await catalog.Initialize();\n\n            var thePlugin = catalog.Single();\n        \n            Assert.Equal(\"HelloOptions\", thePlugin.Name);\n        }\n        \n        [Fact]\n        public async Task CanConfigureDefaultNamingOptions()\n        {\n            TypePluginCatalogOptions.Defaults.PluginNameOptions = new PluginNameOptions()\n            {\n                PluginNameGenerator = (nameOptions, type) => \"HelloOptions\"\n            };\n            \n            var catalog = new TypePluginCatalog(typeof(TypePlugin));\n        \n            await catalog.Initialize();\n\n            var thePlugin = catalog.Single();\n        \n            Assert.Equal(\"HelloOptions\", thePlugin.Name);\n        }\n        \n        [Fact]\n        public async Task CanOverrideDefaultNamingOptions()\n        {\n            var options = new TypePluginCatalogOptions()\n            {\n                PluginNameOptions = new PluginNameOptions() { PluginNameGenerator = (opt, type) => \"Overridden\" }\n            };\n            \n            TypePluginCatalogOptions.Defaults.PluginNameOptions = new PluginNameOptions()\n            {\n                PluginNameGenerator = (nameOptions, type) => \"HelloOptions\"\n            };\n            \n            var catalog = new TypePluginCatalog(typeof(TypePlugin));\n            var catalog2 = new TypePluginCatalog(typeof(TypePlugin), options);\n\n            await catalog.Initialize();\n            await catalog2.Initialize();\n\n            var thePlugin = catalog.Single();\n            Assert.Equal(\"HelloOptions\", thePlugin.Name);\n\n            var anotherPlugin = catalog2.Single();\n            Assert.Equal(\"Overridden\", anotherPlugin.Name);\n        }\n    }\n}\n"
  },
  {
    "path": "tests/unit/Weikio.PluginFramework.Tests/Weikio.PluginFramework.Tests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>netcoreapp3.1</TargetFramework>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"16.3.*\" />\n    <PackageReference Include=\"xunit\" Version=\"2.4.*\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"2.*\" />\n    <PackageReference Include=\"Newtonsoft.Json\" Version=\"12.0.2\" />\n    <PackageReference Include=\"Microsoft.Extensions.Logging\" Version=\"3.1.2\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\src\\Weikio.PluginFramework\\Weikio.PluginFramework.csproj\" />\n    <ProjectReference Include=\"..\\..\\Assemblies\\TestIntefaces\\TestIntefaces.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  }
]