Code Monkey home page Code Monkey logo

Comments (14)

natemcmaster avatar natemcmaster commented on July 30, 2024 3

My only concern if if a DLL is found in multiple plugin directories but of different versions...so I think it's best to try load the newest version when this occurs, but we'll see.

And that's why I made a design choice to keep plugins isolated by default. Assembly version fusion is a hard problem to solve correctly. If you want to see an implementation that handles all the edge cases, checkout the build-time solution of this in the MSBuild task called "ResolveAssemblyReferences". https://github.com/microsoft/msbuild/blob/master/documentation/wiki/ResolveAssemblyReference.md

from dotnetcoreplugins.

Sewer56 avatar Sewer56 commented on July 30, 2024 3

Oh snap, I missed this one.

I should have set this repository to watch since I do myself also make extensive use of this library in one of my projects.

Anyway, if anyone wants another example, my program Reloaded II (universal "Mod Loader" allowing arbitrary managed code injection in native processes), also exposes such a pattern whereby mods (plugins) can share types between each other.

Here is how I do it:

  1. A specific interface, IExports can be optionally implemented by plugins (mods) which, allows the plugins to declare which types should be shared with other plugins:

https://github.com/Reloaded-Project/Reloaded-II/blob/320f691df51ab12ece83035af54558937e79f324/Source/Reloaded.Mod.Interfaces/IExports.cs#L7-L14

  1. Before initializing any of the plugins, I load all exported types from plugins to be loaded into the current AssemblyLoadContext.

https://github.com/Reloaded-Project/Reloaded-II/blob/320f691df51ab12ece83035af54558937e79f324/Source/Reloaded.Mod.Loader/Mods/PluginManager.cs#L300-L306

  1. When I load each plugin (mod), I load the plugin with both others' and the plugin's own exports (loaded in the current AssemblyLoadContext in Step 2) as shared types.
    (I.e. The this will make the plugin use the type from the current ALC)

https://github.com/Reloaded-Project/Reloaded-II/blob/320f691df51ab12ece83035af54558937e79f324/Source/Reloaded.Mod.Loader/Mods/PluginManager.cs#L213

I would also advise adding some form of mechanism where a plugin can declare which plugins it can unify with (I use unique string IDs, "ModDependencies" and "OptionalDependencies") to prevent sharing unwanted types. With time you will notice, especially if you share extensively that you will need this. I have this implemented as you may have noticed above.

This should work fine so long as you try avoid exporting 3rd party libraries, if you do, you will probably face problems if two versions export different versions of a given third party library.

The docs of my implementation might also provide you with some ideas of what I found to be good practices: https://github.com/Reloaded-Project/Reloaded-II/blob/master/Docs/InterModCommunication.md#introduction

Sorry for being late to the party :P

from dotnetcoreplugins.

ShaneYu avatar ShaneYu commented on July 30, 2024

By the way, meant to say in the above post...your library is bloody brilliant and so handy. I was so simple to setup plugin loading as I currently have it. Just hope I can find a way around the above. πŸ˜„

from dotnetcoreplugins.

natemcmaster avatar natemcmaster commented on July 30, 2024

Thanks for giving this project a try! I hope it will be useful.

One of the deliberate design choices I made here is that plugins are isolated from each other. If you want to share information between plugins, you will need to create abstractions which the host application provides.

I wanted to make sure this was possible, so I wrote a sample and pushed it to the repo. Take a look and let me know if it answers your questions. https://github.com/natemcmaster/DotNetCorePlugins/tree/master/samples/dependency-injection

from dotnetcoreplugins.

ShaneYu avatar ShaneYu commented on July 30, 2024

Thank you very much for the reply, I totally get why you'd design it for islolated plugins.
I will take a look at the sample you've mentioned and give it a go, it's a shame though that you have to add the abstractions to the host always. πŸ‘

I wonder if it is possible to scan in all of the plugin directories for assemblies that are the same and then load the latest verion of the found assemblies into the host context and add to the shared types via interface or something? So that the host doesn't have to have a physical reference to the abstractions. It's mainly that I was wanting plugins to provide other functionality that the host doesn't that other plugins could then use etc.

Update:
Your example worked perfectly, so thank you ever so much.

Just as a test though, I had a go at scanning the plugin directories for DLLs that are found more than once, I then loaded those into the default assembly load context.
This worked an absolute treat and everything worked as expected, so I am going to continue playing with this approch for now and see what I can do with it.

My only concern if if a DLL is found in multiple plugin directories but of different versions...so I think it's best to try load the newest version when this occurs, but we'll see.

from dotnetcoreplugins.

Sewer56 avatar Sewer56 commented on July 30, 2024

Related to the post above.

I actually had a fork at one point where I implemented a feature to allow loading of shared types from an arbitrary ALC (as well as the default one).

The benefit of this would be that you could store each plugin's export in a separate ALC, making them unloadable. This is useful as you could you could move, delete and overwrite the shared DLLs at runtime (after unloading, as no handle is open/file isn't used).

Additional benefit is that multiple versions of same libraries could be shared by the application between plugins (i.e. not sharing exports via the default ALC allows for multiple versions of same library).

I don't remember quite why I never decided to implement this on my end (and nuked the commits), but if the either of you are interested, I'd be happy to re-implement this. This would be a very useful optional safety feature in this kind of plugin sharing scenario.

from dotnetcoreplugins.

ShaneYu avatar ShaneYu commented on July 30, 2024

