Ninject Binding Conditionally When Injecting To A Generic Interface - dependency-injection

I have the following code structure which I want to compose with Ninject:
ICommandHandler<FindAssetById, Asset> handler =
new SecurityCommandHandlerDecorator<FindAssetById, Asset>(
new SecurityValidatorComposite<FindAssetById>(
// This list contains both non-generic as generic implementations
new ISecurityValidator<FindAssetById>[]
{
// Contains type constraint 'where T : IRequireAccessToAsset'
new RequireAccessToAssetSecurityValidator<FindAssetById>(...)
}),
new FindAssetByIdHandler(...));
I have this setup in my Ninject:
//Bind Composite To Handler
_kernel.Bind(typeof(ISecurityValidator<>))
.To(typeof(SecurityValidatorComposite<>))
.WhenInjectedInto(typeof(SecurityCommandHandlerDecorator<,>));
//Bind Interface To Concrete
_kernel.Bind(typeof(ISecurityValidator<>))
.To(typeof(RequireAccessToAssetSecurityValidator<>))
.WhenInjectedInto(typeof(SecurityValidatorComposite<>));
_kernel.Bind(typeof(ISecurityValidator<>))
.To(typeof(RequireAccessToSecureAssetSecurityValidator<>))
.WhenInjectedInto(typeof(SecurityValidatorComposite<>));
I want to be able to conditionally bind the concrete validators if the calling parent implements the corresponding interface.
For instance a class like this:
public class FindAssetById: IRequireAccessToAsset{
}
Should get the RequireAccessToAssetSecurityValidator but not the RequireAccessToSecureAssetSecurityValidator. With Ninject the current way it is setup it obviously gets both. But with Ninject you can't call WhenInjectedInto and a conditional When statement. With how difficult this has been I'm assuming at this point I am way off base and how to implement and any suggestions to fix this would be very helpful.
In Simple Injector the equivalent would be something like this:
container.Register(
typeof(ISecurityValidator<>),
typeof(SecurityValidatorComposite<>),
Lifestyle.Singleton);
container.Collection.Register(typeof(ISecurityValidator<>), assemblies);
container.Collection.Append(typeof(ISecurityValidator<>),
typeof(RequireAccessToAssetSecurityValidator<>));
And somehow it knows to apply the right one or the example provided is incomplete. I'd like to replicate something like this with Ninject as I think the solution from here is fairly clean and where I got most of my code from https://github.com/dotnetjunkie/solidservices/issues/4. This is my first foray into really trying to understand DI and how I can apply the decorator pattern with it so any help would be greatly appreciated.

Related

Laravel 4: how to inject another class in a eloquent model

