I've got three projects:
UI
PluginManager
PluginOne
PluginTwo
Inside my Plugin Manager a create a simple plugin interface:
public interface IPlugin<T>
{
void sayMessage(T message);
T createMessage();
}
So, in my other projects I've two IPlugin implementation:
In porject PluginOneProject -->
-------------------------------
public class PluginOne : IPlugin<IntMessage>
{
public void sayMessage(IntMessage message)
{
System.Console.WriteLine(message.ToString());
}
}
where:
public class IntMessage
{
private int message;
public IntMessage(int message)
{
this.message = message;
}
public override string ToString()
{
return this.message.ToString();
}
}
In porject PluginTwoProject -->
-------------------------------
public class PluginTwo : IPlugin<StringMessage>
{
public void sayMessage(StringMessage message)
{
System.Console.WriteLine(message.ToString());
}
}
where:
public class StringMessage
{
private String message;
public StringMessage(String message)
{
this.message = message;
}
public override string ToString()
{
return this.message.ToString();
}
}
Obviously, I've added the corresponding project references.
So, in my UI porject I've NInject, and I perform this convention mapping:
kernel.Bind(b => b.FromAssembliesMatching("*")
.SelectAllClasses()
.InheritedFrom(typeof(IPlugin<>))
.BindAllInterfaces()
);
The graph is built correctly.
So, I don't know how to get an instance of PluginOne, or PluginTwo from UI project.
I'm trying to use this code, however, I've a problem with generic interfaces...
foreach (IPlugin<?> plugin in kernel.GetAll(typeof(IPlugin<>)))
{
plugin.sayMessage(plugin.createMessage());
}
Unfortunately, you must request a specific interface from Ninject, so you must request either IPlugin<IntMessage> or IPlugin<StringMessage>.
I would suggest trying to refactor your app so that you can request a more generic interface, such as IPlugin, and/or create a message interface like IMessage that each message implements. It's not clear from your question what you're trying to accomplish.
Related
I'd like to implement the Decorator pattern in one of my Mvx projects. That is, I'd like to have two implementations of the same interface: one implementation that is available to all of the calling code, and another implementation that is injected into the first implementation.
public interface IExample
{
void DoStuff();
}
public class DecoratorImplementation : IExample
{
private IExample _innerExample;
public Implementation1(IExample innerExample)
{
_innerExample = innerExample;
}
public void DoStuff()
{
// Do other stuff...
_innerExample.DoStuff();
}
}
public class RegularImplementation : IExample
{
public void DoStuff()
{
// Do some stuff...
}
}
Is it possible to wire up the MvvmCross IoC container to register IExample with a DecoratorImplementation containing a RegularImplementation?
It depends.
If DecoratorImplementation is a Singleton, then you could do something like:
Mvx.RegisterSingleton<IExample>(new DecoratorImplementation(new RegularImplementation()));
Then calls to Mvx.Resolve<IExample>() will return the instance of DecoratorImplementation.
However, if you need a new instance, unfortunately the MvvmCross IoC Container doesn't support that. It would be nice if you could do something like:
Mvx.RegisterType<IExample>(() => new DecoratorImplementation(new RegularImplementation()));
Where you'd pass in a lambda expression to create a new instance, similar to StructureMap's ConstructedBy.
Anyway, you may need to create a Factory class to return an instance.
public interface IExampleFactory
{
IExample CreateExample();
}
public class ExampleFactory : IExampleFactory
{
public IExample CreateExample()
{
return new DecoratorImplementation(new RegularImplementation());
}
}
Mvx.RegisterSingleton<IExampleFactory>(new ExampleFactory());
public class SomeClass
{
private IExample _example;
public SomeClass(IExampleFactory factory)
{
_example = factory.CreateExample();
}
}
I'm building a small Nancy web project.
In a method of one of my classes (not a nancy module), I would like to basically do:
var myThing = TinyIoC.TinyIoCContainer.Current.Resolve<IMyThing>();
However, there is only one registration in .Current (non public members, _RegisteredTypes) which is:
TinyIoC.TinyIoCContainer.TypeRegistration
Naturally, in my above code, I'm getting:
Unable to resolve type: My.Namespace.IMyThing
So, I guess I'm not getting the same container registered in my bootstrapper?
Is there a way to get at it?
EDIT
To flesh out a bit more of what I'm trying to do:
Basically, my url structure looks something like:
/{myType}/{myMethod}
So, the idea being, going to: /customer/ShowAllWithTheNameAlex would load the Customer service, and execute the showAllWithTheNameAlex method
How I do this is:
public interface IService
{
void DoSomething();
IEnumerable<string> GetSomeThings();
}
I then have an abstract base class, with a method GetService that returns the service.
It's here that i'm trying to use the TinyIoC.TinyIoCContainer.Current.Resolve();
In this case, it would be TinyIoC.TinyIoCContainer.Current.Resolve("typeName");
public abstract class Service : IService
{
abstract void DoSomething();
abstract IEnumerable<string> GetSomeThings();
public static IService GetService(string type)
{
//currently, i'm doing this with reflection....
}
}
Here's my implementation of the service.
public class CustomerService : Service
{
public void DoSomething()
{
//do stuff
}
public IEnumerable<string> GetSomeThings()
{
//return stuff
}
public IEnumerable<Customer> ShowAllWithTheNameAlex()
{
//return
}
}
Finally, I have my Nancy Module, that looks like:
public class MyModule : NancyModule
{
public MyModule()
{
Get["/{typeName}/{methodName}"] = p => ExecuteMethod(p.typeName, p.methodName);
}
private dynamic ExecuteMethod(string typeName, string methodName)
{
var service = Service.GetService(typeName);
var result = service.GetType().GetMethod(methodName).Invoke(service, null);
//do stuff
return result; //or whatever
}
}
#alexjamesbrown - The short answer is, you don't. Nancy was specifically designed so that you did not deal with the container directly. You mention that the class, that you want to take a dependency on IMyThing, is not a NancyModule. Well this is not an issue, as long as one of your modules has a reference to it, then those dependencies can also have their own dependencies that will be satisfied at runtime.
public interface IGreetingMessageService
{
string GetMessage();
}
public class GreetingMessageService: IGreetingMessageService
{
public string GetMessage()
{
return "Hi!";
}
}
public interface IGreeter
{
string Greet();
}
public class Greeter
{
private readonly IGreetingMessageService service;
public Greeter(IGreetingMessageService service)
{
this.service = service;
}
public string Greet()
{
return this.service.GetMessage();
}
}
public class GreetingsModule : NancyModule
{
public GreetingModule(IGreeter greeter)
{
Get["/"] = x => greeter.Greet();
}
}
The above will work just fine and Greeter will have it's dependency on IGreetingMessageService satisfied at runtime
I have had a very similar issue, needing to "share" the container. The reason this is an issue is that my program runs as a service using Nancy self hosting to provide a REST API. My modules have dependencies which are injected by Nancy itself, but the other parts of the app which are not referenced from modules also need dependencies injected.
Multiple containers are not a sensible option here (or anywhere really), I need to share the container between Nancy and the rest of the app.
I simply did the following
(I'm using Autofac but I suspect that TinyIoC in similar)
public class Bootstrapper : AutofacNancyBootstrapper
{
private static readonly Lazy<ILifetimeScope> container = new Lazy<ILifetimeScope>(RegisterTypes);
public static ILifetimeScope Container => container.Value;
protected override ILifetimeScope GetApplicationContainer()
{
return container.Value;
}
// Create container and register my types
private static ILifetimeScope RegisterTypes()
{
var builder = new ContainerBuilder();
// Register all my own types.....
return builder.Build();
}
}
Then, in my main code, I can use the container myself
public class Program
{
public static void Main(string[] args)
{
// Resolve main service with all its dependencies
var service = Bootstrapper.Container.Resolve<Service>();
service.Run();
}
}
As my NancyHost is within the Service, the container is constructed (once) upon its first use in main, this static is then used when Nancy gets round to creating the Bootstrapper itself.
In an ideal world, I wouldn't really want a globally accessible container, normally it would be local to the main function.
In this particular case "not dealing with the container directly" is highly problematic:
public interface IFoo {}
public class Foo : IFoo { public Foo(string bar) {} }
Assume IFoo already is a constructor dependency of a Nancy module.
Note the Foo constructor's string dependency. I need to communicate to the container to use that constructor for an IFoo singleton, when encountered as a Nancy module dependency. I need to register that on the TinyIoC instance NancyFx uses, and pass in the actual value of bar.
I need to pass a class object through the gwt rpc connection as a generic but it seems that rpc does not cooperate with it. The class is serialized using the java.io.Serializable. I have checked it using the gwt IsSerializable but i still have the error.
Here is my code
MySource.java
#SuppressWarnings("serial")
#PersistenceCapable
#Inheritance(strategy = InheritanceStrategy.SUBCLASS_TABLE)
public abstract class MySource implements Serializable {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Long id;
#Persistent
private String userId;
#Persistent
private String title;
#Persistent
private String description;
#Persistent
private String blobKey;
#Persistent
private String youtubeLink;
#Persistent
private String personalLink;
#Persistent
private Date submitedDate;
#Persistent
private float price;
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getBlobKey() {
return blobKey;
}
public void setBlobKey(String blobKey) {
this.blobKey = blobKey;
}
public String getYoutubeLink() {
return youtubeLink;
}
public void setYoutubeLink(String youtubeLink) {
this.youtubeLink = youtubeLink;
}
public String getPersonalLink() {
return personalLink;
}
public void setPersonalLink(String personalLink) {
this.personalLink = personalLink;
}
public Date getSubmitedDate() {
return submitedDate;
}
public void setSubmitedDate(Date submitedDate) {
this.submitedDate = submitedDate;
}
public Long getId() {
return id;
}
}
AndroidSource.java
#SuppressWarnings("serial")
#PersistenceCapable
public class AndroidSource extends MySource{
public AndroidSource() {
super();
}
}
CategoryBrowseService.java which is the remoteservice model
#RemoteServiceRelativePath("categoryService")
public interface CategoryBrowseService extends RemoteService{
ArrayList<MySource> getSourceList(Class<? extends MySource> classType);
}
CategoryBrowseServiceAsync.java
public interface CategoryBrowseServiceAsync {
void getSourceList(Class<? extends MySource> classType,
AsyncCallback<ArrayList<MySource>> callback);
}
CategoryBrowsePresenter.java where the rpc is called
private void retrieveSources(Class<? extends MySource> classType) {
CategoryBrowseServiceAsync rpcService = GWT.create(CategoryBrowseService.class);
rpcService.getSourceList(classType, new AsyncCallback<ArrayList<MySource>>() {
#Override
public void onFailure(Throwable caught) {
Window.alert("Ooops!!!Sorry!Something went wrong.I am still beta!");
}
#Override
public void onSuccess(ArrayList<MySource> result) {
sourceList = result;
display.setSourceContent(sourceList);
}
});
}
CategoryBrowseServiceImpl.java
#SuppressWarnings("serial")
public class CategoryBrowseServiceImpl extends RemoteServiceServlet implements CategoryBrowseService{
private SourceDatastore dataStore;
public CategoryBrowseServiceImpl() {
dataStore = new SourceDatastore();
}
#Override
public ArrayList<MySource> getSourceList(Class<? extends MySource> classType) {
return dataStore.getSources(classType);
}
}
Here is the error that i get.
Compiling module com.sourcebay.SourceBay
Scanning for additional dependencies: file:/home/santaris/workspace/SourceBay/src/com/sourcebay/client/presenter/mybay/browse/CategoryBrowsePresenter.java
Computing all possible rebind results for 'com.sourcebay.client.model.mybay.browse.CategoryBrowseService'
Rebinding com.sourcebay.client.model.mybay.browse.CategoryBrowseService
Invoking generator com.google.gwt.user.rebind.rpc.ServiceInterfaceProxyGenerator
Generating client proxy for remote service interface 'com.sourcebay.client.model.mybay.browse.CategoryBrowseService'
[ERROR] java.lang.Class<T> is not assignable to 'com.google.gwt.user.client.rpc.IsSerializable' or 'java.io.Serializable' nor does it have a custom field serializer (reached via java.lang.Class<? extends com.sourcebay.shared.source.MySource>)
[ERROR] java.lang.Class<T> has no available instantiable subtypes. (reached via java.lang.Class<? extends com.sourcebay.shared.source.MySource>)
[ERROR] subtype java.lang.Class<T> is not assignable to 'com.google.gwt.user.client.rpc.IsSerializable' or 'java.io.Serializable' nor does it have a custom field serializer (reached via java.lang.Class<? extends com.sourcebay.shared.source.MySource>)
[ERROR] Errors in 'file:/home/santaris/workspace/SourceBay/src/com/sourcebay/client/presenter/mybay/browse/CategoryBrowsePresenter.java'
[ERROR] Line 75: Failed to resolve 'com.sourcebay.client.model.mybay.browse.CategoryBrowseService' via deferred binding
The paradox is that when i am running my application through the eclipse plugin everything works fine. Could anyone help me please? I have checked to fix the problem through the DTO solution without any success. Moreover i have tried to implement a CustomFieldSerializer as Google suggests without any success too.
Thanks in advance,
Stefanos Antaris
P.S. Sorry for the huge post :-)
Well the problem is that you trying to transport a Class object over the network. I have no idea why it is working in dev mode (I've tried it on local project and it failed), but it shouldn't work. You have to use something else instead of Class name for example String, which will contain a name of class. Theoretically it can work if you create CustomFieldSerializer for Class, but using String instead of Class will be easier.
Classes with persistence annotations can work well on the server side, but if you want to pass its data to the client you must create a plain java serializable class to transport data from server to client.
As noted in the previous answer, persistence annotations are not supported in the client side, as they cannot be translated to equivalent javascript code (and it makes sense since the client doesn't have the responsability of persistence).
It could be that the persistence-related annotations in MySource.java make it implossible to translate to javascript. Try removing the annotations to see if it's related. Also make sure that MySource.java is in a package declared as translatable in the module xml file ("source" element).
Try using implements Serializable for defining you class.
I mean like this:
public class AndroidSource extends MySource implements Serializable{
public AndroidSource() {
super();
}
}
Your RPC Services must deal just with Serializable Objects. Domain classes are not translatable to JavaScript So GWT can't send and receive via network (RPC Protocole) such objects. You need to create DTO classes (wich shadows domain class) implementing java.io.Serializable and then reconfigure all your RPC Service to use in input DTOs and output DTOs. Good Luck for your project.
I created console c# project. and in the code I have made a module. My code looks like this.
[Import]
public IMessageSender MessageSender { get; set; }
public static void Main(string[] args)
{
Program p = new Program();
p.Run();
}
public void Run()
{
Compose();
Console.ReadLine(MessageSender.Send("Message Sent"));
}
private void Compose()
{
AssemblyCatalog catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
var container = new CompositionContainer(catalog);
container.ComposeParts(this);
}
public interface IMessageSender
{
string Send(string message);
}
[Export(typeof(IMessageSender))]
public class EmailSender : IMessageSender
{
public void Send(string message)
{
return message;
}
}
It works perfectly fine. But now I added a new project in my solution and added module into that
AnotherProject->EmailSender.cs
[Export(typeof(IMessageSender))]
public class EmailSender : IMessageSender
{
public void Send(string message)
{
return message;
}
}
Now in the main console program I changed some of my code.
private void Compose()
{
var catalog = new DirectoryCatalog(path);
//AssemblyCatalog catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
var container = new CompositionContainer(catalog);
container.ComposeParts(this);
}
But now when I run this program. It doesnt load the module. MessageSender in main program is null. What wrong I have done.
There are a few things you need to check:
Have you correctly referenced the assemblies?
The DirectoryCatalog by default uses the search pattern *.dll. Because you have a console application, which uses the .exe extension, no exports in that assembly will get picked up by the DirectoryCatalog - with the default search pattern. You'll likely want to use an AggregateCatalog, passing in the DirectoryCatalog (*.dll), and either another DirectoryCatalog (*.exe), or an AssemblyCatalog, of the entry assembly.
You currently have one [Import] where you may end up with multiple [Export(typeof(IMessageSender))], you didn't state that you have moved the EmailSender to the class library, merely that you have created a new one, which means you'll likely end up with a cardinality mismatch where it is expecting a sinple import, you have many exports. This will explicitly throw an exception, which is what will happen even it couldn't find a single instance of IMessageSender, because your [Import] attribute is not set to allow a default value where no part can be provided. If you need to be fault tollerant, you can use [Import(AllowDefault = true)]
Incidentally... the above code won't compile, I assume it was just an example and not a copy-paste from your current code?
public void SendMessage(string message)
{
return message;
}
You're retuning a message to a void method - that can't be done, and it also means that EmailSender doesn't correctly implement IMessageSender. Not too bothered, as I think it is an example more than actual code.
I'd like to add one additional method for each service operation in my WCF client proxy code (i.e. the generated class that derives from ClientBase). I have written a Visual Studio extension that has an IOperationContractGenerationExtension implementation, but this interface only seems to expose the ability to modify the service interface, not the ClientBase-derived class.
Is there any way to generate new methods in the proxy client class?
As far as I know, those classes are always partial classes:
public partial class MyWCFServiceClient : ClientBase<IMyWCFService>, IMyWCFService
{
...
}
so you can easily extend them with your own, second file that adds method to the same partial class:
YourOwnFile.cs
public partial class MyWCFServiceClient
{
public void NewMethod1()
{
}
public void NewMethod2()
{
}
}
I got around this by generating a wrapper class for the ClientBase-derived class during the import process. I actually first tried generating an additional partial class with the same name as the client class, but that caused the rest of the code generation to stop working properly.
So my final generated code looks something like:
(generated by the built-in WCF proxy generator):
public interface ServiceReference1
{
IAsyncResult BeginWebMethod1(AsyncCallback callback, object asyncState);
void EndWebMethod1(IAsyncResult result);
IAsyncResult BeginWebMethod2(AsyncCallback callback, object asyncState);
void EndWebMethod2(IAsyncResult result);
// ...
}
public class ServiceReference1Client
{
public event EventHandler<AsyncCompletedEventArgs> WebMethod1Completed;
public event EventHandler<AsyncCompletedEventArgs> WebMethod2Completed;
public void WebMethod1Async() { /* ... */ }
public void WebMethod2Async() { /* ... */ }
// ...
}
(generated by my custom IOperationContractGenerationExtension):
public class ServiceReference1Wrapper
{
private ServiceReference1Client _client;
public ServiceReference1Wrapper(ServiceReference1Client client)
{
_client = client;
}
public IObservable<AsyncCompletedEventArgs> WebMethod1()
{
_client.WebMethod1Async();
// ...
}
public IObservable<AsyncCompletedEventArgs> WebMethod2()
{
_client.WebMethod2Async();
// ...
}
// ...
}
Note: I'm using Silverlight, so that's why everything is async.