Ninject Factory NamedLikeFactoryMethod not working as directed? - c#

NamedLikeFactoryMethod in Ninject Extensions Factory working in non-compliance with documentation
I am basically trying to do what the above post has listed but I guess the API has changed, When I look in the object browser I do not see an overload that would allow for this syntax.
I am trying the code below, I is making me use a NamedLikeFactoryMethod but when I do that it complains about the Bind<>.To<> portion, and either way I am unable to pickup the interface type to call the Create[Name] methods. Has this changed?
I am using Ninject 3, with the Ninject.Extension.Factory 3
Factory
public interface ITemplateProcessorFactory
{
ITemplateProcessor CreateXsltProcessor();
ITemplateProcessor CreateRazorProcessor();
ITemplateProcessor CreateMarkdownProcessor();
}
Binding
Bind<ITemplateProcessor>().To<XsltProcessor>().NamedLikeFactoryMethod((ITemplateProcessorFactory)t => t.);
Bind<ITemplateProcessor>().To<XsltProcessor>().NamedLikeFactoryMethod<ITemplateProcessor,ITemplateProcessorFactory(t => t.);

You have to name your methods GetXXX otherwise the factory will request instances without using a name.

Related

Autofac - how to register open generics as named or keyed types for use in a factory or using IIndex<,>

