Implementing the plug-in architecture in C # programs

Source: Internet
Author: User

Read the tip: This article will tell you how to take advantage of C # 's fantastic features to implement a plug-in architecture and build a scalable solution with a plug-in (plug-ins) mechanism.

The C # language under the. NET Framework, and others. NET language provides a lot of powerful features and mechanisms. Some of them are brand new, while others are copied from the previous language and platform. However, this ingenious combination produces some interesting ways to solve our problems. This article will tell you how to use these wonderful features to build a scalable solution using the plug-in (plug-ins) mechanism. There will also be a brief example that you can even use to replace individual programs that are already widely used in many systems. In a system, there may be many programs that often require data processing. There may be one program that handles employee information and the other is used to manage customer relationships.

In most cases, the system is always designed to be a number of independent programs, with few interactions between them, often using the means of copying code to share. In fact, such a situation can be programmed as plug-ins, and then a single program to manage these plugins. This design allows us to better share common methods in different solutions, providing a unified sense of perception.

Picture one is an example of a program. The user interface is no different from other common programs. The entire form is split vertically into two blocks. The left pane is a tree menu that displays a list of plug-ins, and lists the data managed by the plugin under the branch of each plugin. The right pane is used to edit the data for the selected plugin on the left. Each plugin provides its own interface for editing data. The picture shows a delicate work area.

Begin

Then, the main program must be able to load the plug-ins and then communicate with these plugins in order to implement our design. All of these implementations can be implemented in many different ways, depending only on the language and platform that the developer chooses. If you choose C # and. NET, then the Reflection (reflection) mechanism can be used to load plug-ins, and its interfaces and abstract classes can be used to communicate with plug-ins.

In order to better understand the main program and the communication between the plug-in, you can first understand the design pattern. The design pattern was first proposed by Erich Gamma 1, which uses architecture and object ideas to implement a common communication model. Regardless of whether the component has different inputs and outputs, as long as they have similar structures. Design patterns can help developers solve problems with proven object-oriented theory. In fact, it is the language that describes the solution, regardless of the specifics of the problem or the specifics of the programming language. The key point of design pattern strategy is how to decompose the entire solution according to function, which is done by separating the different functions of the main program. This allows communication between the main program and the subroutine to be done through a well-designed interface. With this decomposition we can immediately get these two benefits: first, the software project is divided into smaller unrelated units, the workflow design can be easier, and the smaller code snippet means that the code is easier to build and maintain. The second advantage is that changing the behavior of the program is not related to the operation of the main program, the main program does not care about the sub-program, as long as there is a common communication mechanism is sufficient.

Establishing an interface

In a C # program, an interface is used to define the functionality of a class. The interface defines the expected method, property, and event information. In order to use the interface, each specific function must strictly follow the definition of the interface to complete the described function. List one shows the interface of the above example program: IPlug. This interface defines four methods: Getdata,geteditcontrol,save and print. These four definitions do not describe how this is done, but they ensure that the class supports the Iplug interface, which is guaranteed to support the invocation of these methods.

Custom properties

Before looking at the code, the discussion is always first shifted to the property customization. Property customization is one of the great new features provided by. NET, and attributes are a common structure for all programming languages. For example, a function is used to identify the public,private that can be accessed. Or the Protect flag is a property of this function. Property customization is so exciting because programmers will no longer be able to choose only from a limited set of attributes provided by the language itself. A custom property is actually a class, it inherits from System.Attribute, Its code is allowed to be self-describing. Property customization can be applied to most structures, including classes, methods, events, domains, and attributes in C #. The sample code snippet defines two custom properties: Plugdisplaynameattribute and Plugdescriptionattribute, All the plugins inside the class must support both properties. List Two is the class that defines the Plugdisplaynameattribute. This property is used to display the contents of the plug-in node. When the program is running, the main program can take advantage of reflection (reflection) to get the value of the property.

Plugins (Plug-ins)

The example program above includes the execution of two plug-ins. These plugins are defined in EmployeePlug.cs and CustomerPlug.cs. List three shows a partial definition of the Employeeplug class. Here are some key points.

