How to override existing binding without removing all conditional such? - c#

The challenge I am facing with Ninject currently is that when I use Rebind<>() it removes all bindings, even those that are conditional. Let me give you a silly example below. Basically what I find undesired behaviour in my case is that when Rebind is called it will remove the conditional WhenInjectedInto<T> binding instead of just overwriting the non-conditional Bind<T>. In the sample below the contract Contract.Assert(cat is Wild); in the ctor will fail after the Rebind.
Is there a way to do what I want - being the ability to keep already injected conditional bindings and overwrite only the non-conditional one?
P.S: In reality I am trying to do some interesting things with DataContext scopes depending on where they are injected (in a request or in an async command)
void Main()
{
StandardKernel kernel = new StandardKernel();
kernel.Bind<ICat>().To<Wild>();
kernel.Bind<ICat>().To<Wild>()
.WhenInjectedInto<EvilCat>();
kernel.Rebind<ICat>().To<Domestic>();
Contract.Assert(kernel.Get<ICat>() is Domestic);
kernel.Get<EvilCat>();
}
interface ICat {}
class Domestic : ICat {}
class Wild : ICat { }
class EvilCat
{
public EvilCat(ICat cat) {
Contract.Assert(cat is Wild);
}
}

Try this:
kernel.GetBindings(typeof(ICat)).
Where(binding => !binding.IsConditional).
ToList().
ForEach(
binding =>
kernel.RemoveBinding(binding)
)
kernel.Bind<ICat>().To<Domestic>();
Of course you can do it without LINQ in a foreach:
var bindings = kernel.GetBindings(typeof(ICat)).ToList();
foreach(var binding in bindings)
{
if (!binding.IsConditional)
kernel.RemoveBinding(binding);
}
kernel.Bind<ICat>().To<Domestic>();

Related

Can you use Autofac's Owned with a marker interface?

I want to use Autofac to create a new instance of one or several WCF channels for a given unit of work. I'd like to use the command pattern to represent units of work, i.e. a given command class is injected with the channel(s) it needs and implements a bunch of related operations.
I tried the following:
interface IUnitOfWork
{
}
class FooCall : IUnitOfWork
{
readonly BarChannel _channel;
public FooCall(BarChannel channel)
{
Console.WriteLine($"FooCall({new {channel}})");
_channel = channel;
}
public string Foo()
{
return "FOO";
}
}
class BarChannel
{
public BarChannel()
{
Console.WriteLine("BarChannel()");
}
}
class FooService
{
Func<Owned<FooCall>> _helperFn;
public FooService(Func<Owned<FooCall>> helperFn)
{
_helperFn = helperFn;
}
public void CallFoo()
{
using (var helper = _helperFn())
{
Console.WriteLine($"CallFoo(), helper={helper}");
helper.Value.Foo();
}
}
}
class Program
{
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterType<BarChannel>().InstancePerOwned<IUnitOfWork>();
builder.RegisterType<FooCall>().AsImplementedInterfaces().AsSelf();
builder.RegisterType<FooService>();
using (var scope = builder.Build().BeginLifetimeScope())
{
Console.WriteLine("call 1");
scope.Resolve<FooService>().CallFoo();
Console.WriteLine("call 2");
scope.Resolve<FooService>().CallFoo();
}
}
}
In short: a service method creates an owned unit of work; the unit of work is injected with a per-owned channel that it calls. The code sample should show two channel instances being created.
Except that it seems that the lifetime scope created for owned dependencies is only tagged with the type as which the dependency was resolved - i.e. as FooCall, not as IUnitOfWork. If I register BarChannel as InstancePerOwned<FooCall>, the code works; as is, registered as InstancePerOwned<IUnitOfWork>, it fails to resolve FooService since it can't find a matching lifetime scope. Am I missing something or is what I want to do not possible with Autofac? I'd rather not have to register all my WCF channels as instance-per-owned for every command class, that seems like it would get pretty verbose. Another workaround would be using instance-per-depedency and resolving a Func directly, but that won't let me say compose units of work while reusing channels and their dependencies between them.
The problem is that InstancePerOwned<T> is really just a special case of InstancePerMatchingLifetimeScope(params object[] lifetimeScopeTag), where the scope is tagged with something like typeof(T). As it stands, there needs to be a direct link between the tag provided there and the one attached to the scope when attempting to resolve, which is always set to the type of whatever's inside that specific Owned<> dependency. There's no additional logic to imply relations between types at that point, it's just a direct match on the tags.
However, InstancePerMatchingLifetimeScope does allow multiple tags to be specified, so it's possible to do something like:
builder.RegisterType<BarChannel>()
.InstancePerMatchingLifetimeScope(new TypedService(typeof(FooCall)),new TypedService(typeof(AnotherUnitOfWork)));
To wrap this up a bit more neatly you could use:
private static IEnumerable<Type> GetTypesImplementingInterface<TInterface>()
{
return AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => typeof(TInterface).IsAssignableFrom(p));
}
and then a new extension method:
public static class AutofacRegistrationBuilderExtensions
{
public static IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> InstancePerOwned<TLimit, TActivatorData, TRegistrationStyle>(
this IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> builder, IEnumerable<Type> serviceTypes)
{
return builder.InstancePerMatchingLifetimeScope(serviceTypes.Select(s => new TypedService(s)).ToArray());
}
}
The usage would then just be:
builder.RegisterType<BarChannel>().InstancePerOwned(GetTypesImplementingInterface<IUnitOfWork>());
I'm not sure if the last part there would be worth pulling into Autofac itself, but I guess if it did then it might be better to combine the two methods above together and retrieve the list of types applicable from existing registrations, e.g. something like
InstancePerOwnedImplementing<TInterface>();
Alternatively, it would probably be a bit messy to extend the matching scope logic to check the relationship between types at resolution time, since not all tags are of the type Type.

