I have a strategic question for my C#-project. I want to implement a plugin-concept and now struggling with the best way for the plugins to manipulate the data of the main project.
At first I created a "Master" PlugIn Project that defines the Interface for the plugins and an attribute to identify a class as a pluginclass when I load it in my main project.
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public sealed class GraphViewerPlugInAttribute : Attribute
{
}
public interface IGraphViewerPlugIn
{
Panel GetRightSidePanel();
string Name();
}
This project is then referenced in the main project and the pluginclasses. The pluginclass implements the interface ...
[GraphViewerPlugIn]
public class myTestPlugIn : IGraphViewerPlugIn
{
public Panel GetRightSidePanel()
{
Panel myPanel = new Panel();
myPanel.BackColor = System.Drawing.Color.Red;
return myPanel;
}
public string Name()
{
return "TestPlugIn";
}
}
... and the main project loads all plugins that are stored in a certain directory.
This works quite well so far, I can get the special Panel from the PlugIn, but now I want to manipulate data of the main project from within the PlugIn. What would be the best way to do that?
I have some kind of data-container-class that is defined in the "Master Plugin Project" in mind. The plugin puts the data into that container and the main project will be recognized by an event that the data has changed and can now look what data has changed and then apply the changes.
Is that the right direction, what do I have to consider and which techniques (i.e. events, static classes ...) shall I use to implement that?
One approach is to add a configuration button which activates a method on the interface designed for configuration.
This method can make use of any code it would like to configure the plug in, including making it's own calls to windows forms.
If you are using windows forms or winfx, and not a custom UI, this is the ideal method because it removes all logic related to the plugin from the application itself, except for notifcation that a configure window was requested.
public interface IGraphViewerPlugIn
{
Panel GetRightSidePanel();
string Name();
void ShowConfigurationDialog();
}
Of course, you then implement ShowConfigurationDialog as such:
public void ShowConfigurationDialog()
{
Form form = new MyConfigurationDialog();
form.ShowDialog();
}
where MyConfigurationDialog is your designer created form for configuring the plugin.
Related
I am trying to create tools for a game to learn, as well as improve my own playing experience.
The primary .NET assembly, csass.dll, that controls the client is heavily obfuscated, and I have no control over this .dll-file at all and reading it's code is very time consuming. The game also includes a mainapi.dll which handles the communication between server and client. I have full control over this assembly and I can listen to the servers responses and send my own requests, which already gives me some pretty nice functionality, however there are some limitations I'd like to work around.
csass.dll references mainapi.dll, by default mainapi does not reference csass. In csass.dll there is a class, let's call it clickHandler, that has a public, non-static method ClickObj() of return type void. I want to call this method from within mainapi.dll, but I have no idea how to go about this, given that I have to leave csass.dll untouched.
Are there any feasible ways to 'retrieve' a clickHandler object (to then call its ClickObj() method) from within the mainapi assembly, without making any changes in csass.dll? Appreciate any and all input!
Create an interface:
public interface IClickHandler
{
void ClickObject();
}
Now create a helper class implementing that interface:
using CsAss;
public class ObjectClicker : IClickHandler
{
CsAss _csass;
public ObjectClicker(CsAss csass)
{
_csass = csass;
}
public void ClickObject()
{
_csass.clickObject();
}
}
Add a dependency on an instance of the interface into your MainAPI class:
public class MainApi
{
IClickHandler _clickHandler;
public MainApi(IClickHandler clickHandler)
{
_clickHandler = clickHandler;
// Now you have a class that can call the click handler for you
}
}
Now wire it all up:
public void StartupMethod()
{
var csass = new CsAss();
IClickHandler clickHandler = new ObjectClicker(csass);
var main = new MainApi(clickHandler);
// TODO: Start your app now that MainApi is properly configured
}
That last step is the only potentially tricky part, depending on your project layout. You need something that can create an instance of CsAss, MainApi and ObjectClicker. Normally I would solve that with the dependency injection (DI) pattern, either using a framework such as Autofac or so-called "poor man's DI" by manually instantiating from a central startup method. That gets a little more difficult with Unity since there isn't an easily accessible startup point. You could start looking into https://github.com/svermeulen/Zenject and go from there for options.
I have a Winforms application that is designed to integrate with external software packages. This application reads data from these packages and pushes it to our server where users log in and use our application (App).
public abstract ClassToImplement
{
public abstract void DefinedMethod1();
public abstract void DefinedMethod2();
}
When we designed the application it was intended to do 95% of the integration work with the remaining 5% (implementation class / App2) being developed by a consultant who's familiar with the 3rd party software.
public class Implemented : ClassToImplement{
public override void DefinedMethod1(...);
public override void DefinedMethod2(...);
}
The "App" outputs a Class Library which is then referenced in the Implementation (App2). In our design we created an Abstract Class and defined the methods. The idea was that the consultant would download the repo for the implementation class and include the App as a reference. They would then write the necessary code for the methods they're implementing, compile and "voila!"
For obvious reasons I don't want to share the source project with external developers, otherwise I'd just share the full solution and use a single app, and, while I know they can see a lot with the DLL reference, it is just easier for us to control everything.
The problem comes with App: the main application algorithm needs to instantiate the implementation class and then the program runs perfectly.
in Form1.cs of App:
ClassToImplement impObj = new Implemented();
impObj.DefinedMethod1();
impObj.DefinedMethod2();
The challenge I'm having is that I cannot build "App" to output a DLL without instantiating the Class. I cannot instantiate the Implemented Class as I haven't got the code (yet).
It would be great to know how to go about achieving this sort of abstraction with a dependancy on (yet) unwritten code and also, what is the technical term for what I'm trying to do?
To make it just "work" use a Func which returns an instance of the abstract class.
In your secret repo:
//Your "App" DLL Project
public abstract class ClassToImplement
{
public abstract void DefinedMethod1();
public abstract void DefinedMethod2();
}
public class App : Form
{
public App(Func<ClassToImplement> initiator)
{
InitializeComponent();
ClassToImplement ci = initiator.Invoke();
ci.DefinedMethod1();
ci.DefinedMethod2();
}
}
//This is in a separate project which will be your startup project internally
public class Dummy : ClassToImplement
{
public override void DefinedMethod1(){}
public override void DefinedMethod2(){}
}
public class Program
{
public static void Main()
{
Application.Run(new App(()=> new Dummy()));
}
}
In the repo shared with the consultant:
// In the repo which is shared with the consultant
// This will be the startup project on the build server, and when the consultant is testing.
public class Implementation : ClassToImplement
{
public override void DefinedMethod1(){}
public override void DefinedMethod2(){}
}
public class Program
{
public static void Main()
{
Application.Run(new App(()=> new Implementation()));
}
}
On your build server, you can pull from both the repos, and set the startup project as the one given to the consultant. But when you are testing and developing internally, you set the startup project to your version with an implementation that does nothing.
As a side note, if you think what you are doing needs to be protected from consultants who have signed a confidentiality agreement, make sure to obfuscate when you do a release.
This is a two-step process usually:
Locate and load the assembly/dll:
Assembly assembly = Assembly.LoadFrom(DLL);
Instantiate the implemented class:
Type type = assembly.GetType(FullNameOfImplemented);
AppInstance = (ClassToImplement)Activator.CreateInstance(type, parameters);
The process you are looking for is often called stubbing. In this case you've chosen to encapsulate the integration functionality in a library, not web services, but the principle is the same.
The idea was that the consultant would download the repo for the implementation class and include the App as a reference.
This sounds like you've got the dependency relationship the wrong way round. If the consultant's code references your app, then your app can't reference it - it'd be a circular dependency. Instead, factor your app something more in line with the following:
App
|
|
App.Integration.Contracts
^ ^
| |
| App.Integration.Stub
|
App.Integration
The abstract class - it could just as easily be an interface in C# - resides in the Contracts assembly. This is the only compiled dependency your application has. Then at runtime use configuration to load either the stub, or the full implementation using an IoC container. An example is Unity for which you will need its configuration API. Reference the true type to use in the configuration file and change only that to update your application to use the full functionality.
First off I think you need to implement a proper plugin system if you dont want to share your code with that other developers.
Second you should code against your interface and not against its implementation. First because you dont have it and second because you may want to switch implementations for different 3rd party software.
If you need an instance for testing or stuff, you can use a handwritten mock or an mocking framework. If you need a real instance later on (when the other developers have delivered) you can use some design pattern like factory pattern or others for the creation. Try to avoid the new keyword if you want to change implementations later on.
So recently; I refactored Views to their own WPF Application project and I moved my ViewModel classes into their own Class Library project. This worked well for keeping my code in order. Then I realised that I didn't have the comfort of the App.xaml.cs class.
This class (for me) meant that I could declare all sorts of objects and access them application wide.
i.e: In the App.xaml.cs
public partial class App : Application
{
public myDatabaseEntities context { get; set; }
// App.xaml.cs Constructor
public App()
{
context = new myDatabaseEntities();
}
}
In some random View Model:
myDatabaseEntities context = ((App)Application.Current).context;
The above allows me to recylce the instance, and comes in particularly handy with Unity's (IoC container) version of lifetime manager.
Thing is, I'm not sure on how to achieve this behaviour within a class Library project. I'm not sure how to create a class that instantiates at runtime. And I have no clue how to pass that App class instance around to relevant classes. Any ideas on how to do this? Any help would be much appreciated.
Personally, I would keep all the "functionally" related Views and ViewModels together (next to each other). You may want to create class libraries (or modules) based for different functional parts of the application. Also, please refer to this MSDN page on building composite application using WPF and Prism.
Coming to your question, have an interface called IApplication defined something like this:
public interface IApplication
{
MyDatabaseEntities Context { get; }
}
and implement that interface on App class:
public partial class App : Application, IApplication
{
public MyDatabaseEntities Context { get; set; }
// App.xaml.cs Constructor
public App()
{
Context = new MyDatabaseEntities();
}
}
In your App.xaml.cs, as part of bootstrapping your application register this App instance with the container by calling RegisterInstance extension method on Unity container:
Container.RegisterInstance(typeof (IApplication), this, new ContainerControlledLifetimeManager());
Now, if your ViewModels take a dependency on IApplication, then they will have access to your App object and to the Context property via this interface. In future you could expose additional properties like: Dispatcher, Resources, etc from your App object through this interface.
Turns out all I needed was a regular class without the xaml front end. Then inherit the Application class. And lastly set it as the base class for app.xaml.cs. The answer is already here
I am working on developing a plug and play framework in ASP.Net MVC whereby I can define modules as separate projects from the Main project. So, a developer can create as many modules as they want.
What I need is that to be able to update settings of any of such modules. For that, in the main project, I defined a base class for some common settings plus each module has its own custom settings. When there is any edit on a module, I have to instantiate instance of that module in the main project. But, main project has no knowledge of any modules.
How do I achieve this?
Thanks!
You can use dependency injection and inject those modules to your application at composition root. As per configuration you can use code or xml (configuration file). You can do auto wiring, late binding etc depending on what you really need.
You can also have initializers at each module so whenever you register a module, it should initialize your registered modules and inject dependencies etc.
Depending on your need, you would have to create a solution that relies on interfaces.
Essentially, the application exposes an API dll with an interface called IModule. IModule has one method called Run(). Your main application will load up the module's assembly, look for something that implements IModule, makes one of those objects and calls Run() on it.
Here is an old article describing how to host a sandbox to run modules inside.
http://msdn.microsoft.com/en-us/magazine/cc163701.aspx
namespace MyApplication.Api
{
public interface IModule
{
void Run();
}
}
The developer would create something like this
public class MyObject : MarshalByRefObject, IModule
{
public void Run()
{
// do something here
}
}
The application will load it up with some kind of Reflection.
public void LoadModule()
{
var asm = System.Reflection.Assembly.Load(/* Get the developer module name from somewhere*/);
var types = asm.GetExportedTypes();
foreach(var t in types)
{
foreach(var i = t.GetInterfaces())
{
if(i == typeof(IModule))
{
var iModule = System.Activator.CreateInstance(t);
iModule.Run();
}
}
}
}
It would be best if you run the code in another appDomain, but it adds a lot of complexity.
public void LoadModuleInAppDomain()
{
// Spin up a new AppDomain
// Load the assembly into the app domain
// Get the object
// Call the Run Method
}
I am converting a project to Prism/MEF and need to download the list of modules from a central db
however the "list downloader" instance Reference is set to null so assuming the code is not in the right place
Here's the flow
public class Bootstrapper : MefBootstrapper {
[Import]
IMyList sync1 { get; set; }
...
protected override void ConfigureAggregateCatalog() {
**sync1.Sync(); // sync1 is null**
AggregateCatalog.Catalogs.Add(....)
}
...
}
[Export(typeof(IMyList))]
private class DBSync : IMyList {
[Import] IDBConn mydb { get; set; }
public void Sync(){
// connects to mydb and gets a list of auth modules for the current user
}
}
the prob is sync1 iS NULL !! why ?
I know i am doing something wrong but this is my 1st prism project from scratch so pls go easy
You are using sync1 to configure your catalogs. Is it possible you haven't composed your parts yet ?
For Bootstrapper's parts to be compsosed it needs to be instantiated by MEF, for example by using GetExportedValue<>, otherwise IMyList will be null.
If so you will need to change your code so that MEF already has a part for IMyList in it's catalog, and then add additional parts.
If this is not your problem, another possible source of the problem could be a composition error when satisfying one of DBSync imports, ie:
[Import] IDBConn mydb { get; set; }
In this case you should get an exception. You could try running the program in debug while setting the option to break on all Common Language Runtime Exceptions.
EDIT :
If your container is null it won't be able to compose the imports in your bootstrapper class. MEf imports it's components when it instantiate the class. You can't rely on imports being available before the container is created.
You will have to :
Change IMyList sync1 so that's it's not an import anymore.
If you really need to have your IMyList composed by MEF, you will need to create a temporary container (no need to use the MefBootStrapper) and use this temporary container just to compose the parts in your bootstrapper class. You can dispose it afterwards. See this other answer (Satisfy Imports in custom ExportProvider).
I would really recommend going with the first option tough, changing sync1 so it's not an import, unless you have a compelling reason to do so.
As far as I can see you have not exported IMyList. Therefor I think you need to put an export attribute on the line before private class DBCon
I hope this helps...
Nigel...