1. This class implements the Iplug interface. Because the main program does not know how to define the class inside the plug-in, this is very plaque? The main program needs to use the Iplug interface to communicate with each plug-in. This design leverages the "polymorphism" inside the object-oriented concept. Polymorphism allows the runtime, by pointing to a reference to the base class, To invoke methods in the implementation-derived class.
2. This class is identified by two attributes so that the main program can determine if the plugin is valid. In C #, to identify a property for a class, you have to declare the attribute before the class's definition, enclosing the contents in parentheses.
3. For brevity, the example simply uses data that is written directly to the code. And if the plugin is a formal product, then the data should always be in the database or file, and all of the data should be managed only by the plug-in itself. The data for the Employeeplug class is stored here with the EmployeeData object, which is also a type and implements the Iplugdata interface. The Iplugdata interface is defined in IPlugData.cs, which provides the most basic data exchange capabilities Used for communication between the main program and the plug-in. All objects that support the Iplugdata interface provide a notification when the underlying data changes. This notification is actually the occurrence of the DataChanged event.
4. When the main program needs to display a list of data contained in a plugin, It calls the GetData method. This method returns an array of Iplugdata objects. This way the main program can use the ToString method to get the data for each of the objects in the array to build each node of the tree. The ToString method is an overload of the EmployeeData class, Used to display the employee's name.
The 5.IPlug interface also defines the save and print methods. The purpose of defining these two methods is to notify a plug-in when there is a need to print or save the data. The Employeeplug class is used to implement the ability to print and save data. When using the Save method, The location where the data needs to be saved will be available at the time of the method call. This assumes that the main program will query the user for information such as paths. The query for path information is the service that the main program provides to each plug-in. For the Print method, The main program passes the options and content to an instance of the System.Drawing.Printing.PrintDocument class. In both cases, the interaction with the user is consistent with the main program.

Reflection (Reflection)

After a plugin is defined, the next step is to see how the main program loads the plugin. To achieve this goal, the main program uses the reflection mechanism. Reflection is used in. NET to view type information at run time. With the help of the reflection mechanism, Type information will be loaded and viewed. This allows you to check the type to see if the plug-in is valid. If the type passes the check, then the plugin can be added to the main program interface, can be manipulated by the user.

The sample program is used. NET Framework of three built-in classes to use reflection: System.reflection.assembly,system.type, and System.activator.

The System.Reflection.Assembly class describes the assembly for. Net. In. NET, an assembly is a hive. For a typical Windows program, the assembly is configured as a single Win32 executable file with specific additional information to accommodate. NET runtime environment. Assemblies can also be configured as WIN32 DLLs (dynamic-link libraries), with the same needs. NET requires additional information. The System.Reflection.Assembly class can get information about the assembly at run time. This information includes the type information that the assembly contains.

The System.Type class describes the type definition. A type declaration can be a class, an interface, an array, a struct, or an enumeration. After a class is loaded, the System.Type class can be used to enumerate the methods, properties, events, and interfaces that the class supports.

The System.activator class is used to create an instance of a class.

Loading plugins

List four shows the Loadplugs method. The Loadplugs method is defined in HostForm.cs and is a private non-static method of the Hostform class. The Loadplugs method uses the. NET reflection mechanism to load the available plug-in files. and verify that they conform to the requirements that are used by the main program, and then add them to the main program's tree display. This method contains the following steps:

1. By using the System.IO.Directory class, our code can use wildcards to find all files with a. plug extension. The static method GetFiles of the directory class can return an array of type System.String, To obtain the physical path of each file that meets the requirements.
2. After getting the path string array, you can start loading the file into the System.Reflection.Assembly instance. The code that establishes the Asdsembly object uses the Try/catch code block, so that if a file is not an effective one. NET assembly, an exception is thrown, and the program pops up a MessageBox dialog box that tells the user that the file cannot be loaded. The loop continues until all the files have been traversed for completion.
3. After an assembly is loaded, the code iterates through all accessible type information and checks to see if the Hostcommon.iplug interface is supported.
4. If all types support the Hostcommon.iplug interface, the code continues to validate these types and checks to see if the properties that have been pre-defined for the plug-in are supported. If there is no support, Then a hostcommon.plugnotvalidexception type of exception will be thrown, as well, the main program will pop up a MessageBox, telling the user the details of the error. The loop continues until all the files have been traversed.
5. Finally, if these types support the Hostcommon.iplug interface and all properties that need to be defined are already defined, then it will be wrapped as a plugtreenode instance. This instance is added to the main program's Tree display area.

Realize