Autofac filter resolved IEnumerable implementations

Is it possible to filter dependencies when resolving IEnumerable in autofac?
I have multiple implementations of an interface (IHandler in the example below) which are defined & registered using an Autofac module in isolated projects. I would like to be able to filter the implementations when resolving in the parent type (Processor in the example below).
The IHandler implementations could be injected into the Processor and filtered in the ctor but this would require resolving all implementations regardless whether they are required which is wasteful.
public interface IHandler { }
public class Handler1 : IHandler { }
public class Handler2 : IHandler { }
public class Handler3 : IHandler { }
public class Processor {
public IEnumerable<IHandler> Handlers;
public Processor(IEnumerable<IHandler> handlers) {
Handlers = handlers;
}
}
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterType<Handler1>().As<IHandler>();
builder.RegisterType<Handler2>().As<IHandler>();
builder.RegisterType<Handler3>().As<IHandler>();
builder.RegisterType<Processor>().AsSelf();
var container = builder.Build();
var processor = container.Resolve<Processor>();
}
As only 1 key can be resolved at a time, my attempt with keys didnt work:
[Flags]
public enum HandlerType
{
One = 1,
Two = 2,
Three = 4
}
builder.RegisterType<Handler1>().Keyed<IHandler>(HandlerType.One);
builder.RegisterType<Handler2>().Keyed<IHandler>(HandlerType.Two);
builder.RegisterType<Handler3>().Keyed<IHandler>(HandlerType.Three);
var enabledHandlers = HandlerType.One | HandlerType.Three;
builder.RegisterType<Processor>().AsSelf()
.WithParameter(ResolvedParameter.ForKeyed<IEnumerable<IHandler>>(enabledHandlers));
I would recommend using the Meta<T> and Lazy<T> implicit relationship types to allow the processor to read config and control all that at runtime. That would also allow you to filter differently in different conditions or turn filtering off entirely without having to change any keys.
Register the handlers with metadata instead of as keyed services...
builder.RegisterType<Handler1>()
.As<IHandler>()
.WithMetadata("type", HandlerType.One);
builder.RegisterType<Handler2>()
.As<IHandler>()
.WithMetadata("type", HandlerType.Two);
builder.RegisterType<Handler3>()
.As<IHandler>()
.WithMetadata("type", HandlerType.Three);
Update your processor to take IEnumerable<Meta<Lazy<IHandler>>> and filter during construction or at some later point when the handlers are needed, your call.
public class Processor
{
private readonly IHandler[] _handlers;
public Processor(IEnumerable<Meta<Lazy<IHandler>>> handlers)
{
this._handlers =
handlers
.Where(h => h.Metadata["type"] == HandlerType.One || h.Metadata["type"] == HandlerType.Three)
.Select(h => h.Value.Value)
.ToArray();
}
}
Each item coming in to the constructor will be a Meta<Lazy<IHandler>>:
Meta<T> has a Metadata dictionary to query and the Value will be the Lazy<IHandler>.
Lazy<T> will not resolve/construct the handler until you call the Value property, so it won't be expensive or cause resolutions you don't want.
So item.Value.Value will be the resolved IHandler (as you see in the LINQ above).
The stuff in the Where filter could be based on config or anything else. But the real win here is that if you still need to resolve all the handlers somewhere else...
public OtherHandlerConsumer(IEnumerable<IHandler> handlers)
...that will still work. You can't do that if they're all keyed. Plus you can add as much metadata as you want to the registrations or even define more robust strongly typed metadata so you can make smarter decisions about which handlers you want.
If you can provide proper filter during container set up phase (as you do in your sample code), you could change your Processor type registration to the following:
builder.RegisterType<Processor>().AsSelf()
.WithParameter((p, c) => p.Name == "handlers",
(p, c) => new[]
{
c.ResolveKeyed<IHandler>(HandlerType.One),
c.ResolveKeyed<IHandler>(HandlerType.Three)
});
Values you need to use could be taken from anywhere you want, from config file too.
Since the registered handlers are based on a configuration switch, it means that the selected handlers won't change at runtime. This is very different than selecting the handlers based on some runtime condition. I therefore propose something similar to this:
var handlerIds = ConfigurationManager.AppSettings["Handlers"].Split(',');
if (handlerIds.Contains("1")) builder.RegisterType<Handler1>().As<IHandler>();
if (handlerIds.Contains("2")) builder.RegisterType<Handler2>().As<IHandler>();
if (handlerIds.Contains("3")) builder.RegisterType<Handler3>().As<IHandler>();
if (handlerIds.Contains("4")) builder.RegisterType<Handler4>().As<IHandler>();
// etc
builder.RegisterType<Processor>().AsSelf();

