In one of the applications I am working on, there are two basic functionalities included: Create and Update.
However, there is a need sometimes to add custom code, so I thought of extending the code by allowing 3rd parties to write and embed their own code:
OnCreating
OnCreated
OnUpdating
OnUpdated
Is there a way to enable the above across multiple assemblies? MEF might help here?
Thank you
Regards
Thanks all for your replies.
Having such an interface means each external assembly has to implement that interface as needed. Then, my application's code, needs to loop through the currently running assemblies, detect all classes implementing that interface, and run their methods?
Does MEF fit here? I can export the implementation from external assemblies and import them inside my app?
Thank you
Regards
You can't have partical classes accross assemblies because partial classes are a language feature, and not a CLR feature. The C# compiler merges all the partial classes into one real class, and that single class the the only thing left after compilation.
You have a couple of alternatives:
Offer events
Make the methods virtual and override them
Use an interface
Your problem looks like it fits events best. The user can simply subscribe to them in the other assembly.
Regarding your MEF question, you could probably do something like the following to run methods from an interface:
var catalog = new DirectoryCatalog("bin");
var container = new CompositionContainer(catalog);
container.ComposeParts();
var plugins = container.GetExportedValues<IPlugin>();
foreach (IPlugin plugin in plugins)
{
plugin.OnCreating();
}
Or create an interface with events as Brian Mains suggested:
public interface IPlugin
{
event OnCreatingEventHandler OnCreating;
}
then the above code would be more like:
var catalog = new DirectoryCatalog("bin");
var container = new CompositionContainer(catalog);
container.ComposeParts();
var plugins = container.GetExportedValues<IPlugin>();
foreach (IPlugin plugin in plugins)
{
plugin.OnCreating += MyOnCreatingHandler;
}
I think I like the latter for the method names you specified. For my plugin work, I've created an interface similar to the following:
public interface IPlugin
{
void Setup();
void RegisterEntities();
void SeedFactoryData();
}
The RegisterEntities() method extends the database schema at runtime, and the SeedFactoryData() method adds any default data (eg. adding default user, pre-population of Cities table, etc.).
Having partial classes supported across assemblies isn't supported.
The reason being that all partial class definitions are combined into a single class during compile time. That single class resides in a single assembly.
Consider using an interface:
IUpdatableObject<X>
Creating(X obj);
Created(X obj);
Updating(X obj);
Updated(X obj);
And then use this interface to add in custom code; each third party can implement this interface (well either they or you can through a wrapper) and this can be a tie into adding custom business logic.
HTH.
You (or the user) can use extension methods:
http://msdn.microsoft.com/en-us/library/bb383977.aspx
Partial methods and classes must be in the same assembly. Partial methods are compiled out if not used. If you need extension points for you classes you should look into virtual methods or events.
Partial classes across assemblies aren't supported because the concept behind the partial class is to allow multiple developers to contribute different methods and members for the same class under a particular namespace.
This was done in order to help developers to sync the code into a single class, inside one assembly, build after compilation.
Related
I have built a plugin system, where I can dynamically load classes into my application (IModule is an interface, so I know the plugin will behave correctly):
var dll = Assembly.LoadFile("path/to/a/dll");
foreach (Type t in dll.GetExportedTypes()) {
if (typeof(IModule).IsAssignableFrom(t)) {
IModule mod = (IModule)Activator.CreateInstance(t);
}
}
So, from my "main" application, I can get and instantiate classes in my plugin. What I would like now, is to be able to get to the classes of the "main" application, from the plugin.
I tried using Type.GetType("NameOfClass"), but that returns null.
This is bound to turn ugly if you need to do it without altering the main module at all, which turns out to be the case. So the following suggestion is a kludge, but I think a kludge may be the best you can hope for in this case.
The static method Assembly.GetCallingAssembly() will return the assembly that called the method you're currently in, so one thing you could do is find a place where the main module directly calls some method M of the plugin modules. Fingers crossed, maybe there's some kind of initializer method that gets called early on.
In M, call Assembly.GetCallingAssembly() and stuff the result in some static field that you can use later to create instances of classes that are defined in the main module.
I think you misunderstood plugin-like concept. You should implement API library which purpose will be to store public plugin interfaces. Those interfaces you will be using in your plugins, and just instantiate your classes through some IoC framework. For example, you can use Ninject:
public class MyPlugin : IModule
{
public MyPlugin(MainApp.API.IMainAppInterface instance)
{
//do something with it.
}
}
public class MyPluginModule: NinjectModule
{
protected override void Load(IKernel kernel)
{
kernel.Bind<MyPlugin>().To<IModule>();
}
}
And in your main application you just load those modules from some folder.
I am writing a project which will encapsulate multiple Calendar APIs (Google Calendar, Outlook ect) in one service. This will allow me to integrate different APIs which can be mapped to our domain model. However I am having issues with required dependencies spilling over into other projects. Here's an example:
I have created a generic class which does most of the work and conversions from the API model to our model. Here's an example:
public abstract class CalendarAPIBase<TEventType> : ICalendarAPI
{
public CalendarEvent Get(string id)
{
if (string.IsNullOrEmpty(id))
throw new ArgumentNullException("id");
return Convert(GetEvent(id));
}
public List<CalendarEvent> GetAll()
{
List<CalendarEvent> result = new List<CalendarEvent>();
List<TEventType> es = GetAllEvents();
foreach (TEventType e in es)
result.Add(Convert(e));
return result;
}
protected abstract List<TEventType> GetAllEvents();
protected abstract CalendarEvent Convert(TEventType obj);
//More stuff below.
}
So this is a beautiful thing, anything that inherits CalendarAPIBase doesn't have to do much work other than getting the data from the API, the base class will handle the conversions.
Ok, so here's where things go wrong. I have created a GoogleCalendarAPI class, which inherits from CalendarAPIBase. It passes in the Event class, which belongs to a NuGet package Google.Apis.Calendar.v3.
public class GoogleCalendarAPI : CalendarAPIBase<Event>
The problem here is that this class is exposing the Event class, therefore anything that references this project will also need to reference Google.Apis.Calendar.v3. Ideally anyone wishing to use this service will only have to reference just the project and not have to worry about installing other NuGet packages.
How can I restructure my classes to prevent this from happening?
The most straightforward way to resolve this stuff is an Abstract factory pattern.
First, you make CalendarAPIBase<TEventType> and all its descendants internal. All the public stuff has to be concentrated within a public ICalendarAPI interface.
Next step is introducing public classes like this:
public static class GoogleCalendarAPIFactory
{
public static ICalendarAPI Instantiate( ....... )
{
.......
return new GoogleCalendarAPI( ..... );
}
}
The factory will make all the TEventType hassle hidden ftom the library user, therefore he will not need to add all the packages containing TEventType implementations.
I'm not sure if you can avoid referencing 3rd party assemblies if you use classes like Google.Apis.Calendar.v3.Event directly in your code.
However, you can use ILMerge to merge 3rd party API into your own, that way the dependencies of your assemblies will be deployed along with your assemblies.
I usually use ILMerge in the post build event.
For example:
After GoogleCalendarAPI project is built, merge GoogleCalendarAPI.dll and Google.Apis.Calendar.v3.dll and save it in "GoogleCalendarAPI_location\mergerd\GoogleCalendarAPI.dll"
Copy "GoogleCalendarAPI_location\mergerd\GoogleCalendarAPI.dll" to the location of the original GoogleCalendarAPI.dll and replace it.
Now you've got GoogleCalendarAPI.dll with Google.Apis.Calendar.v3 baked into it.
Now every assembly that references GoogleCalendarAPI.dll gets both.
I was thinking about designing a proper contract for future plugins creation for an application I'm currently working on. Basically the idea is to define an interface, but I want the application to be aware of plugins that currently presented to the system and to show the user a nice list of plugins with their names and a brief descriptions which ofcourse the developer of the plugin should provide, the user of the application shouldn't be able to alter this easily so an additional config file is not an option. I don't want to use the class name of filename of the assembly for this. Also I think that it should be accessable without instantiating the plugin, but maybe through reflection, something like: assembly.GetType(type).GetProperty("Name").GetValue(null, null).ToString();. Ofcourse I could provide some logic to check for existance something like if(assembly.GetType(type).GetProperty("Name") != null), but this is not a good idea either, because if the property does not exist the end user won't have an idea of what that plugin does, not even what it's name is.
Now, it should behave like a static property, but static is not overridable so it seems that I cannot declare it as a part of an interface nor in an abstract class. Maybe I'm on wrong way, and it only looks like a static property and I can achive this functionality through another approach. So the brief question might be "How to enforce the third party developer to provide some meta information about his plugin". Please advise.
You could try with two interfaces:
IAddIn for be the main interface that all add-ins will implement.
IAddInInfo for be the interface providing the metadata of the add-in (name, publisher, description version etc.)
Each add-in should implement both of these. An IAddInInfo implementation could be like this:
public class ScannerAddInInfo : IAddInInfo
{
public string Name { get { return "Scanner"; } }
public string Description { get { return "Add-in for acquiring images from a scanner device"; } }
}
To ensure that all implementations of add-ins come with metadata, you can make IAddIn a generic interface like:
public interface IAddIn<T> where T : IAddInInfo
{
T Info { get; }
//Continue with the rest of the members you would want every add-in to have.
}
Then the scanner add-in implementation would be:
public class ScannAddIn : IAddIn<ScannerAddInInfo>
{
private ScannerAddInInfo _info = new ScannerAddInInfo();
public ScannerAddInInfo Info { get { return _info; } }
//Continue with the rest of the IAddIn implementation.
}
Then you could load the add-in assembly from a special add-in folder and create instances of the types implementing IAddInInfo and show the info from the discovered add-ins in your application. Note that no add-ins are created yet. To do so you will need to add some more reflection to find the types implementing IAddIn<ScannerAddInInfo>.
To make this simpler you could add the add-in type name to the IAddInInfo interface or something like that.
The only drawback to this approach is that you will have to load all assemblies found in your special add-in folder even if they do not include any add-ins.
To avoid this you could try Mono.Cecil. You then will have to do something like this:
AssemblyDefinition ad = AssemblyDefinition.ReadAssembly(assemblyPath);
foreach (TypeDefinition td in ad.MainModule.GetTypes())
{
if (td.BaseType != null && td.BaseType.FullName == "MyNamespace.MyAddInBase")
{
return true;
}
}
To load the assemblies you can use Assembly.LoadForm and to create instances of the add-ins and add-in infos, one of the Activator.CreateInstance overloads.
Good luck.
To add some 'meta data' to your plugins, you can use attributes. Create a custom attribute for your plugins and read out the information with reflection and show it in your application.
More info about attributes:
Creating Custom Attributes (C# and Visual Basic)
Accessing Attributes by Using Reflection
The thing you should do is basically define your interface and expect other people to implement their concrete classes and give that runtime object to you somehow (your predefined methods, configuration etc.)
But there is some mechanism called dependency injection. That allows you to define your interface and your entry points while a "system" takes care of matchmaking your entry points and implementers' concretes. There is "System.ComponentModel.Composition" namespace for this purpose.
I knew there was a framework called "Unity" doing such job. I guess composition namespace is somewhat a simplified version of unity. You can check help for "ImportAttribute" and "ExportAttribute" classes for some cue.
I used the OWLGrinder to create the assembly and imported the library into my project. That works fine. Now I want to write my own set of classes. Therefore I extended these with the equivalent of the assembly. But it just doesn't work.
The ontology holds a class named ManagementObject.
I created another Class (C#) called RealWorldObject:
public class RealWorldObject : ManagementObject
{
public RealWorldObject(string uri) : base(uri) { }
public RealWorldObject(string uri, RdfDocument rdfdocument) : base(uri, rdfdocument) { }
public RealWorldObject(RdfDocument rdfdocument) : base(rdfdocument) { }
public String getClassName()
{
return this.OwlClassName;
}
public static RdfDocument addRealWorldObjectIndividualt(RdfDocument rdfDocument)
{
Vehicle vehicle = new Vehicle("vehicle1", rdfDocument);
FixedEvent fxE1 = new FixedEvent("autoGekauft", rdfDocument);
fxE1.agent = new xmlns.com.foaf._01.Person("robert", rdfDocument);
vehicle.hasFixedEvent = fxE1;
return rdfDocument;
}
Which leads to the error:
ObjectManagement.Object.RealWorldObject does declare one (and only one) OwlClassAttribute. This is an implementation bug of the plugin.
How else should I extend the generated classes by the OWLGrinder.
Thx it is a long time ago that I used C#, so I'm kind of rusty.
The auto-generated classes produced by OwlGrinder.exe have not been designed for inheritance in mind. I am not saying it is wrong, it is just not designed for that. The auto-generated classes contain plenty of metadata defined as class attributes and inheritance hides all of that. The infrastructure counts on the presence of these attributes and if they are hidden, you get these runtime error messages.
Using Visual Studio Object Browser, take a look of the attributes over the auto-generated classes. OwlClassAttribute, SubClassOfAttribute, LightVersionAttribute are certainly mandatory. You may simply copy/paste the class attributes of ManagementObject on the top of your RealWorldObject class. I assume, it will work. But again, you might bump into additional show stoppers, as you do not follow the default routes ROWLEX has been designed for. This is a bit living on the edge :)
Instead of inheritance, you might consider reverse engineering your auto-generated assembly to C# using Reflector or other tools. Having the source code in your hand, you may modify the generated classes directly. You might make your ManagementObject class partial, and implement your additional methods in a separate file.
I'm having a conundrum here, and I'm not even sure it's possible.
I'm developing a pluginbased application, where all the plugins will have access (read/write) to a shared configuration on the host application. There are easier ways of achieving the problem I'm presenting, but since this is a non-work related project, I'm free to play around :)
Let's say we have Plugin_A that is inheriting a PluginBase abstract class. The abstract class exposes a IConfiguration Config property that can be accessed by the plugin to write to this shared configuration. The IConfiguration Config is set properly by the host upon loading the plugin, to limit the available configuration that particular plugin will access.
What I would like to do is try and use the Dynamic keyword in C# 4.0 to seamlessly write the config-class.
in pseudo C# code here's what I would like to achieve
public class Plugin_A: PluginBase
{
public void DoSomethingWithConfig()
{
ShowAMessageBox(Config.SomeMessage);
Config.HasShownMessage = true;
}
}
Now - in this example I don't want to actually define the .SomeMessage and .HasShownMessage but rather have them be dynamic and returned when called upon.
It seems like a stretch, but is this at all possible?
I don't think you want to implement the IDynamicObject interface, I recommend you have Config inherit from DynamicObject instead. You'll want to override TryGetMember and TrySetMember at least for your example. TryInvokeMember will be necessary if you want to dynamically call methods. Implementing the whole interface is much more difficult.
So, your config class(es) will need to inherit DynamicObject and implement IConfiguration. You can then either declare the field as a dynamic item or as IConfiguration objects and cast them dynamic before you want to use their dynamic behaviors.