{"id":18319893,"url":"https://github.com/bitwalker/pluginhost","last_synced_at":"2025-04-05T22:31:41.423Z","repository":{"id":23973959,"uuid":"27356657","full_name":"bitwalker/pluginhost","owner":"bitwalker","description":"An example C# application which provides runtime extensibility via plugins","archived":false,"fork":false,"pushed_at":"2016-11-22T19:14:34.000Z","size":100,"stargazers_count":31,"open_issues_count":0,"forks_count":3,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-03-21T13:12:38.960Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bitwalker.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-12-01T01:09:43.000Z","updated_at":"2021-10-28T10:56:24.000Z","dependencies_parsed_at":"2022-08-22T06:50:56.905Z","dependency_job_id":null,"html_url":"https://github.com/bitwalker/pluginhost","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitwalker%2Fpluginhost","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitwalker%2Fpluginhost/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitwalker%2Fpluginhost/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitwalker%2Fpluginhost/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bitwalker","download_url":"https://codeload.github.com/bitwalker/pluginhost/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247411237,"owners_count":20934650,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-05T18:14:36.163Z","updated_at":"2025-04-05T22:31:40.986Z","avatar_url":"https://github.com/bitwalker.png","language":"C#","readme":"# PluginHost\n\nThis project is a proof-of-concept for an application which provides\nruntime extensibility via plugins. This application is written in C#,\nusing .NET v4.5, and is composed of the following components:\n\n## Usage\n\nSimply clone the repository, open in Visual Studio and build the solution. Make sure\nPluginHost is set as the startup project, and run the debugger. From here you can type\n`help` and press Enter to execute the command and view a list of available commands.\n\nBy default, PluginHost has no tasks bundled, so we need to add one. I've added the\nPluginHost.Heartbeat project for this purpose. To test the runtime detection and execution\nof tasks, perform the following steps while PluginHost is running:\n\n- In the console, type `start` followed by Enter\n- Go to the PluginHost.Hearbeat project, locate the `bin\\Debug` folder, and copy the\n  `PluginHost.Hearbeat.dll` file to `PluginHost\\bin\\Debug`.\n\nYou should see logging messages in the console reflecting the detection of the new assembly\nand associated tasks, and start up messages for the Heartbeat task. After a few seconds you\nshould start seeing the heartbeat message logged to the console.\n\nTo exit, just type `exit` and press Enter.\n\n## Components\n\n### PluginHost\n\nThis project contains the core application logic for the command shell,\ndependency management, configuration, and task management. It also contains\nthe default set of shell commands, and the default ILogger implementations.\n\n### PluginHost.Interface\n\nThis project contains shared interfaces necessary for plugins to extend\nthe command shell, reference and add logging modules, add new tasks, and\nreference the parent application's configuration.\n\n### PluginHost.Extensions\n\nThis project contains shared common code extensions: a generic comparer\nimplementation, extension methods for collections, enums, streams, numbers,\nstrings, and datetime/timespans.\n\n### PluginHost.Heartbeat\n\nAn example task which acts as a simple heartbeat by logging an event every\n5 seconds.\n\n## Dependency Injection\n\nInjection is handled via the Managed Extensibility Framework (MEF). The\nconfiguration for how dependencies are imported/exported is defined via\nconvention in the PluginHost.Dependencies.DependencyInjector class. It\nworks like so:\n\n- On application startup, MEF loads a catalog of exported dependencies,\nbased on the configured conventions, by loading types from the PluginHost\nassembly, as well as any assemblies in the `plugins` path as defined in\n`App.config`. \n- In addition to this behavior, it has been extended with a custom directory\nwatcher which monitors that plugin directory, and tells MEF to reload the\ncatalog when files are added or removed from that directory. An event is published\nwhich can be subscribed to in order to act on new/removed dependencies (this\nis done for implementations of ITask for example).\n- To import an instance of a dependency, calling one of the Resolve variations\non the `DependencyInjector` class will fetch the type information for the dependency,\nfind the constructor the the largest number of parameters, and attempt to fulfill the\nrequirements of that constructor based on available exports. In this way, dependencies\ncan be automatically injected into instances on creation.\n- If you have an instance of an object that is not tracked by MEF, but for which public\nproperties of exported types exist, you can inject those properties by using the `Inject`\nmethod of the `DependencyInjector` class.\n\n## Command Shell\n\nThe shell is a simple REPL-style interface, which provides a prompt, waits for\nuser input, and responds to that input by looking up commands which can handle the\ngiven input and executing that command.\n\nCommands all implement the IShellCommand interface, and expose two core methods,\n`CanExecute` and `Execute`. When user input is received by the shell, it is parsed\ninto command text and a list of arguments by the CommandParser, and then commands are\nresolved via MEF, and each one is asked whether it can handle the given input. If only a\nsingle command responds, it is executed immediately. If more than one command can handle\nthe input, the user is prompted to choose which command they wish to execute, and then the\ncommand is executed.\n\nSome default commands are provided directly in the PluginHost project: `exit`, `clear`,\n`start`, `tasks`, and `help`. New commands can be provided by extending `IShellCommand`,\nand adding the containing assembly to the plugins directory.\n\n## Tasks\n\nTasks all implement the `ITask` interface, and are loaded at startup via MEF. In addition,\nany tasks added via new assemblies in the plugins directory will be added during runtime,\nand automatically started if `TaskManager` is running.\n\nTasks can execute on a schedule (via `ScheduledTask`), in response to an event (via `ObserverTask`),\nor based on their own behavior entirely, as either one-off tasks, or with their own lifecycle management.\n\n## Logging\n\nLogging is exposed via the `ILogger` interface, and contains two default implementations, `ConsoleLogger`,\nand `EventLogLogger`, both of which do pretty much what you'd expect. You can add new loggers by creating\nan implementation of `ILogger`, and adding the containing assembly to the plugins directory. Right now no\nwork has yet been done on providing a single interface for writing to all loggers, you basically have to\nimport all of them and write to all of them, or choose one to log with and import just that one.\n\n## License\n\nMIT","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbitwalker%2Fpluginhost","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbitwalker%2Fpluginhost","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbitwalker%2Fpluginhost/lists"}