Better way to resolve the binding of multiple services when the context is the same in Ninject?

I've got a class that has a factory method, which when it finds a serialized version of itself should return it; otherwise it should return a new instance of itself:
class ClassToDeserialize : List<SomeClass>
{
public static event Func<ClassToDeserialize> onNoDeserializationFile;
public ClassToDeserialize(SomeClass firstInList)
{
this.Add(firstInList);
}
public static ClassToDeserialize DeserializeIfAny(string jsonPath)
{
if (File.Exists(jsonPath))
return JsonConvert.DeserializeObject<ClassToDeserialize>(File.ReadAllText(jsonPath));
return onNoDeserializationFile();
}
}
I'm trying to refactor my application to use DI, the problem though is that I have to do a double binding for ClassToDeserialize, like so:
static void Main(string[] args)
{
string json = #"C:\obj_serialized.txt";
IKernel ninjectKernel = new StandardKernel();
ClassToDeserialize.onNoDeserializationFile += (() => ninjectKernel.Get<ClassToDeserialize>("NoSerialization"));
ninjectKernel.Bind<ClassToDeserialize>().ToSelf().Named("NoSerialization").WithConstructorArgument("jsonPath", json);
ninjectKernel.Bind<ClassToDeserialize>().ToConstant<ClassToDeserialize>(ClassToDeserialize.DeserializeIfAny(json));
}
I added the onNoDeserializationFile event to let ninject handle all instantiations and decouple my business logic from my IoC, and then I intend to Get a Service which has a dependency upon ClassToDeserialize, and to be able to resolve this request I need to find a way to tell ninject that when a serialization file is found it should call the corresponding binding (even though the context is the same).
ninjectKernel.Get<DependantClass>().DoSomething();
I'm aware this resembles the Service-Locator Antipattern, but is not the only way I'm using the container and this behavior is tied only to the entry point of my application.
What's the proper way for solving this?
You could put that decision logic into an IProvider.
Alternatively there's the When binding syntax for conditions. See Contextual Bindings.
How about using:
kernel.Bind<ClassToDeserialize>().ToSelf()
.WithConstructorArgument(...); // default binding
kernel.Bind<ClassToDeserialize>()
.ToMethod(ctx => JsonConvert.DeserializeObject<ClassToDeserialize>(...))
.InSingletonScope()
.When(ctx => File.Exists(...));
(hint: i didn't compile it so the method sequence might be slightly off).

Binding multiple versions of the same type with Ninject

I am using Ninject to create a set of "plugins", e.g. I have:
Bind<IFoo>().To<Class1>();
Bind<IFoo>().To<Class2>();
Bind<IFoo>().To<Class3>();
... and later on I use kernel.GetAll<IFoo>() and iterate over the results. Each of Class1/Class2/Class3 implement IFoo of course, and have constructors that have a bunch of parameters also injected by Ninject, for example the constructor for Class1 is public Class1(IBar bar, IBaz baz), with both IBar and IBaz injected by Ninject. So far so good.
However, now I want to have two different "versions" of Class1, both bound to IFoo, differing only in a value passed at construction time. That is, for example, suppose the Class1 constructor was now public Class1(IBar bar, IBaz baz, bool myParameter), and I want to do the following:
Bind<IFoo>().To<Class1>(); //Somehow pass 'true' to myParameter here
Bind<IFoo>().To<Class1>(); //Somehow pass 'false' to myParameter here
Bind<IFoo>().To<Class2>();
Bind<IFoo>().To<Class3>();
... Then, when I call kernel.GetAll<IFoo>(), I want 4 versions of IFoo returned (Class1 "true" version, Class1 false version, Class2 and Class3). I've read through the Ninject documentation and can't find a way to do this.
Here are some ideas I tried, but none of them work well:
1) I could just separate classes (e.g. Class1True and Class1False), with one deriving from another, and bind to them. The problem is that this solution doesn't really scale when I have to do this for many classes - I end up polluting my class hierarchy with a lot of useless classes, and the problem becomes worse when the constructor parameter I want to pass is anything more complex than a bool. Realistic example:
Bind<IDrawingTool>().To<Brush>(); //Somehow pass '5' to brushThickness to create a fine brush
Bind<IDrawingTool>().To<Brush>(); //Somehow pass '25' to brushThickness to create a medium brush
Bind<IDrawingTool>().To<Brush>(); //Somehow pass '50' to brushThickness to create a coarse brush
Bind<IDrawingTool>().To<Pencil>();
Bind<IDrawingTool>().To<SprayCan>();
Of course, this is just one possible configuration of infinitely many possible ones. Creating a new class for each brush thickness seems wrong.
2) I looked into the possibility of using a .ToMethod binding, something like this:
Bind<IDrawingTool>().ToMethod(c => new Brush(5));
Bind<IDrawingTool>().ToMethod(c => new Brush(25));
Bind<IDrawingTool>().ToMethod(c => new Pencil());
But in this case I'm confused about the following:
a) What if the Brush() constructor actually requires other parameters as well, that must be injected via Ninject?
b) Are multiple ToMethod bindings actually allowed?
c) Would this work with InSingletonScope()?
So to summarize: What is a good way to bind to multiple "versions" of the same type?
It's perfectly fine to create two bindings for the same type, which differ only in parameters.
So what you've got to do is:
Bind<IFoo>().To<Class1>().WithConstructorArgument("boolParameterName", true);
Bind<IFoo>().To<Class1>().WithConstructorArgument("boolParameterName", false);
Use the WithConstructorArgument to pass the parameter. You can either have Ninject match the parameter by the name - in the above example the Class1 ctor would need to feature a bool parameter whose name is exactly boolParameterName. Or you can match the type, in which case you could only have one parameter of that type in the constructor. Example: WithConstructorArgument(typeof(bool), true).
All the parameters which you don't specify by WithConstructorArgument get ctor-inject "as usual".
Complete working example (using xunit and FluentAssertions nuget packages):
public interface IBar { }
public class Bar : IBar { }
public interface IFoo { }
class Foo1 : IFoo
{
public Foo1(IBar bar) { }
}
class Foo2 : IFoo
{
public Foo2(IBar bar, bool theParametersName) { }
}
[Fact]
public void FactMethodName()
{
var kernel = new StandardKernel();
kernel.Bind<IBar>().To<Bar>();
kernel.Bind<IFoo>().To<Foo1>();
kernel.Bind<IFoo>().To<Foo2>().WithConstructorArgument("theParametersName", true);
kernel.Bind<IFoo>().To<Foo2>().WithConstructorArgument("theParametersName", false);
List<IFoo> foos = kernel.GetAll<IFoo>().ToList();
foos.Should().HaveCount(3);
}
If you don't use any conditional bindings, resolving those "multiple versions" at runtime when the container detects a dependency will result in an exception, due to ambiguity. It surely could work in a "service-locator"-based access, but in true DI composing the object graph, you'll run into trouble using this approach.
In your depicted scenario, this ambiguity would arise should the following hypothetical situation existed:
public class MyDraw
{
public MyDraw(IDrawingTool drawingTool)
{
// Your code here
}
}
kernel.Bind<IDrawingTool>().ToMethod(c => new Brush(5));
kernel.Bind<IDrawingTool>().ToMethod(c => new Brush(25));
kernel.Bind<IDrawingTool>().ToMethod(c => new Pencil);
// Runtime exception due to ambiguity: How would the container know which drawing tool to use?
var md = container.Get<MyDraw>();
However, if you have this class to be injected:
public class MyDraw
{
public MyDraw(IEnumerable<IDrawingTool> allTools)
{
// Your code here
}
}
This would work due to multi-injection. The caontainer would simply invoke all bindings that match IDrawingTool. In this case, multiple bindings are allowed, even ToMethod(...) ones.
What you need to do is rely upon mechanisms such as Named Bindings or Contextual Bindings (using WhenXXX(...) syntax, to let the target of injection to determine which concrete implementation it requires. Ninject has extensive support for this and actually is one of the defining features for it's core DI Framework. You can read about it here.

Different binding in specific object subtree using Ninject

I am using Ninject to perform dependency injection in my project and I've encountered one problem. I need to specify an exception in binding in specific subtrees of my "object tree" (in meaning of inclusion not inheritance). Let's say we have few interfaces and classes (I've excluded constructors and other irrelevant stuff):
interface Wheel { ... }
class RoundWheel : Wheel { ... }
class SquareWheel : Wheel { ... }
class Mechanism { Wheel Wheel; ... }
class Bike { Wheel Wheel; ... }
class Items { Mechanism Mechanism; Bike Bike; ... }
I want to bind Wheel to SquareWheel when it's somehow included in Mechanism (Mechanism can be somewhere higher, eg. Item.Mechanism.ContainerForWheel.(any types further on).Wheel) and to RoundWheel otherwise. Now, let's look at my current solution:
IKernel kernel = new StandardKernel();
kernel.Bind<Wheel>().To<RoundWheel>();
kernel.Bind<Wheel>().To<SquareWheel>().When(x => x.ActiveBindings.Any(p => p.Service.Name == typeof(Mechanism).Name));
Items items = kernel.Get<Items>();
It works like a charm, but looks very inelegant and suboptimal. It's hard to understand clear purpose of this filtering. Do you know any other way to achieve this? Thanks in advance.
Edit 1
I forgot to mention that I don't want to put any annotations and other stuff into my classes. I want to keep everything in kernel setup/modules.
I don't think there's really an easier way to do things. You could also explictly traverse the IContext.ParentRequest and check if there's ever a specific Mechanism. That would be a bit more explicit then using the ActiveBindings property. But will neither be faster nor result in less code.
But what you could do is applying clean code and creating your own When-Extension, so you'll end up with:
kernel.Bind<Wheel>().To<SquareWheel>()
.When(IsDescendantOf<Mechanism1>);
private static bool IsDescendantOf<T>(IRequest request)
{
return request.ActiveBindings.Any(p => p.Service.Name == typeof(T).Name);
}
or, using an extension method:
kernel.Bind<IWheel>().To<Wheel2>()
.WhenIsDescendantOf(typeof(Mechanism1));
public static class NinjectWhenExtensions
{
public static IBindingInNamedWithOrOnSyntax<T> WhenIsDescendantOf<T>(this IBindingWhenSyntax<T> syntax, Type ancestor)
{
return syntax.When(request => request.ActiveBindings.Any(p => p.Service.Name == ancestor.Name));
}
}
btw., you should also be able to replace the check p.Service.Name == typeof(Mechanism).Name by p.Service == typeof(Mechanism). When the name is a match, the type shoould be, too. If you're working with interface you would have to adapt the logic, though.

Categories

Resources