Natasha plug-in dll
Call external dll to implement componentization
scene
- There is an equipment management control system, whose main function is to control equipment and collect information about related equipment. Currently, it only integrates access control and monitoring. When more equipment is expected to be added in the future, it is usually implemented and debugged on site after the company has written it. , the code generally creates an independent project for each device for the total project to call; slowly it may evolve that all devices inherit a common interface class, and the interface class implements obtaining capability sets and sending commands, thereby reducing the need for To modify the master control module, you only need to maintain the capability set at this time; however, you also need to run an entire solution every time. If this system is also needed elsewhere, you can only reduce the references by uninstalling the project for real-time implementation. At this time, you can separate the project and perform component management through Natasha. The advantage of this is that communication is carried out through agreed interfaces and capability sets, and the coupling between the main program and the device is low. If you encounter other projects that require the system, you only need to put the required dll into a specific folder.
- Any system that can be split into modules can be developed according to componentized logic, such as a project with a business process. Each step can have multiple component options and can execute one or more; or through the obtained The plug-in dynamically configures which plug-in should be executed at that step, and uses the plug-in’s feedback to determine whether the next step should be performed.
Benefits
- Low coupling, business separation, plug-ins only need to care about the plug-in interface and feedback, and do not need to care about the business logic of the core system
- The division of labor is clear. Everyone only needs to pay attention to the plug-in code. It is easy to troubleshoot problems after project integration. If the plug-in is not called, there is a problem with the main system. If the result of calling the plug-in does not match the actual situation, there is a problem with the plug-in.
- Easy to maintain and low in learning costs. For a specific plug-in, the amount of code will be far less than that of the entire project, and each business can be split.
implementation
- Get Assembly
Mainly use the method of instantiating the NatashaDomain class (source code location: src\Natasha.Domain\Extension\NatashaDomainExtension.cs)
Related methods:
LoadPluginUseDefaultDependency If the loaded dll has already been loaded, skip
LoadPluginWithAllDependency does not determine the version, the explanation in the source code is the default, and it feels similar to Default
LoadPluginWithHighDependency uses a higher version of the dll
LoadPluginWithLowDependency uses a lower version of the dll
Parameter description:
string path is required, the path where the dll is located
Func? excludeAssembliesFunc = null Optional, the dll that needs to be excluded, return true to exclude references, such as jointly referencing a common dll (such as Utils.dll), at this time you can choose which version to use dll
- Find the clas class and instantiate it
Find the class class (the default implementation class of all plug-ins is *Controller), you can also follow the example below
var type = assembly.GetTypes().Where(item => item.Name.IndexOf(“Controller”)!=-1).First();
Instantiation
var plugin = (IPluginClass)(Activator.CreateInstance(type)!);
example
-
Create two underlying projects
-
IPluginBase project: used to create interfaces used by plug-ins
using PluginUtil; namespace IPluginBase { public interfaceIPluginClass { ///
/// Initialization method /// public void initialize(); ////// Get plugin-specific methods /// /// public List getFunction(); ////// Obtain the required timing method /// /// public List getTimeFunc(); ////// Execute plug-in code through methods /// /// FruitFunction /// Possible input values /// public String execute(FruitFunction function, String param); } } -
PluginUtil project, used to declare FruitFunction
using System.ComponentModel; namespacePluginUtil { public enum FruitFunction { [Description("hardness")] hardness = 01, [Description("Apple-specific features")] appleAttr = 02, [Description("cut")] cut = 03 } }
-
-
Create two plug-in projects
-
PluginApple project
using IPluginBase; usingPluginUtil; namespace PluginApple { public class PluginAppleClass : IPluginClass { public string execute(FruitFunction function, string param) { switch (function) { case FruitFunction.cut: Console.WriteLine("Cut the apple"); break; case FruitFunction.hardness: Console.WriteLine("The apple is crispy"); break; case FruitFunction.appleAttr: Console.WriteLine("Apple-specific properties"); break; } return "end"; } public List getFunction() { Console.WriteLine("Return Apple's existing functions"); return new List() { FruitFunction.appleAttr, FruitFunction.cut, FruitFunction.hardness }; } public List getTimeFunc() { Console.WriteLine("Return to Apple's timing function"); return new List() { FruitFunction.cut}; } public void initialize() { Console.WriteLine("Apple initialization completed"); } } }
-
PluginBanana project
using IPluginBase; using PluginUtil; namespace PluginBanana { public class PluginBananaClass : IPluginClass { public string execute(FruitFunction function, string param) { switch (function) { case FruitFunction.cut: Console.WriteLine("Cut banana"); break; case FruitFunction.hardness: Console.WriteLine("Banana is soft"); break; } return "End"; } public List getFunction() { Console.WriteLine("Returns Banana's existing functionality"); return new List() { FruitFunction.cut, FruitFunction.hardness }; } public List getTimeFunc() { Console.WriteLine("Return to Banana's timing function"); return new List() { FruitFunction.cut }; } public void initialize() { Console.WriteLine("Banana initialization completed"); } } }
-
-
How to use Natasha to implement two plug-in projects
Prerequisite: Place PluginApple.dll and PluginBanana.dll in the plugins folder under the same level as NatashaStudyConsole.exe
using IPluginBase; using PluginUtil; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; namespace NatashaStudyConsole { internal class PluginDemo { public void PluginMethod() { //Get the dll storage path string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory+ "plugins"); //Instantiate NatashaDomain NatashaDomain domain = new(Guid.NewGuid().ToString()); List assemblies = new List(); //Instantiate by getting all dlls Directory.GetFiles(path, "*.dll").ToList().ForEach(dll => { //load dll var assembly = domain.LoadPluginWithAllDependency(dll); // In this example, the project name is "A" and the class that needs to be instantiated is "AClass", so the IndexOf method is used // Get the project name var asmName = assembly.GetName().Name!; // Determine which class should be instantiated based on the project name var type = assembly.GetTypes().Where(item => item.Name.IndexOf(asmName)!=-1).First(); // instantiate var plugin = (IPluginClass)(Activator.CreateInstance(type)!); if (plugin != null) { // save assemblies.Add(plugin); } }); assemblies.ForEach(assembly => { // Implement related methods List functions = assembly.getFunction(); if(functions != null && functions.Count > 0) { assembly.execute(functions[0], ""); } }); } } }
Code structure diagram:
Execution results: