DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
11 Monitoring and Observability Tools for 2023
Learn more

Discoverable and non-discoverable parts in MEF

Denzel D. user avatar by
Denzel D.
·
Jun. 25, 10 · Interview
Like (0)
Save
Tweet
Share
7.13K Views

Join the DZone community and get the full member experience.

Join For Free

If you’ve read my article that introduces to the basics of MEF, then you probably already understand what imports and exports are.

Based on these imports and exports, the MEF composition engine is putting the extensible (and extension) parts together to build the complete functionality set, provided by various modules. Many of the examples show cases where all parts exposed by the extension are discoverable by the composition engine, when called in the main application.

For example, there is an interface that defines the structure of an extension:

[InheritedExport]
public interface ISample
{
string Unit { get; set; }
}


The extension itself looks like this:

public class Sample : ISample
{
public string Unit
{
get
{
return "Assigned text";
}
set { }
}
}

It explicitly exposes the Sample class as a discoverable part via the InheritedExport attribute that decorates the interface. Basically, what the InheritedExport attribute says is that whatever class inherits it, exports its instance. Therefore, Sample will automatically export an instance of ISample.

The composition engine will be able to get this instance in case the main application provides an import for the contract.

This is what’s called a discoverable part – the composition engine is able to detect it and instantiate it for the base application. But what if the developer doesn’t want to make the part discoverable, but still provide imports and exports for some components? I found out that there are ridiculously small amounts of documentation regarding this topic online, so I will try to explain how it works here.

This is the case specific for abstract classes (that are not discoverable anyway) and for classes that for some reason cannot be set abstract. A class can implement an interface. If the interface has the InheritedExport attribute, this will automatically mean that this class exposes an instance of that interface, however this won’t be completely true, since the class can implement other classes, methods or fields.

There is no doubt that the class will abide the contract and will actually be imported if requested, but since it was intended to have different functionality (for example, it is a helper class), the developer could avoid this.

MEF provides the PartNotDiscoverable attribute that tells the composition engine to ignore this part (therefore, it won’t be composed). Let’s take a look at this snippet:

[PartNotDiscoverable]
public class Sample : ISample
{
[Import("MyContract")]
public string Unit
{
get;
set;
}

public void ShowText()
{
Debug.Print("Another text");
}
}

It is the same part as the one shown above with small modifications- first of all, it has the ShowText method and it imports the string setting. This certainly qualifies as an instance of ISample, but I don’t want my application to see it since I am using it as a base class for another class (besides, I won’t be able to use the ShowText method from an ISample instance unless it is called internally – and that requires the class to actually inherit a base class that inherits the interface):

public class MainClass : Sample
{

}

This class can use the ShowText method from the base class in one of its own methods, so I am using the MainClass class as a helper.

In the main application, I can define an export to satisfy the import for the MainClass class:

[Export("MyContract")]
public string welcome = "Sample String";

And of course, there is an import for an ISample instance that will be the an instance of MainClass:

[Import(typeof(ISample))]
ISample sample;

Now I can use the composition process to instantiate the MainClass with the import filled:

AssemblyCatalog catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());

var container = new CompositionContainer(catalog);
var batch = new CompositionBatch();
batch.AddPart(this);
container.Compose(batch);

Debug.Print(sample.Unit);

This will print “Sample String” in the Output window. It works!

Now, let’s take a look at a graphic representation of the above process to better understand the need for a non-discoverable part.

First of all there is a base class that is invisible to the composition engine. It has an import defined and a set of helper methods:

There could be one or more classes that inherit the base class. Although the base class is not discoverable, its imports are discovered by the composition engine when the inheriting class is checked for the ancestor (it discovers the interface behind the ancestor). For example, there is the MainClass (like the one that was shown a bit earlier) that inherits from the base class and OtherClass:

By inheriting the base class, they are automatically considered instances of the interface that defines the base class. And each one of them inherits the import.
The application, by exposing an export, fills the import for the base class, and that will automatically fill the imports for every single class that inherits its functionality from the base class.

While still implementing the needed interface, the base class can provide additional functionality to inheriting classes and helps avoid additional export attributes inside the classes that inherit it. This is just one of the reasons to make a part non-discoverable. Eventually, you will see that the need to implement a class that should not be detected as a part is eventually present, when the plugin model expands.

application Interface (computing)

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • How To Build an Effective CI/CD Pipeline
  • Use Golang for Data Processing With Amazon Kinesis and AWS Lambda
  • Practical Example of Using CSS Layer
  • Distributed Tracing: A Full Guide

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: