I have a service class MyService that I use on the controllers by passing it as a parameter in the controller constructor. Needless to say, I use a factory to instantiate the controllers, and use the factory's service locator to retrieve MyService and then pass it to the instantiated controller.
// factory
$sl = $sl->getServiceLocator();
$ms = $sl->get(MyService::class);
return new MyController($sm);
Now, I need that service in the view. I tried creating a view helper that would take MyService as a dependency, (similar to the controller) like this:
// view helper factory
$ms = $sl->get(MyService::class);
return new MyServiceViewHelper($ms);
However, it won't correctly instantiate MyService. It crashes saying:
Catchable fatal error: Argument 1 passed to MyService::__construct() must be an instance of MyRepository, none given, called in /my-path/vendor/zendframework/zend-servicemanager/src/AbstractPluginManager.php
MyService takes about 3 repositories as dependencies, that are provided naturally by the MyServiceFactory. However, for some reason, the view helper isn't properly calling the factory or something like that, resulting in an incorrect instantiation.
So my next thought is: maybe this is not how you inject services to the view. So now I ask:
How do I inject services to the views themselves?
Edit: please don't say "pass it from the controller".
The viewhelpers are retrieved from a seperate pluginmanager HelperPluginManager, the same applies for the controllers which are managed by the ControllerManager.
To retrieve services from the "root" serviceManager you have to call getServiceLocator() in your factory as you did in the controller factory.
So your code should be:
// view helper factory
$sl = $sl->getServiceLocator(); //This line will do the trick
$ms = $sl->get(MyService::class);
return new MyServiceViewHelper($ms);
Related
I'm trying to pass Param data from view to controller and I'm having trouble. Here's what I'm currently trying to do.
View:
<form action="${doStuffURL}" method='post' params="[keyId: ${mykey.id[i]}]"><g:actionSubmit value="doStuff"/></form>
Controller:
def myObjectService //inject service object
def doStuff = {
myObjectService.doStuff("${params.keyId}") //this blows up because it's value of NULL
myObjectService.doStuff(8) //this works fine
}
It gets to the method block because the error log says "no signature of method MyObject.doStuff() is applicable for argument types: values: [null]." Also, I'm able to see ${mykey.id[i]} data from another field, so the data is definitely in the view.
How can I get the controller to read the Param data?
Thanks!
err lots wrong here:
<form action="${doStuffURL}" method='post' params="[keyId: ${mykey.id[i]}]"><g:actionSubmit value="doStuff"/></form>
why not use:
<g:form name="something" controller="yourController" action="youraction">
As you can see above you are having to generate
form url (maybe you have your reasons)
Controller:
def doStuff = {
MyObject.doStuff("${params.keyId}")
}
Differences between action and methods in Grails controllers
So firstly why you should change controller but my actual concern here is
MyObject.doStuff
is MyObject.doStuff a static method ?
since that is only when a call like this would work. The link shows a static method. gets called here and it may confuse you due to it calling it via executor.registerSenderFault due to how it is generated working - expandability - for future classes that do same thing. this could have been EmailExecutor.registerSenderFault which is the full class in uppercase like you have declared.
surely it should be a service notice starting with lower case.
myObjectServive.doStuff(stuff)
If above is some real method in MyObject and is not a static method then you need to instantiate the class
MyObject myObject = new MyObject()
myObject.doStuff(stuff)
but in short this is why services exist it is all there to save you all the hassle since they just get injected.
I suggest you do some reading looking around
E2A
def doStuff = {
println "my params are $params "
//do you see keyId in there ?
//if so what is doStuff expecting as input a string ?:
// since if you do
println "${params.keyId.getClass()}"
//by default it will be a string you may need to change it from:
//myObjectService.doStuff("${params.keyId}")
myObjectService.doStuff(params.keyId as Long)
}
Personally I don't think it is any of the above edited comments, it still relates to how/what you are injecting. I have seen similar issues. I would suggest you create a brand new service and inject new service as a test and start again - not convinced you were injecting it correctly or if you are the service may be some abstract class rather than a normal service. Or.... you are making some form of similar mistake in the uppercase/lowercase declaration of the service name so you may have created:
MyObjectnameService and calling it using myObjectNameService difference in N in those or.... even worse you have created actual service as myObjectNameService with lowercase name.
test this all again using a much simpler naming convention and create a new service as a test
grails create service MyService
and try again using this service
Short version: how to inject an object inside Action in Play Framework?
Long version: In my project I have custom annotation action #AuthenticationRequired which loads User object from the database and puts it into context.args. It uses DAO class that implements UserDAO. Now I want to use DAO class injected into Action by Google Guice. I can use Guice and inject instances in controllers and tests, but I have difficulties injecting DAO class inside Action.
Injector is a field on GlobalSettings instance.
I tried to override GlobalSettings#onRequest() and put UserDAO instance to context.args and then retrieve it from inside AuthenticationRequired action, but it turns out that Action returned by GlobalSettings#onRequest() being called last in the chain of action used with #With and/or custom annotations, so, it is to late.
I also tried to inject DAO instance by annotating action constructor, but but it uses no-args constructor to create an instance of action.
Any ideas how can I achieve this?
For play 2.5 you can simply add #Inject on top of the constructor of Action class and inject whatever needed. Here is a snippet from my working project (I'm using Guice as DI):
public class ChannelPermissionAction extends Action<ChannelPermission> {
private final AuthorizationService authorizationService;
private final AsyncHelper asyncHelper;
#Inject
public ChannelPermissionAction(AuthorizationService authorizationService, AsyncHelper asyncHelper) {
this.authorizationService = authorizationService;
this.asyncHelper = asyncHelper;
}
...
}
You can achieve this just the same as with controllers - describe your action as (a bean in my case - i'm using spring IoC) a dependency and get it called by
public <A> A getControllerInstance(Class<A> clazz)
of Application Global object. That's all you need - you'r dependencies would be injected.
BTW. Actions need to be created with each instance so in my case I should use "prototype" scope.
Mind it while using Guice - it should have similar functionality.
It seems to me that somewhere a rabbit is being pulled out of a hat when it comes to DI in Web API Controllers.
I grok that:
0) The Controller in a Web API project can be called with various classes to be instantiated, all of which implement the interface on which the Controller depends. e.g., with this Controller code:
private readonly IDepartmentRepository _deptsRepository;
public DepartmentsController(IDepartmentRepository deptsRepository)
{
if (deptsRepository == null)
{
throw new ArgumentNullException("deptsRepository is null");
}
_deptsRepository = deptsRepository;
}
..."deptsRepository" can be a class that implements IDepartmentRepository and retrieves test data, OR it can be a class that implements IDepartmentRepository and retrieves production data, OR (etc.)
1) Web API decides which Controller is called based on the URI the client calls, and that Web API decides which method in that Controller is called based on what type (GET, POST) etc. it is and what args, if any, are passed with it.
2) Castle Windsor intercepts this automatic control of Controllers with its own replacement routing engine.
What I don't grok is just where the developer injects the concrete class that implements the interface expected by the Controller. IOW, if I want to run the class that pulls from test data, where do I add code to specify that? I would think it would be somewhere in Global.asax.cs, something like (pseudocode):
// Use test data for now
DeptsControllerClass = TestDataClass;
//DeptsControllerClass = ProductionDataClass;
IOW, where does one specify, "This time, I want you to inject THIS concrete class which implements the required interface"?
As you wrote at point 1, Routing and IoC are two different things.
Once the routing engine figures out which controller has to be invoked, a "controller factory" will be invoked.
WebApi framework allows to plug your own factory as following:
GlobalConfiguration.Configuration.Services.Replace(
typeof(IHttpControllerActivator),
new WindsorCompositionRoot(this.container));
Read more on Mark Seemann post about webapi&windsor plumbing.
Which concrete will be used to satisfy a given interface dependency, that's up to the ioc you choose to use within your factory as above. Using Windsor you may/should link interfce&concrete in the Installers.
Let me try to recap the whole process
1) Set up the routing in order to link url vs controller
2) create the container and register all components using installers
3) replace default controller factory w/ a factory working w/ your favorite ioc container(Windsor, I presume :-) )
4) Enjoy the magic.
All those steps happend in the Application_start within the Global.asax
I'm new to Rhino, and wondered how to mock a local variable/object inside a method of a class I'd also be mocking. In this case I'd be doing it with an ASP.Net MVC controller & action method.
Here's what the controller looks like, simplified:
public class HomeController : Controller {
public myObjectType myMockedObject; //I want to mock this
public myNonMockedObject; //don't want to mock this
public ViewResult Index() {
//call various methods on the mocked and nonmocked members
return View();
}
}
In other words, I'd like to create a mock home controller and mock some local variables within it and their methods-- but not all of them. Is this possible using Rhino?
You can inject these through constructor parameters. Just write constructor that takes myObjectType as parameter. Within this constructor just initialize your fields.
Note1: in case to run MVC, you will need also parameterless ctro, or modify ConstructorFactory (e.g. here https://www.codeproject.com/Articles/560798/ASP-NET-MVC-Controller-Dependency-Injection-for-Be). Or just think about using some IoC container (e.g. https://www.nuget.org/packages/Unity/) that can inject whatever you want inside the controller (mock or normal class).
Note2: you should extract an interface from myObjectType class and mock that interface instead of concrete class (Rhino handles that better).
Note3: I am usually trying to put all the logic (and test that separately) outside of controller since it is quite tough to test the controller (you need to initialize a lot of stuff there what involves another mocking).
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 ?