I am using MEF and my plugin directory is c:\dev\plugins
I have a form, but when I open it up, I have the following error:
The composition produced a single composition error. The root cause is provided below. Review the CompositionException.Errors property for more detailed information. 1) The export 'Helper (ContractName="IHelper")' is not assignable to type 'IHelper'. Resulting in: Cannot set import 'helper (ContractName="IHelper")' on part 'Manager'. Element: helper (ContractName="IHelper") --> Manager`
I have two assemblies that contain the same exports, but I am using DirectoryCatalog to only load one of them at a time.
This error only seems to show in the designer. When I run the code, I don't get an exception and the app runs fine. The designer does give me the option to Ignore and Continue but I did this once and it failed, so I am holding back.
public class Manager
{
private static readonly Manager instance = new Manager();
public static IHelper Helper { get { return Manager.instance.helper; } }
[Import(typeof(IHelper))]
internal IHelper helper { get; set; }
private Manager()
{
using (DirectoryCatalog catalog =
new DirectoryCatalog(#"c:\dev\plugins"))
{
using (CompositionContainer container =
new CompositionContainer(catalog))
{
container.ComposeParts(this);
}
}
}
}
public interface IHelper
{
string LabelText { get; }
}
[Export(typeof(IHelper))]
public class SpecificHelper : IHelper
{
public string LabelText
{
get { return "Id:"};
}
}
Related
I'm pretty new to Specflow and C#, so I'm facing an issue with specflow hooks.
The problem is: when I use [BeforeScenario], the method is not even called while debugging.
Removing these hooks and replacing it by [TestInitialize], it works perfectly.
I searched here for solution in many questions, but I didn't find any problem besides something about private methods, which not seems to be my case.
I have 4 classes: Tests, Steps, PageObjects, and Hooks (which contains driver and hooks).
'Tests' class inherits from 'Steps', which inherits from 'PageObjects', which inherits from 'Hooks'.
Every call is public and I'm writing down some code from 'Hooks' class:
namespace AutomationPractice.Helper
{
[Binding]
public class Hooks
{
public IWebDriver _driver;
[BeforeFeature]
public void BeforeScenario()
{
if (_driver == null)
{
_driver = new ChromeDriver();
}
else { throw new Exception("Couldn't initialize the driver"); }
}
[AfterFeature]
public void AfterScenario()
{
if (_driver != null)
{
_driver.Quit();
}
else throw new Exception("There was an error while trying to close the driver");
}
}
}
'PageObjects' class:
namespace AutomationPractice.PageObjects
{
[Binding]
public class GoogleSearchPageObjects : Hooks
{
public string goToGooglePage(string url)
{
return _driver.Url = url;
}
public IWebElement GetTxtSearch()
{
return _driver.FindElement(By.Name("q"));
}
public void fillTxtSearch(string search)
{
GetTxtSearch().SendKeys(search);
}
}
}
'Steps' class:
namespace AutomationPractice.Steps
{
[Binding]
public class GoogleSearchSteps : GoogleSearchPageObjects
{
[Given(#"I am on google home page")]
public void GivenIAmOnGoogleHomePage(string url)
{
goToGooglePage(url);
}
[When(#"I fill the '(.*)' field")]
public void WhenIFillTheField(string search)
{
fillTxtSearch(search);
}
Every class is rounded by [Binding] though.
Thanks in advance!
You have too many things going on in the same class hierarchy. It would be much simpler to decouple the following things:
The Web Driver
The page objects
Step definitions
You can use SpecFlow's dependency injection framework to wire these things together using constructor arguments.
First your Hooks class where you manage the web driver instance for all step definitions and page objects:
[Binding]
public class Hooks
{
private IObjectContainer container;
public Hooks(IObjectContainer container)
{
this.container = container;
}
[BeforeScenario]
public void CreateWebDriver()
{
var driver = new ChromeDriver();
container.RegisterInstanceAs<IWebDriver>(driver);
}
[AfterScenario]
public void DestroyWebDriver()
{
var driver = container.Resolve<IWebDriver>();
driver.Quit();
driver.Dispose();
}
}
And the google search page object becomes a separate class that receives a web driver object as a constructor parameter, which decouples it from SpecFlow all together.
public class GoogleSearchPage
{
private readonly IWebDriver driver;
private IWebElement TxtSearch => driver.FindElement(By.Name("q"));
public GoogleSearchPage(IWebDriver driver)
{
this.driver = driver;
}
public void EnterSearchTerm(string searchTerm)
{
TxtSearch.SendKeys(searchTerm);
}
}
And finally the step definition class, which is where everything gets wired together via the dependency injection framework that comes with SpecFlow:
[Binding]
public class GoogleSearchSteps
{
private GoogleSearchPage googleSearch;
public GoogleSearchSteps(IWebDriver driver)
{
googleSearch = new GoogleSearchPage(driver);
}
[When(#"I fill the '(.*)' field")]
public void WhenIFillTheField(string search)
{
googleSearch.EnterSearchTerm(search);
}
}
Part of the problem you have right now is the class hierarchy. You are mixing classes that should be separated, but coordinated. By separating the step definitions from the initialization of the web driver, and keeping the page object in its own class you keep the dependencies between these objects organized and limited to exactly what they need (decoupling), and yet still allow them to work together (cohesion).
Your methods are names BeforeScenario and AfterScenario, but you are using the attributes for BeforeFeature and AfterFeature.
These have to be static that they will be called.
You need to change the attributes.
I'm having a little trouble wrapping my head around the Ninject Factory Extension.
I have the following class structure
public class Resource
{
public IResourceLoader ResourceLoader {get;set;}
public Resource(IResourceLoader ResourceLoader)
{
this.ResourceLoader = ResourceLoader ;
}
}
public class Banner : Resource
{
public Banner([Named("pngLoader")] IResourceLoader ResourceLoader)
:base(ResourceLoader)
{ }
}
public class MetaData : Resource
{
public MetaData ([Named("xmlLoader") IResourceLoader ResourceLoader)
:base(ResourceLoader)
{ }
}
interface IResourceLoader
{
object resource {get;}
}
public class XMLLoader : IResourceLoader
{
public resource { return "this was sent by xml loader"; }
}
public class PNGLoader : IResourceLoader
{
public resource { return "this was sent by png loader"; }
}
I'm trying to implement convention based filtering based on the Named attribute as show here. So I implemented the following interface.
interface IResourceLoaderFactory
{
IResourceLoader GetxmlLoader();
IResourceLoader GetpngLoader()
}
And then my bindings in the dependency resolver look like
kernel.Bind<IResourceLoader>().To<XMLLoader>().NamedLikeFactoryMethod((IResourceLoaderFactory f) => f.GetxmlLoader());
kernel.Bind<IResourceLoader>().To<PNGLoader>().NamedLikeFactoryMethod((IResourceLoaderFactory f) => f.GetpngLoader());
Assuming the above is correct, I don't know how to proceed to have it so that Ninject gives Banner or MetaData the correct IResourceLoader based on the [Named] in the constructor that it passes it to the base constructor.
I'm using all of this in an mvc 5 application like
public class HomeController
{
public ActionResult Index(/* do banners and meta need to be asked for here? */)
{
/* or do I need to instantiate them here/? */
Banner banner = new Banner(/* what to put here? */);
Meta meta = new Meta(/* what to put here? */);
...
}
}
Thanks
Let me try to answer your question, i'm not a 100% sure i've understand your question correctly, so please give me feedback if i haven't.
Now, your basic problem is that you want to inject an IResourceLoader - but depending on what you inject it into, it should either be an XMLLoader or a PNGLoader.
You've correctly identified named bindings as one possible solution for choosing the appropriate IResourceLoader.
However, you don't need to combine NamedLikeFactory and [Named]-Attribute pattern to achieve what you want, one of those is enough, and here the [Named]-Attribute is probably the better alternative of the two (there is a third which i'll get to later).
So here's what you do:
public const string XmlLoaderName = "XmlLoader";
public const string PngLoaderName = "PngLoader";
Bind<IResourceLoader>().To<XMLLoader>()
.Named(XmlLoaderName);
Bind<IResourceLoader>().To<PNGLoader>()
.Named(PngLoaderName);
And then you specify the appropriate type in the ctor (as you did):
public class Banner : Resource
{
public Banner([Named(pngLoaderName)] IResourceLoader ResourceLoader)
:base(ResourceLoader)
{ }
}
public class MetaData : Resource
{
public MetaData ([Named(xmlLoaderName) IResourceLoader ResourceLoader)
:base(ResourceLoader)
{ }
}
and that's basically it!
now to use it in your controller all you've got to do is:
public class HomeController
{
public HomeController(Banner baner, MetaData metaData)
{
...
}
}
no need to use a factory. Except, in case you need to instantiate a Banner orMetaData instance per request, in which case you would create a factory interface:
public interface IResourceFactory
{
Banner CreateBanner();
MetaData CreateMetaData();
}
which is bound like:
Bind<IResourceFactory>().ToFactory();
// ToFactory is an extension method from Ninject.Extensions.Factory
which will be used like:
public class HomeController
{
private readonly IResourceFactory resourceFactory;
public HomeController(IResourceFactory resourceFactory)
{
this.resourceFactory = resourceFactory;
}
public ActionResult Index()
{
var banner = this.resourceFactory.CreateBanner();
....
}
}
Alternative for Named binding: You could also use a conditional binding like:
Bind<IResourceLoader>().To<XMLLoader>()
.WhenInjectedInto<Banner>();
and corresponding Banner ctor:
public Banner(IResourceLoader resourceLoader)
{
...
}
This alternative can make sense if there's a very limited set of classes which get a ResourceLoader injected. Or if you can't add an [Named]-Attribute to the ctor (for example because it's a third party library...).
Another alternative altogether again would be to give Ninject more information on how to construct a type. For Example:
Bind<Banner>().ToSelf()
.WithConstructorArgument(
typeof(IResourceLoader),
ctx => ctx.Kernel.Get<XmlLoader>());
I have built a modular program using
http://www.codeproject.com/Articles/258681/Windows-Forms-Modular-App-using-MEF as a base and I have several of my modules working.
It is a MDI Windows Forms application and I need to call back to the host module for some stuff.
a) Location information for the MDI host window
b) Write to the status bar in the host window.
I have managed to get the application to compile but when I call the host functions it always gives me a null exception
I did look at Using MEF with C#, how do I call methods on the host, from the plugin?
which is where I got my line
public Exec.Core.Interfaces.IHost Host;
But host is always null so I get exceptions trying to access the members of MDIForm which is the host.
Even if I do public Exec.Core.Interfaces.IHost Host {get;set;}
This is the Host.
NameSpace Exec
{
[Export(typeof(Exec.Core.Interfaces.IHost))]
// MDIForm is the host.
public partial class MDIForm : Form, Exec.Core.Interfaces.IHost
{
///other stuff not related to the problem
// defined in public interface IHost
public Point myLocation()
{
return this.Location; // need the window location
}
// defined in public interface IHost
public IHost GetHost()
{ // is this what GetHost Should Return? Not sure
return this;
}
// defined in public interface IHost
public void SendMessage(string message)
{
SetStatusBar(message); // print a message to MDIForm status bar
}
}
}
Then is the IHosts.cs
namespace Exec.Core.Interfaces
{
public interface IHost
{
IHost GetHost();
void SendMessage(string message);
Point myLocation();
// MDIForm GetThis( ); /* this gives error. Can't resolve MDIForm
I don't know why and can't resolve.*/
}
}
This is one of the modules where I am trying to get stuff from the host
namespace Exec.Modules.Tasks
{
[Export]
public partial class frmTasks : Form
{
[Import(typeof (Exec.Core.Interfaces.IHost))]
public Exec.Core.Interfaces.IHost Host;
// unfortunately Host == NULL at this point
private void SendMessage (string message)
{
try
{
Host.SendMessage(message); <Throws System.NullReferenceException
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
private IHost WhichHost()
{
try
{ /// not really sure what will be returned here
return GetHost();<Throws System.NullReferenceException
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
private Point Location()
{
try
{
return mylocation(); <Throws System.NullReferenceException
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
}
}
And finally this is how I put all of the objects together in ModuleHandler.cs
This is pretty much taken from the codeproject above with some seperation of some method calls into 2 pieces so I could see why it was dying.
namespace Exec.Core
{
[Export(typeof(IModuleHandler))]
public class ModuleHandler : IDisposable, IModuleHandler
{
[ImportMany(typeof(IModule), AllowRecomposition = true)]
// The ModuleList will be filled with the imported modules
public List<Lazy<IModule, IModuleAttribute>> ModuleList
{ get; set; }
[ImportMany(typeof(IMenu), AllowRecomposition = true)]
// The MenuList will be filled with the imported Menus
public List<Lazy<IMenu, IModuleAttribute>> MenuList { get; set; }
[Import(typeof(IHost))]
// The imported host form
public IHost Host { get; set; }
AggregateCatalog catalog = new AggregateCatalog();
public void InitializeModules()
{
// Create a new instance of ModuleList
ModuleList = new List<Lazy<IModule, IModuleAttribute>>();
// Create a new instance of MenuList
MenuList = new List<Lazy<IMenu, IModuleAttribute>>();
// Foreach path in the main app App.Config
foreach (var s in ConfigurationManager.AppSettings.AllKeys)
{
if (s.StartsWith("Path"))
{
// Create a new DirectoryCatalog with the path loaded from the App.Config
DirectoryCatalog cataloglist = new DirectoryCatalog(ConfigurationManager.AppSettings[s], "jobexe*.dll");
catalog.Catalogs.Add(cataloglist);
}
}
// Create a new catalog from the main app, to get the Host
catalog.Catalogs.Add( new AssemblyCatalog(System.Reflection.Assembly.GetCallingAssembly()));
// Create a new catalog from the ModularWinApp.Core
DirectoryCatalog catalogExecAssembly = new DirectoryCatalog( System.IO.Path.GetDirectoryName(
System.Reflection.Assembly.GetExecutingAssembly().Location ), "exe*.dll");
catalog.Catalogs.Add(catalogExecAssembly);
// Create the CompositionContainer
CompositionContainer cc = new CompositionContainer(catalog);
try
{
cc.ComposeParts(this);
}
catch (ReflectionTypeLoadException e)
{ MessageBox.Show(e.ToString()); }
catch (ChangeRejectedException e)
{ MessageBox.Show(e.ToString()); }
}
}
}
So again, the modules work independently but are unable to call back to the host. Wondering what I am doing wrong.
Thanks in advance for any help
One final thing that may have something to do with the issue.
Here is the code that starts the program
public static ModuleHandler _modHandler = new ModuleHandler();
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//Initialize the modules. Now the modules will be loaded.
_modHandler.InitializeModules();
// this goes straight to class MDIForm() constructor
Application.Run(_modHandler.Host as Form);
}
Colin
You instantiate your ModuleHandler manually and then call InitializeModules, where a catalog is created and passed to a new composition container. Then, this container is used to satisfy all the imports of that particular ModuleHandler instance through the line:
cc.ComposeParts(this);
This tells MEF to look for Import attributes and populate the decorated properties with instances of classes decorated with the corresponding Export attributes.
What you are missing is the analogous call to populate your frmTasks objects. Thus, the following Import is not satisfied and the property is null:
[Import(typeof (Exec.Core.Interfaces.IHost))]
public Exec.Core.Interfaces.IHost Host;
You have several options among which I'd look into the following two:
Modify the IModule interface so that you can explicitly pass an IHost to the modules. Then, in the InitializeModules, after the call to ComposeParts, iterate over the composed modules passing them the host instance. This accounts for setting the Host property through the IModule interface. You could also stick to the MEF imported property by putting it in the IModule interface and calling ComposeParts for each module instance.
Expose the container through a ServiceLocator and get the IModuleHandler instance from the modules to access the Host property.
I have an answer, I just don't think its the right one.
On my question I edited it and added the main program but i did not add its class.
It looks like
namespace Exec
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
///
//Create a new instance of ModuleHandler. Only one must exist.
public static ModuleHandler _modHandler = new ModuleHandler();
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//Initialize the modules. Now the modules will be loaded.
_modHandler.InitializeModules();
Application.Run(_modHandler.Host as Form);
}
}
}
I was debugging and I found that in _modHandler.InitializeModules();
IHost Host was set, and its part of
public static ModuleHandler _modHandler = new ModuleHandler();
and everything here is static but not accessable. So I changed the class signature to public to make it global (dirty word I know)
public static class Program
and then in
namespace Exec.Modules.Tasks
in the Load_Form event I added a line to initialize Host.
public partial class frmTasks : Form
{
[Import(typeof (Exec.Core.Interfaces.IHost))]
public Exec.Core.Interfaces.IHost Host;
private void Load_Form(object sender, EventArgs e)
{
Host = Program._modHandler.Host.GetHost; << added this to initialize host
other stuff....
}
other stuff that now works
}
I don't think that this is how its supposed to work. I think that I should be able to populate this through the interfaces and modules...
Comments?
I've recently looked into using MEF in order to build a plugin framework and also read quite a few articles and followed tutorials however what I'm attempting to achieve (and i haven't seen an example of this yet) is to provide an access point so i can load plugins from a set directory at the point of (for example) form loads, in order to alter the controls or prevent load ect or another example would be button clicks in order to extent or once again prevent standard functionality from taking place. Could anyone point me in the direction of other resources or provide a simple example explaining how this could be accomplished?
TIA
This is a simple implementation example. First add the reference System.ComponentModel.Composition to the project.
Declare the Plugin interface:
[InheritedExport]
public interface IPlugin
{
string Name { get; }
}
In the same or another assembly, implement the bellow interface.
public class Plugin1 : IPlugin
{
public string Name
{
get { return "Plugin#1"; }
}
}
Later build your Catalog using DirectoryCatalog and AssemblyCatalog.
public class CatalogManager : IDisposable
{
[ImportMany(typeof (IPlugin), AllowRecomposition = true)]
private IEnumerable<IPlugin> _plugins;
private CompositionContainer _container;
public CompositionContainer Container
{
get { return _container; }
}
public IEnumerable<IPlugin> Plugins
{
set { _plugins = value; }
}
private CatalogManager(string pluginsDir)
{
var catalog = new AggregateCatalog();
//--load all plugin from plugin directory
if (Directory.Exists(pluginsDir))
catalog.Catalogs.Add(new DirectoryCatalog(pluginsDir));
//--load all plugin from executing assembly
catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
Initialize(catalog);
}
private void Initialize(AggregateCatalog catalog)
{
_container = new CompositionContainer(catalog);
_container.ComposeParts(this);
}
public void Dispose()
{
if (_container == null)
return;
_container.Dispose();
_container = null;
}
}
In our prism application we need to load a module to the centre pane when the user clicks an item in a tree(seperate module). The module in the centre pane(say designer module) can open a file and display itself if it is given a path. How can I pass the path of the file to this module?
For example
in Designer module
public DesignerViewModel(DataAccess dataAccess)// This will be injected
{
}
//The following class can create the model objects using the IDataService for getting data from remote location
public DataAccess(IDataService service)//this will be injected
{
}
The data access object is local to the Designer module, so I wouldnt like to expose it to outside the module. So the registration is done in the module
public class DesignerModule : IModule
{
public void Initialize()
{
var container = ServiceLocator.Current.GetInstance<IUnityContainer>();
container.RegisterType<Object, DesignerView>("DesignerUI");
container.RegisterType<DataAccess>();
}
}
IDataService is registered in the application level
public class BootStrapper : UnityBootstrapper
{
protected override void ConfigureContainer()
{
base.ConfigureContainer();
Container.RegisterType<IDataService, DataService>();
}
}
Note that IDataService is a singleton for the entire app. I cannot pass the path of file which is specific to a module instance in IDataService. Note that you can open any number of modules in the centre pane as you like, just click on a tree item->tree will fire an event with the selected item id->app will find out a path corresponding to the item id and invoke the module.
How will I pass the path when I say _regionManager.AddToRegion("CenterRegion", DesignerModule); Prism will do all the dependency injections beautifully, but how to pass the path is a big question?
You can use EventAggregator to exchange with messages beetwen modules.
Each module subscribe to EventAggregator.
While you open a module you can send to host control notification about newborn.
Host control send response back with initialization data.
public class MessageEvent : CompositePresentationEvent<Message>{}
internal class MessageReceiver
{
private readonly MessageEvent _evt;
private readonly string _myId = Guid.NewGuid().ToString();
internal MessageReceiver(IEventAggregator eventAggregator)
{
_evt = eventAggregator.GetEvent<MessageEvent>();
_evt.Subscribe(Receive, true);
_evt.Publish(new Message { Source = _myId, Command = Message.Commands.WhoIAm });
}
public void Receive(Message message)
{
switch (message.Command)
{
case Message.Commands.WhoIAm:
_evt.Publish(
new Message
{
Destination = message.Source,
Command = Message.Commands.Initialize,
MessageData = Encoding.UTF8.GetBytes("init data")
});
break;
case Message.Commands.Initialize:
if (message.Destination == _myId)
{
//init
}
break;
}
}
}
public class Message
{
public enum Commands { Initialize, WhoIAm }
public string Source { get; set; }
public string Destination { get; set; }
public Commands Command { get; set; }
public byte[] MessageData { get; set; }
}
I found out the answer from my colleague.The parameters can be overriden with your own objects when you call Resolve(). So create the object which is going to be injected, populate it and pass with the Resolve<>() with ParameterOverride. Search for ParameterOverride in google for more information.