Ninject ActivationException on ChildKernel - ninject

I'm getting an ActivationException saying there was an error activating IEventBroker. MyDataSource takes an IEventBroker has a parameter. If I don't use the child kernel, there is no issue. What is going on?
var kernel = new StandardKernel();
var childKernel = new ChildKernel(kernel);
var eventBroker = new EventBroker();
childKernel.Bind<IEventBroker>().ToConstant(eventBroker);
var myDS = childKernel.Get<MyDataSource>();

From the ChildKernel readme:
The default behavior of Ninject that classes are bound to themself if
not explicit still exists. But in this case this will be done by the
top most parent. This means that this class can not have any
dependency defined on a child kernel. I strongly suggest to have a
binding for all objects that are resolved by ninject and not to use
this default behavior.
So you need to explicitly bind MyDataSource to self to make it work:
var kernel = new StandardKernel();
var childKernel = new ChildKernel(kernel);
var eventBroker = new EventBroker();
childKernel.Bind<IEventBroker>().ToConstant(eventBroker);
childKernel.Bind<MyDataSource>().ToSelf();
var myDS = childKernel.Get<MyDataSource>();

Related

How to add custom roslyn analyzer from locally placed DLL?

I have created a Roslyn Analyzer project which generates a nuget package and DLL of it. I want to use that DLL in a standalone code analysis project. How can i do that? For example i have following code:
MSBuildLocator.RegisterDefaults();
var filePath = #"C:\Users\user\repos\ConsoleApp\ConsoleApp.sln";
var msbws = MSBuildWorkspace.Create();
var soln = await msbws.OpenSolutionAsync(filePath);
var errors = new List<Diagnostic>();
foreach (var proj in soln.Projects)
{
var analyzer = //Here i want to load analyzer from DLL present locally.
var compilation = await proj.GetCompilationAsync();
var compWithAnalyzer = compilation.WithAnalyzers(analyzer.GetAnalyzersForAllLanguages());
var res = compWithAnalyzer.GetAllDiagnosticsAsync().Result;
errors.AddRange(res.Where(r => r.Severity == DiagnosticSeverity.Error).ToList());
}
I have tried following
var analyzer = new AnalyzerFileReference("Path to DLL", new AnalyzerAssemblyLoader());
But here AnalyzerAssemblyLoader shows error as it is inaccessible to to its protection level (class is internal).
Kindly suggest me if we can do this.
the .WithAnalyzers() option will allow you to pass an instance of an analyzer. If you're referencing the DLL locally, you can just create the analyzer like you would any other object and pass it to the compilation.
var analyzer = new MyAnalyzer();
var compilation = await proj.GetCompilationAsync();
var compWithAnalyzer = compilation.WithAnalyzers(ImmutableArray.Create<DiagnosticAnalyzer>(analyzer));
If you're not referencing the assembly, but want to load it at runtime, you can use the usual System.Reflection based methods to get an instance of the analyzer:
var assembly = Assembly.LoadFrom(#"<path to assembly>.dll");
var analyzers = assembly.GetTypes()
.Where(t => t.GetCustomAttribute<DiagnosticAnalyzerAttribute>() is object)
.Select(t => (DiagnosticAnalyzer) Activator.CreateInstance(t))
.ToArray();
compWithAnalyzers = compilation.WithAnalyzers(ImmutableArray.Create(analyzers));

Spring & RabbitMQ - register queue at runtime

How can I create new queue bound to Fanout exchange and run it during runtime? So far I have this:
Map<String, Object> arguments = new HashMap<>();
arguments.put("x-message-ttl", 600000L);
GenericBeanDefinition runtimeQueueBean = new GenericBeanDefinition();
runtimeQueueBean.setBeanClass(Queue.class);
runtimeQueueBean.setLazyInit(false);
runtimeQueueBean.setAbstract(false);
runtimeQueueBean.setAutowireCandidate(true);
ConstructorArgumentValues queueConstrArgs = new ConstructorArgumentValues();
queueConstrArgs.addIndexedArgumentValue(0, queueName);
queueConstrArgs.addIndexedArgumentValue(1, true);
queueConstrArgs.addIndexedArgumentValue(2, false);
queueConstrArgs.addIndexedArgumentValue(3, false);
queueConstrArgs.addIndexedArgumentValue(4, arguments);
runtimeQueueBean.setConstructorArgumentValues(queueConstrArgs);
this.context.registerBeanDefinition("nejm", runtimeQueueBean);
GenericBeanDefinition runtimeFanoutExchange = new GenericBeanDefinition();
runtimeFanoutExchange.setBeanClass(FanoutExchange.class);
runtimeFanoutExchange.setLazyInit(false);
runtimeFanoutExchange.setAbstract(false);
runtimeFanoutExchange.setAutowireCandidate(true);
ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues();
constructorArgumentValues.addIndexedArgumentValue(0, "staticCache");
runtimeFanoutExchange.setConstructorArgumentValues(constructorArgumentValues);
this.context.registerBeanDefinition("staticCache", runtimeFanoutExchange);
GenericBeanDefinition runtimeBinding = new GenericBeanDefinition();
runtimeBinding.setBeanClass(Binding.class);
runtimeBinding.setLazyInit(false);
runtimeBinding.setAbstract(false);
runtimeBinding.setAutowireCandidate(true);
constructorArgumentValues = new ConstructorArgumentValues();
constructorArgumentValues.addIndexedArgumentValue(0, queueName);
constructorArgumentValues.addIndexedArgumentValue(1, Binding.DestinationType.QUEUE);
constructorArgumentValues.addIndexedArgumentValue(2, "staticCache");
constructorArgumentValues.addIndexedArgumentValue(3, "");
runtimeBinding.setConstructorArgumentValues(constructorArgumentValues);
this.context.registerBeanDefinition("bajnding", runtimeBinding);
GenericBeanDefinition runtimeMessageListenerAdapter = new GenericBeanDefinition();
runtimeMessageListenerAdapter.setBeanClass(MessageListenerAdapter.class);
runtimeMessageListenerAdapter.setLazyInit(false);
runtimeMessageListenerAdapter.setAbstract(false);
runtimeMessageListenerAdapter.setAutowireCandidate(true);
constructorArgumentValues = new ConstructorArgumentValues();
constructorArgumentValues.addIndexedArgumentValue(0, this);
constructorArgumentValues.addIndexedArgumentValue(1, new RuntimeBeanReference("jackson2JsonMessageConverter"));
runtimeMessageListenerAdapter.setConstructorArgumentValues(constructorArgumentValues);
this.context.registerBeanDefinition("mla2", runtimeMessageListenerAdapter);
GenericBeanDefinition runtimeContainerExchange = new GenericBeanDefinition();
runtimeContainerExchange.setBeanClass(SimpleMessageListenerContainer.class);
runtimeContainerExchange.setLazyInit(false);
runtimeContainerExchange.setAbstract(false);
runtimeContainerExchange.setAutowireCandidate(true);
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.addPropertyValue("connectionFactory", new RuntimeBeanReference("connectionFactory"));
propertyValues.addPropertyValue("queues", new RuntimeBeanReference("nejm"));
propertyValues.addPropertyValue("messageListener", new RuntimeBeanReference("mla2"));
runtimeContainerExchange.setPropertyValues(propertyValues);
this.context.registerBeanDefinition("defqueue", runtimeContainerExchange);
The problem is that queue/exchange is not created at the runtime, and I have to manually start the listener (unless I call this.context.start() - but I don't know if this is correct approach).
My question - is there some way to magically start all generated beans in runtime (something like this.context.refresh() - this exists but doesn't work or similar)?
UPDATE:
This is how I do it currently (this approach works, but don't know if correct one)
Map<String, Object> arguments = new HashMap<>();
arguments.put("x-message-ttl", 600000L);
Queue queue = new Queue(queueName, true, false, false, arguments);
FanoutExchange exchange = new FanoutExchange("staticCache");
Binding binding = new Binding(queueName, Binding.DestinationType.QUEUE, "staticCache", "", null);
rabbitAdmin.declareQueue(queue);
rabbitAdmin.declareExchange(exchange);
rabbitAdmin.declareBinding(binding);
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(this.connectionFactory);
container.setQueues(queue);
container.setMessageListener(new MessageListenerAdapter(this, this.converter));
container.start();
You can't do that way. BeanDefinition and this.context.registerBeanDefinition are for parsing phase of your application context lifecycle.
If you app is already there, the application context won't accepts any BeanDefinition.
Yes, you can declare Queue and its Binding to the exchange manually at runtime. And also you even can create SimpleMessageListenerContainer manually and make it worked.
And what is good for you that you just need to use their classes manually to instantiate. There is just need to supply container environment (e.g. inject this.applicationContext to the listenerContainer object).
For the declaration on the Broker you must use RabbitAdmin bean from your applicationContext.
From other side there is no reason to start a new listenerContainer manually. The existing one can supplied with your new Queue at runtime.

Why resolving a collection also create 1 element?

I am using Autofac 3.5.2 on Mono and when I try to register a generic collection and then resolve it I get the right instance where 1 element of the right type has already been added. To explain it in code:
class Fake {}
var builder = new ContainerBuilder();
builder.RegisterType<Fake>();
bilder.RegisterGeneric(typeof(List<>));
var scope = builder.Build();
var list = scope.Resolve<List<Fake>>();
Console.WriteLine(list.Count); // => prints 1!
Is this to be expected? Why? How can I avoid that?
Autofac has built-in support for collection and will by default try to use the constructor with the most available arguments when it resolves a service.
Autofac automatically uses the constructor for your class with the most parameters that are able to be obtained from the container
> http://autofac.readthedocs.org/en/latest/register/registration.html#register-by-type
List<T> contains a constructor which take a IEnumerable<T>.
When Autofac resolve List<Fake> it will choose the constructor with IEnumerable<T>, then resolve IEnumerable<T> which will resolve all available instance of T.
If you have more than one Fake registered, Autofac will resolve all of them when you resolve. For example :
var builder = new ContainerBuilder();
builder.RegisterType<Fake1>().As<IFake>();
builder.RegisterType<Fake2>().As<IFake>();
builder.RegisterGeneric(typeof(List<>));
var scope = builder.Build();
var list = scope.Resolve<List<IFake>>();
Console.WriteLine(list.Count); // => prints 2!
You can specify which constructor to use when you register List<T>
var builder = new ContainerBuilder();
builder.RegisterType<Fake1>().As<IFake>();
builder.RegisterType<Fake2>().As<IFake>();
builder.RegisterGeneric(typeof(List<>)).UsingConstructor(Type.EmptyTypes);
var scope = builder.Build();
var list = scope.Resolve<List<IFake>>();
Console.WriteLine(list.Count); // => prints 0!
Or you can ignore default behavior by using the ContainerBuildOptions.ExcludeDefaultModules parameter in the Build method
var builder = new ContainerBuilder();
builder.RegisterType<Fake1>().As<IFake>();
builder.RegisterGeneric(typeof(List<>));
var scope = builder.Build(ContainerBuildOptions.ExcludeDefaultModules);
var list = scope.Resolve<List<IFake>>();
Console.WriteLine(list.Count); // => prints 0!
I won't recommend removing default behaviors unless you really know what you do.

Resolving unnamed Ninject multi-binding

I am new to Ninject and am struggling to get this test to pass. (This test passed with Autofac but the behaviour seems different in Ninject).
[Test]
public void RegisterInstance_unnamed_should_return_unnamed_when_multiple_registrations()
{
var sut = new StandardKernel();
var instance1 = new Dependency3();
var instance2 = new Dependency3();
sut.Bind<Dependency3>().ToConstant(instance1).Named("instance1");
sut.Bind<Dependency3>().ToConstant(instance2);
sut.Get<Dependency3>("instance1").ShouldBeSameAs(instance1);
sut.Get<Dependency3>().ShouldBeSameAs(instance2);
}
When I call the last line I get this exception message:
Ninject.ActivationException : Error activating Dependency3
No matching bindings are available, and the type is not self-bindable.
Activation path: 1) Request for Dependency3
How do I resolve a binding that is not named when there are multiple bindings?
Thanks
If you want to treat the un-named binding as a "default", you're required to add .BindingConfiguration.IsImplicit = true to the named bindings. Like so:
Bind<Dependency3>().ToConstant(instance1)
.Named("instance1")
.BindingConfiguration.IsImplicit = true;
Otherwise the named binding will satisfy a request without a name as well.

JavaScriptSerializer and monodevelop

Im reading this book but I JavaScriptSerializer from the System.Web.Script.Serialization namespace because it seems to be unavailable?
I know this a really old post but by chance someone stumbles upon this like I have, System.Web.Script.Serialization is available in System.Web.Extensions.
Download source here and add as existing project.
Then add as reference:
http://www.bloxify.com/post/MonoTouch-Easy-JSON-Library.aspx
Edit:
You may also find that the monotouch linker is pretty aggressive. I would have code work fine in the simulator but crash in the device with method missing exceptions. Add a method somewhere in your app (you dont have to call it) like so:
public void FixMonoTouchErrors()
{
var gc = new System.ComponentModel.GuidConverter();
var sc = new System.ComponentModel.StringConverter();
var dc = new System.ComponentModel.DateTimeConverter();
var cc = new System.ComponentModel.CharConverter();
var sh = new System.ComponentModel.Int16Converter();
var sh1 = new System.ComponentModel.Int32Converter();
var sh2 = new System.ComponentModel.Int64Converter();
var dec = new System.ComponentModel.DecimalConverter();
var nc0 = new System.ComponentModel.NullableConverter(typeof(Int16?));
var nc1 = new System.ComponentModel.NullableConverter(typeof(Int32?));
var nc2 = new System.ComponentModel.NullableConverter(typeof(Int64?));
var nc3 = new System.ComponentModel.NullableConverter(typeof(decimal?));
var nc4 = new System.ComponentModel.NullableConverter(typeof(DateTime?));
}