Silex - real DI vs injecting $app which looks like ServiceLocator? - symfony

I read the article yesterday: https://igor.io/2012/11/09/scaling-silex.html
And another one http://davedevelopment.co.uk/2012/10/03/Silex-Controllers-As-Services.html
So a conceptual question rised in my head:
Currently I do have a lot of controllers in separate classes. I overwrite controller_resolver to create a controller class instance and inject $app into contoller's constructor.
I define routes like this $app->get('/hello', 'HelloController::indexAction') <- my controller resolver will create new HelloController($app); - so far so good.
But to be honest it became a ServiceLocator pattern, not a DependencyInjection, because I do inject whe whole $app which looks like ServiceLocator usage.
Now I am in doubt: should I leave it as is (because it works well) or try "controllers as services" to inject only those sevices on which my controller really depends on? May be my SeviceLocator approach will hit me some day? (people say that DI is better for tests).
I have also looked into Symfony Framework Bundle: class Controller extends abstract class ContainerAware which also have the whole $container injected! ServiceLocator approach in full stack framework?
Any recomendation? Pros/cons?

The symfony2 full-stack framework
The framework uses the Dependency Injection pattern and not the Service Locator pattern.
All controllers aren't services by default. The ContainerAware class includes methods to get access to the service container, so you can call Services inside the Controller.
If you are going to use a Controller as a Service you need to remove the Controller extend. All dependencies you want to use inside the controller needs to be injected by the Service Container.
Read more about this in a blogpost by richard miller, one of the core contributors of Symfony2.
The Silex micro-framework
The Silex micro-framework provides the bare bones of a framework, it's up to you how the architecture looks and which patterns you use.
The Silex documentation uses Controllers that aren't Services. It injects the complete Service Container inside very Controller:
$app->post('/post/{id}-{slug}', function($id, $slug) use ($app) {
// ...
});
If you want to use controllers as service, you should only inject the services you want to use inside the controller.
EDIT: The Controller::action syntax refers also to a Controller that isn't a Service. The Controller:action notation is used to refer to Controllers as Services.

There's lot's of personal preference involved here. What you've done already is a good (enough) step to organising your code base. Some people like myself take things a step further and move our controllers to the container, rather than injecting it in to some kind of BaseController. This happens in both Silex and the full stack Symfony framework.
My advice would be to leave everything you have as is, then try defining your next controller as a service, by practising BDD.
For example, the behaviour of a UserController view action:
It should retrieve the user from a database
It should render the user with a template
Not once does it mention retrieving the database or the template renderer from a container. I'm comfortable not injecting the container, so I'll only inject what I'm led to believe I need by BDD.

Related

Implement mapster dependency injection via Simple Injector IoC container

I'm using Mapster for mapping and Simple Injector in my .net framework 4.8 MVC and WebApi controllers.
I'd like to inject Mapster as a dependency in my services but I can't figure it out how to make it work with Simple Injector. The Mapster documentation is really vague in my opinion:
Mapster - Dependency Injection
Mapster - References
Can someone provide and example of how to use Mapster with Simple Injector? Doesn't matter if the controller is mvc or a web api.
The code I need is the configuration in Application_Start in Global.asax.cs and in the service concrete. Thanks!
I'm unfamiliar with Mapster, but after looking at the documentation link you provided, I'm assuming that integrating with Simple Injector can be done as follows:
var config = new TypeAdapterConfig();
container.RegisterInstance(config);
services.RegisterSingleton<IMapper, SimpleInjectorMapper>();
Where SimpleInjectorMapper is:
public sealed class SimpleInjectorMapper : ServiceMapper
{
public SimpleInjectorMapper(
Container container, TypeAdapterConfig config)
: base(container, config)
{
}
}
The 'trick' here is that the Simple Injector Container class implements System.IServiceProvider, which is the base interface used by most of the DI facilities in .NET and .NET Core and is the base interface that the MS.DI abstraction relies on. Mapsters ServiceMapper expects an IServiceProvider in its constructor, which is now provided using the Container.
There are a few downsides to this approach. Main downside is that in case a dependency is missing, you'll get a more generic "no service registered" exception in line with what MS.DI would throw, instead of a very information rich exception that Simple Injector would throw in case the resolve would fail when you call Container.GetInstance.
This, however, is a as far as I can go in providing an answer. If you wish to integrate more deeply with Simple Injector, you likely need a more complex SimpleInjectorMapper implementation, but others (e.g. the designers behind Mapster) need to help you with that. At least, hopefully, this answer will get you started.

Unity DI - C# Dependency Injection how to use with a repository class constructor ? It's only intended for controllers?