I am using Net Core 5 and had not yet had a need to use anything other than the built in Dependency Injection. I now have a need to be able to resolve a specific service based on the value selected from a dropdown list of services in a UI.
Out of all the DI containers out there I have decided to delve a bit further into Autofac and think that using either named services and a factory pattern or keyed services will be the way to go but I am running into a bit of difficulty, here is an example;
I have an Interface that look like this
public interface IChartDataService<TSource, TTarget>
And I have services that have to implement this interface like this
public class TreantService : IChartDataService<SourceDto, TargetDto>
I am struggling to work out how I am supposed to register these services in the Autofac container.
For named services I have tried to register like this
containerBuilder.RegisterGeneric(typeof(MarkOneService)).As(typeof(IChartDataService<,>)).Named<MarkOneService>("markone");
containerBuilder.RegisterGeneric(typeof(MarkTwoService)).As(typeof(IChartDataService<,>)).Named<MarkTwoService>("marktwo");
and I try to resolve them like this
var service = scope.ResolveNamed("markone", typeof(IChartDataService<,>));
also tried it this way
var service = scope.ResolveNamed("markone", typeof(IChartDataService<SourceDto,TargetDto>));
I cant have registered them correctly as this errors with saying that the service is not registered.
My preferred method would be to use Keyed services, that way I can make use of 'IIndex' but again this is stumping me as to how to register or whether what I am trying to do is even possible.
I am trying to register keyed services like this
containerBuilder.RegisterGeneric(typeof(MarkOneService)).As(typeof(IChartDataService<,>)).Keyed("markone", typeof(IChartDataService<,>));
OR
containerBuilder.RegisterType<MarkOneService>().As<IChartDataService<,>>().Keyed<IChartDataService<,>>("markone");
I am clearly missing something as I cant seem to get the syntax right to be able register correctly. When I do get the registration working I then cant resolve the service because of the open interface.
Also, as I would prefer to use keyed service I dont know how I would be able to get the injected service dictionary. This obviously wont work as it doesn't match my Interface
IIndex<string, IChartDataService> serviceDic
and this is syntactically invalid according to VS
IIndex<string, typeof(IChartDataService<,>)> serviceDic
OR
IIndex<string, IChartDataService<,>> serviceDic
I have spent way too much time on this now and I am going round in circles so could do with some tother insight as to where I may be going wrong, anybody any suggestions? can you point me to any examples of what I am trying to acheive please?
There's a bit to unpack here and, while I can kind of explain why things aren't working the way you want, the short answer is you're probably going to have to redesign how you're doing what you're doing. Which is likely not the answer you want, but... it's the answer.
To understand why, we need to ignore Autofac entirely for a moment and just look at the types you're working with.
You have an interface:
public interface IChartDataService<TSource, TTarget>
As an open generic, this could be IChartDataService<string, Exception> or it could be IChartDataService<object, object> or anything else. (Yes, I get there may be constraints, but stick with me - as an open generic, those types could change all over the place.) So when you talk about IChartDataService<,> in that form, that's what you're saying: "The open generic where anything could be in either of those type parameter spots."
Now, sometimes folks will create an equally generic implementation, like:
public class ChartDataService<TSource, TTarget>
: IChartDataService<TSource, TTarget>
Taking a step back to Autofac, that's what RegisterGeneric is for - to handle the open generic implementations. If you had this sort of thing, you'd register like:
builder.RegisterGeneric(typeof(ChartDataService<,>))
.As(typeof(IChartDataService<,>));
In that case, you're actually registering an open generic.
However, that's not what you have. You have types that implement an interface - a very specific interface. Let's look at what you have:
public class TreantService : IChartDataService<SourceDto, TargetDto>
Based on that, we see:
TreantService isn't a generic at all. That class, itself, has no generic type parameters.
TreantService implements a closed generic interface. Put another way, you can cast a TreantService to an IChartDataService<SourceDto, TargetDto> but you can't cast it to IChartDataService<string, Exception> or anything else.
For all intents and purposes, IChartDataService<SourceDto, TargetDto> in this case is no different than any other standard interface like IComparable or something. Once it's a closed generic like this, it's just a type.
So let's say you have a bunch of these, with a bunch of different DTO types:
public class FirstService
: IChartDataService<FirstSource, FirstTarget> { }
public class SecondService
: IChartDataService<SecondSource, SecondTarget> { }
public class ThirdService
: IChartDataService<ThirdSource, ThirdTarget> { }
Sure, they all implement IChartDataService<TSource, TTarget> but they're closed generics. You can't cast them to the same underlying interface.
Now let's say you want to store them all in a List<T>. What would the T be there to make that work?
It'd be object - the only common base class they have. You'd have to use List<object>. Which, yeah, sucks, but as you found there's no such thing as a List<IChartDataService<,>>, or a dictionary that would hold an open generic as the value. If you think about it, that makes sense, because let's say you wanted to pull them back out:
// Pretend this is a thing.
var list = new List<IChartDataService<,>>();
foreach(var item in list)
{
// What type is `item` in this loop?
// How does the compiler know what types
// to fill in for the open generic? It's
// not a dynamic language, so you can't
// "switch types" on every loop iteration.
}
Hopefully at this point you can start seeing some of the problems with what you're trying to do, and it's not a problem with Autofac - it's a problem with how the interfaces are designed and how you want to consume them.
This is why you'll sometimes see non-generic interfaces like System.IEnumerable and generic counterparts like System.Generic.IEnumerable<T>. IEnumerable for the things that are common regardless of the generic type parameters and the generic to make things strongly typed.
I can't really tell you how to solve the problem because how you approach it will largely be dependent on your application code and what exactly you're doing. But, a recap of what I've covered here is where I'd personally start if it was me:
Ignore Autofac. Try to design things that you could mock out entirely in a unit test (like having a constructor parameter with the right types that can simulate what you'll actually see). If you can't get it to compile or work with all your types without Autofac, Autofac is not going to magically somehow make it work.
Consider a common non-generic interface. Sort of like that IEnumerable vs IEnumerable<T> difference. It may be that for implementation purposes it's nice to have that generic, but the actual common methods that get called don't require the generic (or maybe could take object?).

ASP.NET Core option dependency in constructor

I'm using ASP.NET Core and I'm attempting to create a resolvable class which has an optional parameter:
public class Foo
{
public Foo() : this(null)
{}
public Foo(IValidator<FooEntity> validator)
{
}
}
I've created two constructors for this object so that if a dependency isn't found, I would assume it would just fall back to the default constructor.
However when I run my application I receive this error
Additional information: Unable to resolve service for type 'FluentValidation.IValidator`1[FooEntity]' while attempting to activate 'Foo'
I know there is probably a way to manually resolve the construction of the Foo object. But I would prefer not to do that because I will have to do this for every class that I create without a validator.
Does anyone know how to configure ASP.NET Core DI to fall back to a different constructor if the dependency is not found?
EDIT
Sorry, I should of been a bit more clear before.
This Foo class I'm referring to in really a base class for a CRUD Service, which will be used over and over again.
I'm looking for a generic solution which doesn't require me to configure each Service I create each time.
So using a lambda to resolve this is not an option, The null object pattern seems feasible but I can't comprehend how to write a generic one in which I won't have to configure for each service
I think its general behavior of Containers to resolve the constructor with the most parameters.
Basically what AddTransient does is the following:
services.AddTransient<Foo>();
//equals to:
services.AddTransient<Foo>(c=> new Foo(c.GetService<IValidator<FooEntity>()));
So you can register it yourself like this:
services.AddTransient<Foo>(c=> new Foo());
At this point in the startup class you should know if IValidator<FooEntity> has been registered. Or, if you are using reflection add this logic to your reflection code.
Difference
The difference between the 2 options is that with the first option is that the lambda function to resolve the class is created on startup. + if you change the constructor no code needs to be changed elsewhere.
If you create the lambda yourself this lambda is compiled on build, so theoretically startup should be faster (I have not tested this).
Great mindset
A great mindset is to own the libraries you are using. In Visual studio/Resharper you can decompile source-code, or you can find the repositories on github nowadays.
There you can see the source code, you can see how the services parameters is 'compiled' to the IServiceProvider (see BuildServiceProvider() method, it will give you alot of insight.)
Also look at:
ServiceDescriptor, Your type registration.
Service, the one that resolves the type.
Solution
best way to do it is this, (sorry for psuedo code but i have no editor at hand).
getTypes()
.Where(x=> x.EndsWith("Entity") //lets get some types by logic
.Select(x=> typeof(IValidator<>).MakeGeneric(x)) //turn IValidator into IValidator<T>
.Where(x=> !services.IsRegistered(x))
.Each(x=> services.Add(x, c=> null)) //register value null for IValidator<T>
You need to register the IValidator<T> first:
var services = new Microsoft.Extensions.DependencyInjection.ServiceCollection();
services.AddTransient<IValidator<FooEntity>, RealValidator<FooEntity>>();
services.AddTransient<Foo>();
var serviceProvider = services.BuildServiceProvider();
var validator = serviceProvider.GetService<IValidator<FooEntity>>();
var foo = serviceProvider.GetService<Foo>();
Assert.NotNull(validator);
Assert.NotNull(foo);

Unity suddenly fails to create class when I added an interface

In the process of decoupling some code and I extracted an interface for one of our classes, and mapped it using Unity like so
Container.RegisterType<IUserAuthorizationBC, UserAuthorizationBC>(
new Interceptor<InterfaceInterceptor>(), new InterceptionBehavior<PolicyInjectionBehavior>());
As you can see the class is UserAuthorizationBC and the interface is of course IUserAuthorizationBC. Once i did this I began to get an error in a class that I thought would not have mattered. The ctor for the class that now gives an error is as follows
public RoleAuthorizationService(IDataContractFactory factory,
UserAuthorizationBC businessProcessor)
: base(factory, businessProcessor)
{
_authBC = businessProcessor;
}
As you can see I haven't refactored it yet, I haven't even touched it, it was set up to get a concrete instance of UserAuthorizationBC and whoever created it is also injecting an IDataContractFactory which I did find mapped in our code base as you can see in following code snippet.
Container.RegisterType<IDataContractFactory, DefaultDataContractFactory>(
new Interceptor<InterfaceInterceptor>(),
new InterceptionBehavior<PolicyInjectionBehavior>());
I get an error from unity as follows
Microsoft.Practices.Unity.ResolutionFailedException: Resolution of the
dependency failed, type =
"HumanArc.Compass.Shared.Interfaces.Service.IRoleAuthorizationService",
name = "(none)".
Exception occurred while: Calling constructor Microsoft.Practices.Unity.InterceptionExtension.PolicyInjectionBehavior(Microsoft.Practices.Unity.InterceptionExtension.CurrentInterceptionRequest
interceptionRequest,
Microsoft.Practices.Unity.InterceptionExtension.InjectionPolicy[]
policies, Microsoft.Practices.Unity.IUnityContainer container).
Exception is: ArgumentException - Type passed must be an interface.
Now if I go comment out my mapping for IUserAuthorizationBC it will work fine again. I have no idea why.
actually I don't know why it ever works because if you look at the DefaultDataContractFactory it uses all generics which I would assume would always fail to resolve as at the time the unity doesn't know the type of T - see the class below.
public class DefaultDataContractFactory : IDataContractFactory
{
public DefaultDataContractFactory();
public virtual T Create<T>();
public virtual object Create(Type type);
public virtual Example<T> CreateExample<T>();
protected Type CreateFactoryType(Type instanceType);
}
So to sum things up there are two questions.
How does it even work in the first place before I added an interface for the IUserAuthorizationBC class and then added the mapping for unity - I would think that the IDataContractFactory would always blow it up.
Since it does work if I comment out the container mapping for IUserAuthorizationBC why does it stop working when I uncomment it - I would have thought it wouldn't make a bit of difference as this particular class always has been injected with a concrete instance of the UserAuthorizationBC
I thought I understood dependency injection fairly well - especially with unity but I am clearly missing the boat here.
I was going to make this a comment, but it's too long. Maybe your Unity container is configured for convention-based registrations, so your explicit registration is confusing matters. The IDataContractFactory/DefaultDataContractFactory pair needs to be explicity registered because the names don't follow the prescribed convention.
See if you have something like this in your code:
// This will register all types with a ISample/Sample naming convention
container.RegisterTypes(
AllClasses.FromLoadedAssemblies(),
WithMappings.FromMatchingInterface,
WithName.Default);
Prerequisite
Take a look at Interception using Unity. It looks like you are using interception with policy injection. Two conditions need to be met in order for a method to be intercepted. The policy needs to match on the method / type. And the type needs to opt-in to interception in the Unity registration by selecting an interceptor (InterfaceInterceptor, VirtualMethodInterceptor, or TransparentProxyInterceptor).
Answers
Commenting out that registration effectively opted-out that type from using interception.
You opted-in to interception but you told Unity to use interface interception. You are not resolving an interface, so it doesn't know how to generate a proxy for interception.
Possible solutions
Leave the registration as-is with the InterfaceInterceptor and update all constructors to use your new interface instead of the concrete type.
Change your new IUserAuthorizationBC registration to use VirtualMethodInterceptor and update any methods you want to be able to be intercepted to be virtual.
Change your new IUserAuthorizationBC registration to not specify an interceptor to effectively opt-out of interception.

Is there a good way to register the same object twice in StructureMap?

I have some feature toggles that I include in my .NET application which uses StructureMap. I want to register the feature toggles for two purposes.
Display current state of all IFeatures on a diagnostic page.
Use certain instances in constructors of services that rely on given IFeature implementations
Here is my setup. What I'm wondering is, am I doing this right? Is there a better way I could be doing it?
class HotNewFeature : IFeature { ... }
class ServiceThatUsesFeature
{
public ServiceThatUsesFeature(HotNewFeature hotNewFeature) { ... }
}
// Type registry setup
For<HotNewFeature>().Singleton().Use<HotNewFeature>();
For<IFeature>().Singleton().Add(c => c.GetInstance<HotNewFeature>);
For<ServiceThatUsesFeature>().Singleton().Use<ServiceThatUsesFeature>());
// Get all instances on the diagnostics page:
IEnumerable<IFeature> features = ServiceLocator.Current.GetAllInstances<IFeature>();
I expect that on the diagnostic page, features would in this case contain an IEnumerable with a single element, the instance of HotNewFeature.
Use the Scan feature to register all types that implement IFeature. That will satisfy your first need, to display a list on the Diagnostics page.
If a service needs a specific implementation, it should declare the specific type it needs (HotNewFeature) instead of the interface (IFeature) in the constructor. You have done this correctly in your example. At that point you do not need to do anything more in StructureMap. If you request ServiceThatUsersFeature from StructureMap, and it relies on a concrete class (HotNewFeature), StructureMap will know how to instantiate that concrete class.

How to register a helper class for passing object instances in Unity

I have a scenario where I need to inject an instance of a type using a helper class. In our system we are currently using Unity to inject that object into various layers.
Here is what I currently have:
container.RegisterInstance<ITest, new Test()>();
But instead of that I would like to use a helper class that would create the instance for me:
container.RegisterInstance<ITest, Helper.GetITestIntance()>();
container.RegisterType<ITest>(
new ContainerControlledLifetimeManager(),
new InjectionFactory(o => Helper.GetITestIntance()));
According to this: http://social.msdn.microsoft.com/Forums/en/wpf/thread/b71665b9-cc71-4c88-9776-6ccb4f871819 there does not seem to be a direct way. You can either register an instance that will be used, or register a "Type" that the container will instantiate on his own at some moments when it is required. There does not seem to be any way to register a "factory", nor the Type-registering methods do not take any delegates/callbacks..
There could be some way with use of Container Extensions - maybe you will be able to intercept the query for an instance and then provide your own response.. I think this a good place to start reading on it:
http://visualizationtools.net/default/unity-objectbuilder-part-i/
http://visualizationtools.net/default/unity-objectbuilder-part-ii/
edit: sorry, sorry, I've overlooked the LifetimeManager registration paramter. It seems this is exactly what you are looking for: http://tavaresstudios.com/Blog/post/Writing-Custom-Lifetime-Managers.aspx
So, write a factory in form of LifetimeManager, the creation would be done in GetValue method, and register a Type with your this Manager - and the Unity will ask the manager for object instances.

Categories

Resources