I want to build a flexible reporting system for my application. So far I only have a concept in my head and need some tips on implementation. I'm using Crystal Reports to render reports and I know how to load reports dynamically.
Now, the idea is that every report will be packaged as a separate assembly (.dll). The reporting framework will be loading every custom report and communicating with it via clearly defined interface like this:
public interface IReport
{
string GetTitle();
string GetDescription();
void SetParameter();
void Print();
}
Also, there will be some base implementation (as an abstract class) that will handle some common operations on the reports (like binding to data source, etc.):
public abstract class Report
{
...
}
Inside every dll there will be an implementation of concrete class, representing this or that report:
public class CustomersReport : Report
{
...
}
Now, I have to figure out the following:
1) How to dynamically locate and load the dll?
2) How to create an instance of concrete class (CustomerReport) and cast it to IReport in order to call necessary methods on it?
Have you ever implemented such an extensible system? Could you please share your expertise / code snippets?
Thanks in advance.
EDIT:
While investigating this question I found Jon Skeet's article on Plug-ins and Cast Exceptions that might be helpful.
See this:
Problem with dynamic loading of a dll into my program
Is doing exactly what you want wihtout all the YAGNI around it.
Have a look at Mono.Addins (it's MIT license so it's ok with closed software). From your description it does what you need. Basically it uses a dependency tree + plugins based on interfaces. It has it's own manager for loaded .dll-s and its objects are based on the loaded interface, so you don't need any more magic casting to call anything.
You can consider MEF from Microsoft. It is a composition engine that can be set up to monitor a local folder and automatically load assemblies that export parts (implementation of IReport in your case) that you're interested in.
We do have a system like that we implemented sometime ago. We have a single assembly with reports that we load into a separate application domain and reload if the file version has changed. Then we use .NET remoting to communicate between app domains. We considered using Add-in framework from Microsoft but we found it to be very complex and imposing and decided it was too heavy and complex in our case.
Related
okay. So I want to build up a program, that acts as a core for "plugin"-modules.
Another developer could create a plugin1.dll and add it to the "modules" folder to enhance the functionality of my core-application.
So lets say my core has as example those functionalities:
Logging
User Authentification
User Interface
As example we have our core-application as mentioned above and someone wants to add a plugin that lets an user see the current time and log it into a standard-log.txt.
So he would create a class-library that has the functionality:
get the current time (functionality included in the .dll)
display the current time (functionality included in the .dll)
log the current time (functionality included in the core)
Now my problem is, I can invoke the functionalities of the plugin easily from my core-application using reflection, but how would I the other way around?
How can my plugin1.dll access and invoke the fully-set up logging-functionality of the core-program?
I hope you got my question. I want my plugin1.dll to be able to call as example Logging-methods of my core-class.
Thanks!
I suggest to separate your problem into two aspects:
How can the plugins know what functions are available in the core
application (at compile-time)?
How can they actually invoke those function (at run-time)?
An answer to the first aspect, is to create a separate interface-dll, that defines one (or more) interfaces that the core application will provide. Note that this should contain ONLY the interface definitions, no implementation. A plugin-developer can then import that dll, and program against that interface (without needing a dependency on your complete core implementation).
An answer to the second aspect: You could demand from your plugins to expose a well-known entry-point for initialization. In that method you could provide them a reference to your core implementation as an argument, so that they can store that reference and invoke methods on that interface as needed.
A simple example could look similar to the following:
Interface dll:
public interface ICoreApplication
{
//These are the methods that you want to provide to your plugins:
void LogMessage(string msg);
//void SomeOtherMethod(...)
//...
}
public interface IPlugin
{
//These are the methods that you expect from your plugins:
void Init(ICoreApplication coreReference);
}
(BTW: The IPlugin interface could also contain additional methods, if you alredy know the functionality that you expect your plugins to provide. In that case, you would not have to invoke your plugins via reflection, but via that interface.)
Core application:
public class Core : ICoreApplication
{
public void InitPlugins()
{
IPlugin somePlugin = ...; //retrieve via reflection
somePlugin.Init(this);
}
}
Note that this is just a simple example, to illustrate the basic concept. There is much more to providing a robust plugin-architecture. You need to think about things like
Security (Can you trust your plugins? Can you trust the file system from where you load them?)
Error-handling (What happens if a plugin throws an exception? What if it wants to notify you about an "expected failure"?)
Threading (If you invoke your plugins on your main thread, they can block your whole application. If you invoke them on some other thread, you need to think about synchronization. What if a plugin creates a new thread and invokes your core application on that thread?)
etc...
I have a Winform application where I would like to implement some sort of an interface for the customer, so parts of the code is changeable by customer later on if they need to. I believe my approach is wrong, because I get an error in Visual Studio after recompiling my Winform application. The error is "Argument type MyClass is not assignable to parameter type MyClass", but I'm still able to recompile it. I'm worried this would break later on...
This is how I have implemented it until now:
In my winform application I have created an abstract class with a virtual method.
I'm "releasing" an open source project dll assembly for the customer where this abstract class is implemented and the method is calling the base method in the abstract class. If customer would like to change the method, they simply implement it themselves.
This open source project is then referenced and implemented in my winform application.
When customer would like to change the method they implement the method, recompile the dll and replace the new dll with the one I distributed with my assembly.
My winform application has it's own strong name, and the open source project has it's own strong name.
However, when I recompile my Winform application after having referenced the open source project, i get this error: "Argument type MyClass is not assignable to parameter type MyClass". I can still recompile the project. But I'm concerned the implementation has some serious flaws and will break later on. Especially also since I have implemented WyBuild where I will distribute updates for the Winform application.
I need to provide a way for the customer to change some methods in the application without having access to all the source code. How can this be achieved if my implementation is wrong, what is your suggestion?
Thanks.
I'd say that approach itself is a bad way to do it. To me, this sound very error prone, and you state yourself that you have a bad feeling about it. If so, then really don't do it this way.
There sure is a couple of other solution thinkable, but given your descriptions I might do it as follows, which would stay your your original intention.
Have a look at Microsoft's Managed Extensibility Framework (MEF), which could help you in several ways.
Simply put, it would work like this:
You define the interface that the custumer has to implement.
The client then creates an assembly that implements exactly that interface and puts it a location that is monitored by MEF
MEF loads the assembly automatically (no need to reinvent the wheel)
MEF gives you a lot of control over how you want it to work. Like, like should it allow loading only or multiple assemblies that implement that interface at the same time, or should only look for plugins only at the start of the application or monitor the plugin location during the full life-time of it.
Also by doing it this way you get rid of the custom solution you are assembling here and instead use a mature framework that provides a standadized way to do it. Just have look at some tutorials on the net, it is really easy to get into.
Sorry if I am not clear enough, I've had a hard time writing this question.
I downloaded an open source software. I would like to expand the functionalities so I would like to create modules that encapsulates the functionality these modules would be .dll files.
I would like to have one completely independent from another: if I set a key to true in the config file and if the DLL is present on the folder, the plugin should be loaded.
The problem is: how can I make the call for the plugin dynamically (only call of the plugin is applied)?
If I reference the plugin classes directly, I would have to reference the plugin dll, but I want to be able to run the core software without the plugin. Is there any design pattern or other mechanism that would allow me to load and use the DLL only if the plugin is applied and still be possible to run the core software without the plugin?
There are various ways to achieve this and I will describe one simple solution here.
Make a common interface that each plugin must implement in order to be integrated with core application. Here is an example:
// Interface which plugins must implement
public interface IPlugin
{
void DoSomething(int Data);
}
// Custom plugin which implements interface
public class Plugin : IPlugin
{
public void DoSomething(int Data)
{
// Do something
}
}
To actually load your plugin from dll, you will need to use reflection, for example:
// Load plugin dll and create plugin instance
var a = Assembly.LoadFrom("MyCustomPlugin.dll");
var t = a.GetType("MyCustomPlugin.Plugin");
var p = (IPlugin)Activator.CreateInstance(t);
// Use plugin instance later
p.DoSomething(123);
You can use some kind of naming convention for your plugin assemblies and classes
so that you can load them easily.
You can use MEF.
The Managed Extensibility Framework (MEF) is a composition layer for
.NET that improves the flexibility, maintainability and testability of
large applications. MEF can be used for third-party plugin
extensibility, or it can bring the benefits of a loosely-coupled
plugin-like architecture to regular applications.
Here is programming guide.
Plugins or DLLs in .NET jargon are called assemblies. Check out the Assemply.Load method, and also this guide in msdn.
The System.Reflection namespace provides many tools that will help you with this scenario.
You can
inspect assemblies (DLL files) to examine the objects inside them,
find the types that you are looking for (specific classes, classes which implement specific interfaces, etc)
create new instances of those classes, and
invoke methods and access properties of those classes.
Typically you would write a class in the extension which does some work, create a method (e.g. DoWork()), and then invoke that method dynamically.
The MEF mentioned in this question does exactly this, just with a lot more framework.
I'm developing a MAF application which, in a DLL contains a class. The problem is, when one of the methods exposed by one of the AddIns uses this class. Example:
class A
{
Property_1
Property_2
Method_X()
}
And my AddIn has a method which use class A
MyAddIn.Set(class A);
So, with this, where must I place the DLL in the pipeline? Or how should I proceed with this scenario?
When the proyect start, the warnings of the AddInStore.Update() method throws messages like: unable to connect a part of a canalization...
So, there is an article this which says "There are many other capabilities MAF provides such as versioning, passing collections and WPF visuals, passing non-serializable types, etc.". But I can't find an example.
EDIT:
Thanks to Panos for this link about the restrictions on contracts. And after more research I've found this article which, through the Paint.NET proyect, shows how to use data types in the host without referencing.
After reading both sources, I know that this is what I'm looking for. But I can't understand it yet.
As a final petition, can someone please provide me code example? Just to finally get it.
Thanks.
You should study these guidelines on what types are allowed in the contracts assembly.
Basically you should not reference the dll you mention in the pipeline (contracts, adapters and views) because this way you can leak types from the host to the add-in. This means that you will lose versioning because all pipeline segments are referencing the same assembly. What this means is that if the add-in is referencing v.1 of the assembly and the contract is referencing v.2, both versions will be loaded and an InvalidCasrtException will be thrown.
A solution to this is to create an interface based on class A and make it a contract. Then your add-in can provide the implementation. Thiw way you will not lose versioning.
Regards,
Panos
My application allows users to write plugins (implementing IPlugin) that they can instantiate at runtime. On startup a directory of plugin .dlls is parsed, registering all the available plugins information. At runtime a GUI is provided that lets users create instances of any of the plugins. This works fine.
But now I see MEF and hope I can do the same, but in a more elegant way codewise.
What I got working so far with MEF: on startup I am doing an import of all plugins in a directory (that export IPlugin) and read out the information like name, category, author, etc... These are encoded as exported metadata attributes to the plugin classes. The import is done lazyly so all the plugins are not instantiated on startup, which is important.
The problem is that now I don't see a way to elegantly instantiate a selected plugin at runtime given the additional complication that the plugins constructor is an importing constructor which is importing a reference to an IPluginHost (which it needs immediately to do some initialization).
Together with a plugininfo I save the respective Export in a dictionary during startup, so when the GUI asks to instantiate a plugin given a specific plugininfo I have access to the Export (where Export.Value is my actual IPlugin). But from there how can I create an instance of the plugin and have it composed with the IPluginHost?
I gather I should write my own ExportProvider that serves the IPluginHost whenever someone asks for it, but I don't have access to the assembly or the type of the specific plugin that would let me add it to a Catalog, add the catalog and ExportProvider to a container and call .ComposeParts on that container.
I hope I made my problem clear, if not, let me try a short version of the question:
isn't it a standard usecase for MEF to have a program that lazy-loads plugins on startup to parse the available plugins infos and then at runtime create specific instances given specific plugininfos? would be great to get a codeoutline of the steps involved.
If I understand correctly, you are looking for a way to dynamically create multiple plugin instances, potentially of the same plugin.
You need to declare an import of the type ExportFactory<IPlugin,IPluginMetadata> and then select the correct factory based on the metadata. ExportFactory.CreateExport will take care of any imports required by the IPlugin instances, like the IPluginHost you mentioned.
Note that ExportFactory was only in the silverlight edition of MEF in earlier releases. To get it in the desktop edition, you currently need the latest version from codeplex (MEF 2 - Preview 1). There is also a known problem with importing ExportFactory via the constructor, so use a property.
Have you created a CompositionContainer yet? You can use it to request particular plugin types and get them instantiated. The catalogs will get you part of the way there. You can aggregate multiple catalogs (using the AggregateCatalog) then pass the result to the constructor of the CompositionContainer. When you request your specific IPlugin Type (just keep track of the Type of the export) and you can ask the CompositionContainer to instantiate the plugin for you and it will do the constructor injection for you automatically.