Unlimited extension of application projects without modifying code

Source: Internet
Author: User
Tags export class

In many application projects that require modular development and are complicated (such as ERP), how to easily expand is often a headache.

Under the traditional conditions, we will distribute various functions in different class libraries, and each time a function is added, an assembly will be referenced. In this method, we will find that, each time you add a new extension, you must reference the newly added assembly. This also means that you need to re-compile the main application every time, there are also maintenance costs.

In the. NET 3.5 era, you may think of addin, but this method will also bring about expansion costs.

The most perfect solution we are pursuing is:

After compiling the application, we can add unlimited extensions without changing the original program. That is to say, I installed application a on the user's machine, and then I made some extensions. I have compiled this new function into FC. the DLL class library is in, but I don't want to re-compile the EXE file and all the components every time I upgrade it. I just need to re-compile the new FC. copy the DLL to the application installation directory.

 

In this way, the maintenance cost can be greatly reduced. In the. NET 4.0 era, the use of the MEF framework can indeed meet the above requirements, but the prerequisites are:

1. Before developing a project, you must specify the structure and specifications of the entire project, at least what the entire application looks like, and you must have a bottom in your brain.

2. Compile a public class library that contains all the behavior specifications for future extension components, that is, define all interfaces that may be implemented in the future in this public class library, all subsequent extended assemblies must implement these interfaces.

 

The content involved in this article may be somewhat esoteric. I hope you can accept it. It doesn't matter if you cannot accept it. After all, many things require time to master.

 

Let me give you a simple example. For example, if I want to develop an application, click a button in a window to display the name of the ball, for example, football, ball, and volleyball. However, Maybe I only gave two options at the beginning-football and volleyball. This is the two Assembly I expanded before I gave the program to the customer. But after a few days, I suddenly remembered that, there are also "badminton" and "basketball", so I want to add two more DLL for the application, but I want the application to be extended without modifying the code, no matter whether I want to expand 100 or 10000 DLL files in the future, I don't need to regenerate the main program. I just need to drop the new DLL into the ext folder in the application.

 

Let's take a look at how to implement it.

1. Create a public class library and write two interfaces. The iball interface is a class related to ball information. This interface is implemented when extension is provided.

    public interface IBall    {        string GetInformation();    }

It has a public method getinformation, which returns the name of the corresponding ball, such as football ".

Another interface is used to describe metadata.

    public interface IMetaData    {        string BallType { get; }    }

Why is this metadata interface defined? This is to identify which extension is called by our application.

For example, the Football Class extension implements the iball interface, the Volleyball Class extension also implements the iball interface, and the Basketball Class extension also implements the iball interface, more extensions may be implemented in the future, so how do we know the football we are calling? Instead of basketball? Therefore, we need this imetadata class. When exporting extended classes, we define the balltype attribute of imetadata for each type. For example, when I define a football class, I define balltype as "foot ball" and set balltype to "volley" when defining the volleyball class.
Ball ". In this way, in our application, we can use this to determine which extension we are calling. Of course, if you do not need to explicitly know which extension to call, this metadata can be ignored.

 

2. Write two class libraries respectively, meeting the following two conditions:

A. Implement the iball interface.

B. Use exportattribute to identify the export type.

The classes of MEF are all from the system. componentmodel. Composition assembly. You just need to reference the Assembly. I will not talk about how to reference the Assembly. This is the basic knowledge. These classes are distributed in the following three namespaces.

System. componentmodel. Composition

System. componentmodel. Composition. Hosting

System. componentmodel. Composition. primitives

 

Using system; using system. collections. generic; using system. LINQ; using system. text; using system. threading. tasks; using system. componentmodel. composition; using system. componentmodel. composition. hosting; namespace ballliba {// <summary> // football // </Summary> [Export (typeof (commonlib. iball)] [exportmetadata ("balltype", "foot ball")] public class football: commonlib. iball {Public String getinformation () {return "";}}}

In MEF, we do not need to implement the interface that provides metadata. We only need to directly set the attribute value in the exportmetadata feature, the runtime automatically generates classes that implement metadata (in this example, the imetadata interface.

 

In the same way, let's create another class library.

/// <Summary> /// volleyball /// </Summary> [Export (typeof (commonlib. iball)] [exportmetadata ("balltype", "volley ball")] public Class Volleyball: commonlib. iball {Public String getinformation () {return "Volleyball ";}}

Now, our project has two extensions.

 

3. to implement our main application, we only need to reference the interface in the public class library we prepared earlier. The extended DLL does not need to be referenced and MEF will automatically search for it. Therefore, you can generate DLL files for all the extended assemblies, and then throw them to the ext folder in the same location as the EXE file, if you have 1000 DLL files, you can just drop them all into the folder, and MEF will automatically search for them.

We use a winform program as the main program, as shown in.

When the program is running, all the assembly is automatically found based on all the extended DLL files in the ext directory, and then displayed in ComboBox. We select the corresponding ball, and then click the button, in this way, the ball name is displayed in the text box.

Using system; using system. collections. generic; using system. componentmodel; using system. data; using system. drawing; using system. LINQ; using system. text; using system. threading. tasks; using system. windows. forms; using system. componentmodel. composition; using system. componentmodel. composition. hosting; namespace testapp {public partial class form1: FORM {compositioncontainer mycontainer = NULL; // The type of the introduced combination [Importlistener] ienumerable <lazy <commonlib. iball, commonlib. imetadata> mball; public form1 () {initializecomponent (); directorycatalog catl = new directorycatalog ("Ext"); mycontainer = new compositioncontainer (catl); try {mycontainer. composeparts (this); // composite component} catch (exception ex) {MessageBox. show (ex. message);} var resbils = (from T in mballselect T. metadata. balltype ). toarray (); this. comboBox 1. datasource = resbils;} private void button#click (Object sender, eventargs e) {If (this. combobox1.selectedindex =-1) {MessageBox. Show ("select an extension. "); Return;} string ballname = This. combobox1.selecteditem. tostring (); // retrieves the Extension Assembly var ballinstance = mbils to be executed. firstordefault (x => X. metadata. balltype = ballname); If (ballinstance! = NULL) {this.txt result. Text = ballinstance. value. getinformation ();}}}}

From the code above, we can summarize the usage of MEF. If you are interested in this method, you can back it up, because no matter what project you use, the idea is the same.

1. Declaring a compositioncontainer variable is required because it can be used to indicate which extended assembly the current application is merged.

2. when instantiating compositioncontainer, I used the directorycatalog class. Why? Because this class is easy to use, you just need to tell it which folder your extended DLL is placed in. It will automatically find the exported extension class in the folder you specified.

3. If there is an export class, there will naturally be an import class. Because all our extensions implement the iball interface, iball should be used for the Export type of the extended class, any declared export class will be detected by MEF and loaded automatically.

Therefore, the export is for the extended assembly, so the import is easy to understand, that is, for our main application, like this example, the winform application as the main program, all extensions are used in this winform, so this winform must import the type. Therefore, the following code is available.

// The imported combination type [importtasks] ienumerable <lazy <commonlib. iball, commonlib. imetadata> mbcalls;

The advantage of lazy to delay instantiation is to improve performance. Remember that the import type added with import does not use new, because directorycatalog will automatically instantiate all the DLL files found in the ext folder, this is the reason for the implementation of latency. It is new only when it is used. Otherwise, if my extension directory contains 100000 DLL and 350000000 classes, then all of your operations will be instantiated, and the performance is estimated to overhead the memory.

As I mentioned earlier, imetadata is used to identify metadata, so we do not have to implement it on our own, and we do not have to specify which interface is actually used, because in the code above, lazy <t, tmetadata> there are two generic parameters?

T is the type we want to import. In this example, It is iball. Note that the type here must be a public interface rather than a specific extension class, otherwise, it will not be able to achieve the purpose of unlimited expansion. The interface is used for its versatility.

Tmetadata is the type used to identify the number of elements. In this example, it is the imetadata interface. Therefore, I didn't need to specify imetadata because it will be specified here, MEF will automatically search for its attribute balltype along this clue.

 

After instantiating the compositioncontainer container, remember to call the extension method composeparts, telling MEF that all the Extended Assembly will be combined with the current instance, otherwise you will not be able to call it.

 

Now, if you run this winform, you will understand it.

 

As you can see, the football and volleyball classes are not referenced in the project. I just threw them into the ext directory and the application will automatically recognize them.

We do not need to modify a line of code in the winform program.

 

If you still don't believe it, we will add a DLL to define a basketyball (basketball ball). Then, we will generate a DLL for this basketball class library, which will also be thrown to the ext directory, I don't need to modify the winform program.

Using system; using system. collections. generic; using system. LINQ; using system. text; using system. threading. tasks; using system. componentmodel. composition; using system. componentmodel. composition. hosting; namespace balllibc {// <summary> // basketball // </Summary> [Export (typeof (commonlib. iball)] [exportmetadata ("balltype", "Basket Ball")] public class basketball: commonlib. iball {Public String getinformation () {return "basketball ";}}}

In the same way, compile the class library into a DLL and then drop it into the ext file. Then run the winform program.

As you can see, I didn't make any changes to winform. I just put a DLL in the ext directory. After running the DLL, the program will automatically identify and find the corresponding type. The drop-down list automatically adds a basket ball option. Select it and click the button. The badketball class is executed and "basketball" is output ".

 

And so on, you can add another one thousand 10 thousand DLL, as long as it complies with the iball interface specifications and is set for export, and then put all the one thousand DLL files in the ext directory, the application does not need to make any changes. After running, it will automatically find one thousand 10 thousand extension classes.

In this way, does it save a lot of maintenance and upgrade costs? Is MEF (managed extensibility framework) powerful?

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.