I'm trying to use the built-in laravel's Ioc container to inject a PageManager class inside a Page model and I'm a little lost.
What I'm trying to achieve is something like that:
class Pages extends Eloquent {
public function __construct(PagesManagerInterface $manager, array $attributes = array())
{
parent::__construct($attributes);
$this->manager = new $manager;
}
public function saveToDisk()
{
$this->manager->writeToFile();
}
But I obtain this error:
ErrorException: Argument 1 passed to Pages::__construct() must be an instance of PagesManagerInterface, none given.
I tried to add this in app/start/global.php:
App::bind('Pages',function(){
return new Pages(new PagesManager);
});
But is seems ignored by the framework, and also i don't know how to insert the $attribute array into this declaration.
I'm a little lost so any help is appreciated!
It's not a good idea to overload a model's constructor because new instances can be spawned behind the scenes through various methods, like Model::find().
When that happens, the dependencies you're asking for in your custom constructor aren't being passed in because the Model class isn't aware of them. So, you get that error message.
See the find() method here: http://laravel.com/api/source-class-Illuminate.Database.Eloquent.Model.html#380-397
See this post by Jason Lewis: http://forums.laravel.io/viewtopic.php?pid=47124#p47124
I think that what you need is:
App::bind('PagesManagerInterface',function(){
return new Pages(new PagesManager);
});
This tells Laravel to inject a new Page object everytime it needs an instance of your PagesManagerInterface wich wasn't passed while creating the model.
In Laravel you can use the IoC Container:
public function saveToDisk(){
$managerObject = app()->make('path\to\class\PagesManagerInterface');
$managerObject->writeToFile();
}

Castle windsor property injection

Im a windsor noob and im having some problems getting dependency injection to work. im using a asp.net web application.
I have done the following
public interface IHandler{
...
}
public class Handler : IHandler{
...
}
then i try to register the code in global.asax application_start
container.Register(Component
.For(typeof(IHandler))
.ImplementedBy(typeof(Handler))
.Named("handler"));
When i want to use the Handler i create a property
public IHandler handler{get;set;}
but when i try to use it, it is null? why? am i missing someting?
Best regards
UPDATE
The only thing i doto register/resolve is the following:
container.Register(Component
.For(typeof(IHandler))
.ImplementedBy(typeof(Handler))
.Named("handler"));
and:
container.Resolve<IHandler>();
Do i need to do something else, Does it work to run this att application start?
UPDATE 2
Can the problem ocour because im trying to dependency inject on an ascx controll?
Make sure the component that has the IHandler property is also registered (and resolved) in Windsor.
You said this is for an ASP.NET application. The default lifestyle of Windsor components is singleton. Are you sure you want this component shared like that? You may want a transient or per-web-request lifestyle for this component.
Try removing the name from the registration, like this:
container.Register(Component
.For(typeof(IHandler))
.ImplementedBy(typeof(Handler)));
Alternatively, if you must name the component, you can use ServiceOverrides for the consuming class:
container.Register(Component
.For<SomeConsuer>()
.ServiceOverrides(new { handler = "handler" }));
If you are going to be registering several interfaces/services, then I recommend registering by convention (this is recommended in the docs). Consider this:
container.Register(
AllTypes.FromAssemblyNamed("Assembly")
.Where(Component.IsInNamespace("Assembly.Namespace"))
.WithService.DefaultInterface()
.Configure(c => c.LifeStyle.Transient));
This method performs matching based on type name and interface's name. More info Registering Components By Convention

windsor resolve dependency based on calling controller

Let's say I have a (crappy pseudo code):
interface IUserService
{
....
User CreateUser(bunch of parameters)
....
}
With one implementation that get's injected into a bunch of different controllers.
The concrete UserService is injected with a
interface IHRService
{
bool ValidateInfo(user _user)
}
This is for additional/optional validation and has at least 2 implementations. ValidateInfo is called from UserService's CreateUser function. I want to inject different IHRService into UserService based on what controller is calling the UserService - this is so I can call the same CreateUser function from multiple different screens and be able to skip the additional validation in one but not the other.
Is something like this possible with windsor or am I going about this the wrong way? Should I get the correct IHRService inside of the particular controller then pass that into the CreateUser function?
I don't know if I understood you well but it seems that you could inject into UserService and abstract factory that creates a concret implementation of IHRService depending on some options at runtime. Windsor deals with abstract factories very well for that scenarions. Does it make sense ?

For specific controller make Windsor instantiate different classes

I use S#arp Architecture which uses Windsor Castle for IoC. I got a new controller now that, unlike all other controllers in the project, need a different implementation of the same interfaces. I.e. all controllers use ProductsRepository: IProductsRepository as implementation, but the new one has to use SpecificProductsRepository.
How do I configure it to recognize and manage this automatically? Either in pure Windsor way, or with ASP.NET MVC help (e.g. in my custom controllers factory).
OK looks like I need subcontainers. Still searching.
An easier and much simpler way would be to use Windsor's service overrides.
E.g. register your repos like so:
container.Register(Component.For<IProductsRepository>
.ImplementedBy<ProductsRepository>()
.Named("defaultProductsRepository"),
Component.For<IProductsRepository>
.ImplementedBy<SpecificProductsRepository>()
.Named("specificProductsRepository"));
which will ensure that the default implementation is ProductsRepository. Now, for your specific controller, add a service override like so:
container.Register(Component.For<NewController>()
.ServiceOverrides(ServiceOverride
.ForKey("productsRepository")
.Eq("specificProductsRepository"));
You can read the docs here.
Edit: If you want to register your repositories with AllTypes, you can adjust the registration key e.g. like so:
container.Register(AllTypes.[how you used to].Configure(c => c.Named(GetKey(c)));
where GetKey e.g. could be something like:
public string GetKey(ComponentRegistration registration)
{
return registration.Implementation.Name;
}
OK, these days I tend to answer my own questions... so here it is for those who need it.
// create subcontainer with specific implementation
var mycontainer = new WindsorContainer();
mycontainer.Register(AllTypes.Pick()
.FromAssemblyNamed("My.Data")
.WithService.FirstInterface()
.Where(x => x.Namespace == "My.Data.Custom")
.Configure(x => x.LifeStyle.Is(LifestyleType.PerWebRequest)));
container.AddChildContainer(mycontainer);
ControllerBuilder.Current.SetControllerFactory(new ExtendedControllerFactory(
new Dictionary<string, IWindsorContainer> { {"", container}, {"Lm", mycontainer} }));
The controller factory chooses appropriate container based on name. The biggest challenge there is to call appropriate container's Release(controller) at the end of request, i.e. remember which container was used to instantiate controller. But this can be solved in several ways I suppose - remember in thread-specific (in HttpContext), remember in BaseController property, remember in internal dictionary, etc.

MVP : other constructor's parameters than view and model?

I'm experimenting with implementing a lightweight mvp framework with Delphi 2009.
Views are passive but supports databinding (via an interface property).
I'm facing a dilemna:
I've several very similar views/presenter/model triad, ie :
order form and a customer form = behavior and logic is the same but the datasource for databinding is different and the form title too. the datasource is a common property for all my models so it's not a problem, to set the form title, I'm forced to hard code it in my presenter InitView method
All is working good, but I'm in a situation where I have several simple mvp triads very similar. I want to refactor it but in that case I will have to pass some parameters to the mvp constructor.
So far I'm doing like that :
Create the view
Create the model
Create the presenter and inject model and view in the constructor
In fact, I'm facing a choice :
Having some very generic views/presenter, use them like that but inject 1 or 2 parameters in the constructor
Having some views/presenters superclass, and derive all my similar view/presenter from them and set some specific values in the overriden methods.
Can you give me some hints / advices ?
(sorry if i'm not very clear)
Fred,
I will choose 1 & 2 in a way that is having an abstract views/presenters that contain generic behaviors and creates abstract functions that could be possible specific behaviors implemented by subclasses.
for example,
public abstract class AbstractPresenter{
// subclass will be implemented
public abstract void InitView(Model model, View view);
}
and then you might have sublcasses, OrderFormPresenter and CustomerFormPresneter extends from AbstractPresenter.
public OrderFormPresenter extends AbstractPresenter{
public void InitView(Model model, View, view){
// do something specific values
}
}
public CustomerFormPresenter extends AbstractPresenter{
public void InitView(Model model, View, view){
// do something specific values
}
}
Please, correct me if it goes wrong direction.
I hope it helps.
Tiger
I'd create a generic view/presenter with parameters and subclass only when needed.
Another approach (and the way that I once solved this problem so it worked very well) is to build a generic "metadata" interface into the model, and the view (either interfaces, or via class inheritance) then use these generic interfaces in your presenter. I chose to use inheritance for my model, and interfaces for my view (was easer to slap a interface on an existing form than to require form/frame inheritance across the board). In my solution, the constructor for the presenter took 3 parameters, the model, the view and the "MVP name". I used the name of the MVP to load settings which were specific to the current scenario.

Resources