Thanks very much @Sewer56, I will take a look at what you've done and see if it fits my needs. I am not, in this instance, in need of being able to unload and update DLL's on the fly, I am able to just restart the host service. I've not bothered with the IExport approach has you've done, thus far, but I am doing what @natemcmaster has done with the plugin configuration class.

They way I've currently got it working is to scan all of the plugin directories for their dependencies, figure out which ones are used more than once and then load them into the default/current ACL, if more than one version is found, the latest version is loaded. I've set the option in the plugin loading to prefer shared types as well. This seems to be working quite nicely and because I have a little control over the plugins being created and used for my application...I can make sure that as part of updatting a plugin that any dependency updates are done in other plugins also.

Also, being late to the party with good information like the above is better than not contibuting at all, so thanks very much πŸ˜„ πŸ˜„

from dotnetcoreplugins.

natemcmaster avatar natemcmaster commented on July 30, 2024

@ShaneYu: They way I've currently got it working is to scan all of the plugin directories for their dependencies, figure out which ones are used more than once and then load them into the default/current ACL, if more than one version is found, the latest version is loaded.

I think this is a good approach. It's what I would recommend in general for those who want to share types among plugins which are not present in the host. If you think this would be a generally useful API to have in this library, I think it would be worth adding. It's a fairly specific case, so it probably deserves documentation and a sample too.

@Sewer56: thanks for sharing details on Reloaded II. It looks like a nice framework for handling more complicated plugin compositions. With DotNetCorePlugins, I've chosen to keep the loader fairly simple. Along with your project, there are several others that people use to compose large applications together, such as System.Composition (MEF). Rather than re-invent, I'd rather provide integration and support for those composition frameworks. I'd be happy to add a sample to this repo showing how DotNetCorePlugins can be used with Reloaded II, or links in the docs, if you think it's useful.

from dotnetcoreplugins.

Sewer56 avatar Sewer56 commented on July 30, 2024

I'd be happy to add a sample to this repo showing how DotNetCorePlugins can be used with Reloaded II, or links in the docs, if you think it's useful.

No need in this case, no user of Reloaded would ever require to directly work with DotNetCorePlugins, in fact they couldn't, unless they were directly contributing to the loader code itself. In addition. Reloaded II's documentation is fairly complete and self contained for any developer who wishes to use it.

I believe you may have misunderstood what Reloaded II is. Reloaded II at the core is an application (plugin loader) of its own that can be used for extending existing native applications. It is a loader that loads arbitrary .NET Standard plugins into native applications, which may then use techniques such as hooking/detouring/trampolining to alter the behaviour of a given native application.

It also contains a plugin manager (WPF GUI), which controls which plugins should be loaded into which application among many other features. In other words, Reloaded II can best be described as a tool/standalone application to get .NET code running inside native applications.

I mostly use it personally to tamper with old games, as a hobby for my spare time.
You can do a lot with it in the hands of the right person.

(This is Sonic Heroes, a game from 2003 running in flawless widescreen at an 32:9 aspect ratio. Normally this game cannot run in anything else than 4:3 and any of the 4 hardcoded resolutions.)

Reloaded II Plugin

from dotnetcoreplugins.

natemcmaster avatar natemcmaster commented on July 30, 2024

Gotcha, thanks for the clarification.

from dotnetcoreplugins.

jzabroski avatar jzabroski commented on July 30, 2024

I think the paradigm @natemcmaster chose fits that of Visual Studio and similar "integrated development environments" or what I think of as "Application Shell" Architectural Style.

Application Shell Architectural Style is basically object capability model: Each plugin only has access to resources provided to it by a specific part of the shell. Some tools, like Visual Studio, don't tunnel these resources all the way down and instead expose Resources for Plugins as statics. However, the basic things I see in Application Shell Architectural Style are:

  • Children identify their parents, Parents don't identify their children
  • As a natural consequence, every Child is a lambda function with no free variables.
  • Features like "Context menus" are therefore handled by passing arguments to functions. For example, in Windows File Explorer, the File Type is context passed to the Context Menu Visualizer, which determines what options are available to perform on the file (or group of files).
  • Rather than use free variables, components store state to track what would otherwise be handled through free variables. In object capability model, this is called the Membrane pattern, and what @natemcmaster is arguing as the solution here.
  • Therefore, any limitations in Nate's model can be solved by reading through Mark S. Miller's PhD thesis on Robust Composition, or Ka-Ping Yee's Secure Interaction Design book.

Sorry if this is not clear. It's something I spent over a decade of my life thinking about. I first encountered this architecture reading Charles Petzold's books, but I have since viewed his explanations as baroque and idiosyncratic.

from dotnetcoreplugins.

jzabroski avatar jzabroski commented on July 30, 2024

An abbreviated version of Ka-Ping Yee's Secure Interaction Design is available here: Guidelines and Strategies for Secure Interaction Design. I've joking referred to this as, "The Definitive Explanation of why Linux's PAM subsystem is deplorable, terrible, and will give you a Horrible, No Good, Very Bad Day".

Once you realize Access Control and Concurrency Control are two sides of the same coin, you will never go back to your old way of building composite applications.*

  • This advice doesn't apply to some consumer-facing applications, or applications that disallow plugins and are deliberately monolithic.

from dotnetcoreplugins.

stale avatar stale commented on July 30, 2024

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Please comment if you believe this should remain open, otherwise it will be closed in 14 days. Thank you for your contributions to this project.

from dotnetcoreplugins.

stale avatar stale commented on July 30, 2024

Closing because there was no response to the previous comment.
If you are looking at this issue in the future and think it should be reopened, please make a comment and mention natemcmaster so he sees it.

from dotnetcoreplugins.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.