Hi! I’ve set up a simple plugin system for my application that works by a plugin author compiling a Dll and placing it in a Plugins folder. E.g:
This works just fine for me when I test because I can reference my application’s project in MyPlugin.csproj – but third party authors won’t have access to my application’s assembly (they can’t exactly reference an exe).
I’m wondering what the appropriate way to handle this is. Is it to extract the “Public API” part of my application to another project that I can then compile to a DLL and redistribute?

How about other assemblies that my main project references (say a NuGet package) that an author might need but I am not allowed to redistribute? Will I have to instruct them to manually download and reference this themselves? Or is there a way to tell the compiler “Hey, I know you can’t find an implementation for this but trust me it exists and it’s defined like this” e.g. like a header file in C(++).
Example of what I mean:

If I’m writing a plug-in for a product, usually that product offers a public library/SDK where they’ve broken out those public references I need. So I’ll important a nuget package or add a dll reference to my project.
Yes I figured that was the correct solution, thanks for confirming. But how about third party libraries? If my main project references AwesomeMathLib.dll can I somehow include the classes from this assembly in my compiled MyProjectPublicCore.dll (if so, how)? Or do I have to tell the plugin authors to manually download AwesomeMathLib.dll?

You can just “using” import them, when you compile the DLL, you can compile it to single file which includes the imports. Basically it copies the library code in the “using” line.

This is why people use nugets, because there you can specify the prerequisites to the extension.
Regarding accessing plugin class from the main, use interfaces.
I extracted the public API of my application to its own DLL (MyProjectPublicCore.dll) so now I can reference Plugin just fine. However I still can’t reference Vector2 since it’s a dependency of MyProjectPublicCore.dll that MyPlugin can’t reference. How do I go about compiling MyProjectPublicCore.dll and its dependencies to “single file” like you mentioned above? The closest I can find is “packing” the project to a MyProjectPublicCore.nuget file. Is this what you mean?

You can use MEF or something like it to load all DLLs in a “plugins” folder and iterate over them to find any classes implementing an IPlugin interface that you create.
Then if someone wants to make a plugin, they simply reference the DLL you created which contains IPlugin and anything else you might let them have access to, and code against that interface.

If you want to get fancy, and have multiple places where plugins can be inserted, you can create multiple interfaces; for instance you might have an ILoaderPlugin to support loading new file formats and an IRendererPlugin to render 3D graphics or something like that.

Keep in mind though that executing arbitrary third party code can be dangerous; whoever is using your app will need to trust that whoever created the plugins they’re using is not trying to inject malicious code into your app.

As for the NuGet package licensing… why would a NuGet package not allow redistribution? Seems kind of pointless to upload a package to NuGet if you’re not going to let people actually use it!

I find MEF confusing since there are almost no tutorials or examples of how to use it, and the few that do exist mix MEF 1 and 2 concepts (attribute / attribute-less etc) or use very outdated code examples (2009!). The actual loading of files I’ve already taken care of though by manually iterating through each assembly’s public types.

MEF was created for this. It’s been recommended to myself as well by very experienced engineers (20+ years writing software).
We do something similar. Our setup:

Common on nuget that defines IPlugin or Plugin or whatever.
Plugins use above nuget to get classes and include their dependencies in plugins folder.

Main app loads all DLLs in plugins folder and searches for anything implementing the plugin.
(they can’t exactly reference an exe).
you’ll be surprised to find out they can lol. Sure, it’s not good practice, but it definitely works!
Why is it not good practice?
I did not create a system like this, but wrote plugins for system which works like this.

Create a public nuget which exposes types that you want the developer to be able to acces (Plugin, IPlugin, PluginHelper etc)
When they build their plugin project, they need to copy their DLL to their plugin folder. This can get tricky if they have other dependencies (multiple projects, nuget etc). In this case they will want to copy their dependencies also, so you will need to load those dlls as well. Maybe you want to enforce some separation, for example you want each plugin in a subfolder (Plugins/PluginA/PluginA.dll, Plugins/PluginB/PluginB.dll Plugins/PluginB/PluginBDependency.dll . The behavior of loading external DLLs is a bit different when using .Net Core

If you want creating the DLLs easy for other developers you might want to publicise some custom SDK (target/props files) which will create a clear output (bin/plugin which will not contain the DLLs of your library project, only their dependencies)

Yes, you should extract all relevant parts of you Plugin API to its own class library project. When you build your DLL, the compiler will also dump all necessary DLLs for all your referenced assemblies (direct referenced dlls, referenced projects, and NuGet packages, included). E.g. if you’re using “JoeBob” NuGet package, when you build your class library in release mode targeting .NET 5, in the [Project]/bin/Release/net5.0 folder you’ll have Plugin.dll and JoeBob.dll (among other things like .pdbs, etc). You’ll have to distribute them together and make sure they get installed on the user’s machine in the same folder. If you’re using any packages that restrict distribution, you’ll have to get guidance from them on how to package and distribute your library.

NuGet packages are a bit smarter. You can give NuGet a manifest telling it what all other packages you depend on and the NuGet client will download all of them for the user when they install your package. Here’s a link on how to create a NuGet package.

Extract the public API out of your application and put it into a DLL. Plugin authors will need to reference that DLL in order to develop the plugin.
Have a look at Microsoft’s Managed Extensibility Framework (MEF). It makes loading plugins pretty damn easy. However, it has been a few years since I messed with it and I don’t know what parts are compatible with .NET Core/NET5, if at all.

You can use reflection directly to do what you want if you don’t want to use MEF, but plugin authors will definitely need to reference that DLL so you can work with CLR types instead of just using reflection to invoke methods you hope exists.

source