The main program framework is designed to be two assemblies. The first assembly is Host.exe, which provides the main program's Windows Forms interface. The second assembly is HostCommon.dll, which provides all the type definitions required for communication between the main program and the plug-in. For example, The Iplug interface is configured in the HostCommon.dll, so it can be accessed by the main program and the plug-in equivalent. The two assemblies are in a folder, and the additional assemblies that are attached as plugins need to be configured together. Those assemblies are configured within the Plugs folder ( A subfolder of the main program directory). The Employeeplug class is defined in the Employee.plug assembly, The Customerplug class is defined in the Customer.plug assembly. This example specifies the plug-in file with the. plug as the extension. In fact, these plug-ins are common. NET class library files, but typically the library files use the. dll extension, Here's A. Plug. A special extension is completely unaffected by the program's operation, but it allows the user to know more clearly that this is a plug-in file.

Comparison of designs

It's not necessarily the case that the design is correct like an example program. For example, when developing a C # program with a plug-in, you do not have to use attributes. The example uses two custom attributes, and can actually be implemented by defining the parameters of the two iplug interfaces. Here's a selection of properties, is because the name of the plugin and its description in essence is actually a property of a thing, conforms to the specification. Of course, using properties causes the main program to need more code about reflection. Designers always need to make reasonable decisions about different needs.

Summarize

The sample program is designed to be as simple as possible to help understand the communication between the main program and the plug-in. In the actual production, you can do a lot of improvements to meet the practical requirements. For example:

1. By adding more methods, properties, events to the Iplug interface, you can increase the communication point between the main program and the plug-in. More interaction between the two allows the plugin to do more things.
2. You can allow users to proactively select plugins that need to be loaded.

Source
The complete source code for the sample program can be downloaded here: Http://www.sunmast.com/code/PlugSample.zip

The Translator notes: I have thought about it before. NET inside how to implement the plug-in mechanism, do to do to always feel that the design is not good enough. And yesterday in the online inadvertently found this article, write is really great, so after reading, decided to translate it, before and after the total spent about 10 hours. The translation may not be very good, please forgive me. Please do not hesitate to correct me.

Note
1 Erich Gamma et al. Design Patterns (Addison-wesley, 1995).

Picture one:

List one: the IPlug interface

public interface IPlug
{
Iplugdata GetData ();
Plugdataeditcontrol GetEditControl (Iplugdata Data);
BOOL Save (string Path);
BOOL Print (PrintDocument Document);
}

List II: The Plugdisplaynameattribute class definition

AttributeUsage (AttributeTargets.Class)
public class PlugDisplayNameAttribute:System.Attribute
{
private string _displayname;

Public Plugdisplaynameattribute (String DisplayName): Base ()
{
_displayname=displayname;
Return
}

public override string ToString ()
{
return _displayname;
}

List III: A partial listing of the Employeeplug class definition

Plugdisplayname ("Employees")
Plugdescription ("This plug was for managing employee data")
public class EmployeePlug:System.Object, IPlug
{
Public Iplugdata GetData ()
{
Iplugdata data = new EmployeeData
{
New EmployeeData ("Jerry", "Seinfeld")
, New EmployeeData ("Bill", "Cosby")
, New EmployeeData ("Martin", "Lawrence")
};

return data;
}

Public Plugdataeditcontrol GetEditControl (Iplugdata Data)
{
return new Employeecontrol ((EmployeeData) Data);
}

public bool Save (string Path)
{
Implementation not shown
}

public bool Print (PrintDocument Document)
{
Implementation not shown
}
}

List four: The method loadplugs

private void Loadplugs ()
{
String files = Directory.GetFiles (" Plugs "," *.plug ");

foreach (string f in files)
{

Try
{
Assembly a = Assembly.LoadFrom (f);
System.Type types = A.gettypes ();
foreach (System.Type type in types)
{
if (type. GetInterface ("IPlug")!=null)
{
if (type. GetCustomAttributes (typeof (Plugdisplaynameattribute),
false). Length!=1)
throw new Plugnotvalidexception (type,
"Plugdisplaynameattribute is not supported");
if (type. GetCustomAttributes (typeof (Plugdescriptionattribute),
false). Length!=1)
throw new Plugnotvalidexception (type,
"Plugdescriptionattribute is not supported");

_tree. Nodes.Add (New Plugtreenode (type));
}
}
}
catch (Exception e)
{
MessageBox.Show (e.message);
}
}

return;
}

About the author
Shawn Patrick Walcheske is a software development engineer in Phoenix, Arizona, USA. He is also Microsoft Certified Solution Developer and Sun Certified Programmer for the Java 2 Platform. You can contact him here,[email protected].

Original Shawn Patrick Walcheske

Original link: http://www.cuj.com/documents/s=8209/cujweb0301walcheske/

Implementing the plug-in architecture in C # programs

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.