Say I have a source and destination class that is mapped using AutoMapper.
The destination has a logger service injected into the constructor.
However, I don't know how to get the service injected into the constructor through StructureMap?
I've tried the following:
Mapper.Initialize(m =>
{
m.ConstructServicesUsing(ObjectFactory.GetInstance);
});
which didn't prevent me having the exception on the mapping call, I guess because the service isn't being injected in properly.
I also tried the following:
CreateMap<Source, Dest>()
.ConstructUsing(x=> ObjectFactory.GetInstance<ILoggerService>());
But I get the error: cannot convert Lamda expression to delegate type, yet all the examples I have seen use this method?
The lambda you pass into ConstructUsing must return an instance of the destination type. So in your case, you would want to do this:
CreateMap<Source, Dest>()
.ConstructUsing(x=> ObjectFactory.GetInstance<Dest>());
Assuming you have StructureMap setup correctly, it should create the Dest object and inject the ILoggerService for you.
You can also do this:
Mapper.Configuration.ConstructServicesUsing(container.Resolve);
Mapper.CreateMap<Source, Dest>().ConstructUsingServiceLocator();
Related
When creating an service container in Symfony2 you mostly pass "static" arguments (like other classes etc.) to its constructor.
However I'd like to create a factory and therefore I need to be able to pass an dynamic argument to the service constructor.
The examples I found ( e.g. http://symfony.com/doc/current/cookbook/service_container/factories.html) are all ending up using static arguments as argument.
But what do I have to do, if I want my factory to decide which object to return based on (for example) user input?
I have some problems understanding why service factory should not work on your case. Do you need to return different service class unrelated to each other?
What I see from the factory example is that you could do something like this:
class NewsletterFactory
{
public function __constructor(...)
{
// Receive arguments needed to create the service below
}
public function get()
{
// Say the variable $userInput exists and is derived from constructor
if ($userInput === 'string')
return new NewsletterManager($dynamicArgument1);
if ($userInput === 'integer')
return new AnotherNewsletterManager($dynamicArgument2);
return new DefaultNewsletterManager();
}
}
Now, if this doesn't fit your needs. You can also create a service say CustomFactory that returns what you need. What is returned is not directly a service, so you can do whatever you want. But this would prevent you from requesting the objects created by CustomFactory from the dependency container.
Similar to that is the FormFactory. It is the factory used to instantiate form type. But the FormFactory is more powerfull since it is coupled with a dependency injection tag and a compiler pass, which register each types into the dependency injection system so they can be retrieved on their own. I don't exactly all the internals of the Form component but I think it could solve your problem if other methods do not.
Regards,
Matt
Consider this code:
public function showActiveJobsAction($slug)
{
$em = $this->getDoctrine()->getEntityManager();
$category = $em->getRepository('JobeetBundle:Category')->findBySlug($slug);
if (! $category) {
throw $this->createNotFoundException('Unable to find Category entity.');
}
$jobService = $this->container->get('job_service');
$category = $jobService->populateCategoryByItsActiveJobs($category);
return $this->render('JobeetBundle:Category:jobs.html.twig', array(
'category' => $category,
));
}
job_service need JobeetBundle:Category repository to work. The repository is passed to service constructor. It's all defined in services.yml
So in this case I end up with two instance of JobeetBundle:Category repository class?
If yes how can I change my design to do it better?
Probably it's better to create code just like:
$jobService->getCatetoryWithActiveJobsByItsSlug($slug)
but I still wonder if container looks for object existance before create it?
When you get a service from the container, by default, you get always the same instance. It is also the same instance when this service is injected into another one.
So you don't have two worry, you get only one instance of the service job_service.
Here is an extract from the Symfony2 book, chapter Service Container:
As an added bonus, the Mailer service is only created once and the same instance is returned each time you ask for the service. This is almost always the behavior you'll need (it's more flexible and powerful).
Hope that helps!
In general, you wont get duplicate repositories (or services) in Symfony2 so no worries there.
This:
$jobService->getCatetoryWithActiveJobsByItsSlug($slug)
Is a better approach simply because it hides the entity manager/repository stuff from your controller. You could (in theory at least) swap out the entire Doctrine2 engine with something else and still have your controller code work.
A class has a unique constructor taking IMyInterface as its argument. If I define a concrete type of IMyInterface and registers it to StructureMap then there is no issue and my class can be instanciated with this concrete type.
However, in some cases, no concrete type will be registered. In that case, I would like to receive null for the IMyInterface parameter. Instead I get an exception:
StructureMap Exception Code: 202
No Default Instance defined for PluginFamily IMyInterface.
Is it possible to define a default value for a missing plugin?
Context: my class, which is a service, uses the Spark view engine and defines some default namespaces. The service uses a ISparkNamespacesProvider (IMyInterface) to add aditional namespaces. The client app may register such a provider or not. That's why the constructor of the service will receive either a provider or none.
Taken from here:
For<IService>().Use<MyService>()
.Ctor<IMyInterface>("nameOfParameter").Is(null);
But You should think about why Your class is dependent on IMyInterface. If it's optional - that's a code smell. Maybe You should refactor it out as method argument for method that needs it or as settable property.
There shouldn't be need for switching between concrete implementation and null. When composing dependency graph at composition root, You should know exactly what will be Your dependencies w/o .If(isSomething()).Use<MyService>().Ctor<IMyInterface>(null).
You might want to check out this tekpub presentation and this book (look for so called MEAP access) about DI and IOC.
One way to accomplish what You want is using so called 'poor man dependency injection'. That is - to define second constructor:
public MyClass():this(null){...}
But I wouldn't recommend that.
StructureMap now supports this case via UseIfNone https://structuremap.github.io/registration/fallback-services/
I was using a ServiceLocator which i was DIing with Unity
public ServiceLocator(IUserStore userStore, IProdcutsStore productsStore, ...etc) {}
public IUserStore UserStore
{
get { return userStore; }
}
This all worked fine, but I wanted lazy instantiation of the repositories as they have quite sparse use.
So my ServiceLocator now looks like
public ServiceLocator(IUnityContainer container) {}
public IUserStore UserStore
{
get { return (IUserStore)container.Resolve(typeof(IUserStore)); }
}
// ...etc
I'm now getting a really unhelpful ResolutionFailedException error
Resolution of the dependency failed,
type =
"DomainModel.DataServices.Interface.IUserStore",
name = "". Exception message is: The
current build operation (build key
Build
Key[DomainModel.DataServices.Interface.IUserStore,
null]) failed: The current type,
DomainModel.DataServices.Interface.IUserStore,
is an interface and cannot be
constructed. Are you missing a type
mapping? (Strategy type
BuildPlanStrategy, index 3)
Telling me my interface type cannot be instantiated because it is an interface is pretty pointless. I know it's an interface, that's why the container is supposed to be resolving it for me!
Anyway, the point to note here is that I know the type mapping in the config is fine, as when I was injecting the type interface directly instead of trying to lazy load, it resolved it with no problems.
What am I missing that means something somewhere has to change in order to lazy load this way?
Update: I am guessing what's happening here, is that when I DI the container into the ServiceLocator, the "main" container is instantiating a new container each time which is then not configured properly. I think maybe I need some way to specify that I was to pass this in as the container, rather than resolve it with a new instantiation.
You're going in a somewhat wrong direction... At first you've had a testable class that declared its dependencies in the constructor and you turned it into non-so-testable, asking for "something" inside a container... No good =(
You should either implement some factory interface for your expensive object and require it in the constructor, or (if you can) switch to Unity 2.0 and use the Automatic Factories:
public ServiceLocator(Func<IUserStore> userStoreBuilder)
//...
public IUserStore UserStore
{
get { return userStoreBuilder(); }
}
If you want to only create the instance of that object once, you can add cahcing to that property, or with .NET 4.0 you can try asking Lazy in the constructor.
P.S. Oh, yes. And answering your particualr question =) If you still want to inject an instance of your container somewhere else, you need to first register it inside itself =)
container.RegisterInstance<IUnityContainer>(container);
Fix (see comments) DO NOT register a Unity container inside itself, this will cause StackOverflowException in container.Dispose(), the correct instance will be injected as a dependency without the registration.
I am fairly new to StructureMap, but my understanding is that there are two ways of getting an instance from the ObjectFactory:
By type (i.e. ObjectFactory.GetInstance<IFoo>())
By type and name (i.e. ObjectFactory.GetNamedInstance<IFoo>("foo.bar"))
I have seen a multitude of examples out there demonstrating how to create an MVC Controller Factory that will provide controller instances using StructureMap, and in most cases I have seen, they are using the method from option #1 above.
Let's say we have some controller that accepts a repository/DAO interface as a constructor arg...
public class FooController : Controller
{
public FooController (IFooRepository fooRepository)
{
// constructor code goes here
}
}
Using the interface class gives me the ability to "inject" any implementation of that interface in to my controller. What if for two different actions, I want to inject different implementations? Perhaps in one case, I need an implementation of my repository that will query a SQL Server database, and in another case, I need an implementation that will get data from an XML file or through a Web Service call.
It seems that if you use the ObjectFactory.GetInstance() method, you would be restricted to only providing your controller with a single implementation of your repository interface.
However, if you go with named instances, then you will end up having to create the instances based on the name of the controller that the MVC framework provides. In most cases, this will typically be the controller name coming from the URL, but it's really up to the route configuration. This seems like it could be very confusing, and would only get more confusing as the number of routes increased.
Is there any alternative method that would allow for different controller instantiation strategies without using named instances? Would it be a better idea to just create separate controllers, and make sure that all the actions in any given controller will be valid for the same concrete instance of a repository/DAO class?
For what it's worth, I ended up going with named instances, where the names of each instance are based on the name of the controller that the MVC framework pulls from the URL.
For instance, the URL /foo/DoSomething might get an IController instance from the ObjectFactory that is instantiated with a Repository object that uses the SqlClient API for data access. A URL such as /foo.webservice/DoSomething would then create an instance of the same concrete controller class, but pass that instance's constructor a repository object that uses a web service for data access.
There are several ways to override StructureMap's default auto-wiring behavior for constructor arguments. In my case, I used the CtorDependency and Is methods, and had mappings that looked something like this...
// create a named instance for the "foo" controller that uses the SqlClient based repository
InstanceOf<IController>()
.Is.OfConcreteType<FooController>()
.CtorDependency<IFooRepository>()
.Is(new FooRepositorySql(Constants.FooConnectionString))
.WithName("foo");
// create a named instance for the "foo.webservice" controller that uses the Web Service based repository
InstanceOf<IController>()
.Is.OfConcreteType<FooController>()
.CtorDependency<IFooRepository>()
.Is(new FooRepositoryWs(Constants.FooServiceUrl))
.WithName("foo.webservice");