i wanna know if it's possible to inject dependency for a class constructor as it is injected for controllers, i have the following cenario as an example:
An AccountController which depends on an AccountRepository like bellow:
public AccountController(IAccountRepository repository)
The dependency is injected perfectly using Unity DI, which have the following configuration:
container.RegisterType<IUserStore<ApplicationUser>, UserStore<ApplicationUser>>(new HierarchicalLifetimeManager(), accountInjectionConstructor);
container.RegisterType<UserManager<ApplicationUser>>(new HierarchicalLifetimeManager());
container.RegisterType<IdentityDbContext<ApplicationUser>, ApplicationDbContext>(new HierarchicalLifetimeManager());
The problem is that i have a class AuthorizationServiceProvider which also needs the AccountRepository... In this case, how would i instantiate or use this AuthorizationServiceProvider class without having to instantiate and provide it all the dependencies?
Provider = new SimpleAuthorizationServerProvider>(),
This provider is set inside the Startup class and called before the Unity DI config initializes...
Here the visual studio complains that there's no argument given that corresponds to the class constructor, but if i provide a new AccountRepository i'd have to provide all it's dependencies as well, (ApplicationDbContext context, UserManager userManager) which are already provided for the Unity DI when creating the controllers....
Could somebody help me please?
Thanks in advance...
how would i instantiate or use this AuthorizationServiceProvider class without having to instantiate and provide it all the dependencies?
You can't. This is actually the core of what we're trying to achieve with Dependency Injection. Your application code should let go of the control over its dependencies. This means that your application code should not create an AuthorizationServiceProvider. Rather, it should let a third-party provide this dependency. Typically, this means you require the dependency be supplied using Constructor Injection.
Letting application code create these dependencies itself causes problems, typically referred to as the Control Freak anti-pattern or Dependency Inversion Principle violation. It causes strong coupling, which can hinder maintainability.
When working with Dependency Injection, this third-party is called the Composition Root. The Composition Root is:
a (preferably) unique location in an application where modules are composed together.
With DI, only the Composition Root will create graphs of objects. You are using Unity, which is a DI Container. The DI Container acts as the Composer, which is part of your Composition Root.
Instead of using a DI Container, you can build the object graphs by hand, which means you will have to create a complete tree of dependencies at once. This practice is called Pure DI. Still, the Composition Root is the location where those object graphs are created; with or without a DI Container.
Your view of DI might be troubled by the use of the standard Identity template that Visual Studio provides. From a design and DI perspective, however, this template is horrifying.
Either way, all these stated concepts, patterns and anti-patterns are described quite thoroughly in the book Dependency Injection in .NET by Mark Seemann.

ASP.NET 5 dependency injection outside of Controllers and Views

Each tutorial or example that I've found for using DI in ASP.NET 5 only shows how it works with Controllers and Razor Views. I need to use DI for other classes but don't know the proper way to resolve types and provide an instance. Right now I have an instance of a HackyDependencyResolver that everything must reference in order to get the proper instances. I want to either access ASP.NET's service resolver or follow some other best-practice for resolving dependencies.
For example if I have
public class SomeClass
{
public SomeClass(IUseMe useMe)
{
}
}
which is not an ASP.NET MVC Controller. I need a pattern for resolving a correct instance for IUseMe when SomeClass is created. Certainly I can make my own global factory, but is that the best way?
DI has nothing to do with asp.net, controllers or views. In the end all are classes. Considering that an action is an entrypoint in your app, any service you need there should be injected, The service itself has some dependencies and those will be injected automatically by the DI Container when it instantiates the controller.
All you have to do is to define your services (not every object needs injected deps) then register those services into the Di Container.
How do I resolve IUseMe so that I'm not dependent on a particular implementation?
You don't. The Di Container does that based on configuration, when the controller is instantiated. Everything has a flow, you don't just pick classes out of thin air and say "I want this created by the Di container". OK you could, but it would be the wrong approach.
The whole point of using a DI Container is not to care about instantiating services. The framework takes care of integrating with the container, your only job is to define the classes properly and to configure the container .

Lazy loading dependencies with symfony DI

Currently I've got a Symfony2 DI container instance ready with a service and all it's dependencies. Lets say for example I have a Car class and it has Engine and Lights as dependencies.
In my current setup both these dependencies are automatically created through setter injection when the Car object is created, but it might very well be that my Car object won't need it's lights this time around thus it doesn't explicitly need to create an instance of this dependency.
Is there a way to achieve this in Symfony DI? Thus only creating an instance of the Lights object when needed? My guess is it'll be some sort of Proxy implementation like Doctrine has but as far as i've seen it doesn't exist in Symfony DI.
Inject the dedendencies that are mandatory through the Constructor via your services.yml, automatically.
If you have optional dependencies inject them through a setter in your Controller when you need them.
$this->container->get('cars')->setLights(new \Namespace\Lights());
Of course your Cars class must be designed like so and you have to direct the injections yourself in your controller, or whereever needed, code.
Question is already answered, but for who needs this functionality, lazy services are implemented in Symfony 2.3.
You need to install the ProxyManager bridge.
You can find official documentation here.
A very interesting question, but I don't think it's possible within Symfony2's Dependency Injection Container. The container is only aware of what you tell it - in this case, you have a dependency that's conditional on a specific use-case. Plus, the registration of services happens early on in the app's life, so I don't see how you could get this to work.
Maybe you should use the Factory pattern. Register a CarFactory as a service, and then when fetching a Car instance, you can specify that it should include a Light dependency.
Can I ask why you want to achieve this? There may be a simpler solution.
It's not a pretty workaround, but you can try injecting the whole DIC, then getting the Light and Engine services when neccessary.
I was thinking about something like this method in the Car class:
protected function getLightService()
{
if (!$this->light) { //so we reuse the first instance
$this->light = $this->dic->get("car.light");
}
return $this->light;
}

Mix "traditional" controllers with Castle-Windsor controllers. Is this possible?

I'm integrating a series of controllers into an existing project which already contain controllers which use Castle Windsor for DI/IoC. I've modified the Installer to only register Controllers in a certain namespace (specifically the root). This modification appears to be working. When I try to access my controllers, which do not use Castle Windsor and are located in a different namespace (specifically, a custom Area), I get the error message: "No component for supporting the service [Controller Name] was found".
Is it possible to mix "traditional" controllers with controllers which use Castle Windsor in a single project?
Does this make sense?
If you are getting that error, you are trying to resolve the controller (directly or indirectly) through the container.
If you have a separate logic path that needs a controller that isn't register from the container, nothing is stopping you from calling new MyController().
As an aside, thinking in terms of the controller using the container is somewhat backwards. The container manages your instances--your instances have no idea whether they are container-managed or not.

Resources