Grails 3 Controller Scope - session

Looking at Grails 3 documentation, the following is written about scopes:
prototype (default) - A new controller will be created for each request (recommended for actions as Closure properties)
The odd part here is that I get significantly different results in Grails 3.1.4 if I explicitly state:
static scope = "prototype"
Take for example the following UserController
class UserController {
def userService
List<String> users
def loadUsers() {
if (!users) {
println("########## have to load users");
try {
user = userService.getAllUsersInAd()
} catch (Exception e) {
// do something
}
} else {
println("########## dont have to do it " + users.size());
}
}
}
And the following UserService
class UserService {
def getAllUsersInAd() {
println("######### querying")
return new ArrayList<String>();
}
}
If static scope is omitted:
When I close a Firefox browser and re-open it, "dont have to do it is executed", regardless of how many times I close/reopen it. What is even more weird about this is that I can open a completely different browser (like chrome) when I close Firefox, and the same message executes. It is almost as if the scope of this controller is a similar one to #ApplicationScope of JSF.
After a good 5-10 mins of idle time, the query is executed again, but the scenario remains.
If static scope is stated:
After each browser closing, the "have to load users" is executed as expected.
My question is, is the documentation wrong for the default scope? If it is not, what is the difference between explicitly stating scope="prototype" and omitting it(aside from the obvious above) ?

In the default generated application.yml file for a Grails 3.1.4 app you should see a setting like this:
grails:
controllers:
defaultScope: singleton
That tells the framework to make controllers singleton. The default scope is prototype if that setting is not set.

Yes, I believe controllers were changed to singleton (application) scope by default a while ago (version 1.4.x as it happens). I'm trying to find documentation of that. It seems it was a JIRA issue fix, originally here, but Grails has moved away from JIRA, and didn't migrate all the bugs to GitHub.
You shouldn't have state in controllers anyway according to the Grails team:
Why does Grails recommend singleton scope for controllers with actions as methods?
See Burt's answer, and Jeff even speaks up in the comments.
EDIT: As Jeff says, the default is still prototype, but the default generated config changes them all to singleton, which is recommended.

Related

JAX-RS: How to run a method on start (without servlets)

I have a JAX-RS (Jersey) server with which I register and bind my stuff.
I want to print a banner when the server starts up. I want to do this using the JAX-RS framework not the web server's platform (i.e., no Jetty, Netty, Thorntail, etc hooks).
I saw the following which mentions the tried and true Servlet way of doing things:
Jax rs: How can I run a method automatically everytime my server restarts? , but that does not work because I am not running a servlet container in my server so that lifecycle call is never made.
I figured there must be a JCA-ish type object that I can register with Application/ResourceConfig that has such a lifecycle call, but I am unable to even find any kind of list of the things you can actually register.
Not to complain (but I will), but I cannot decide if this is so difficult because when they moved the project to eclipse, they broke every hyperlink to the old official documentation or that it is simply so implicit, like Spring, that it only works by github'ing other people's code and realizing, 'oh, I did not know you could do that'.
Jersey has Event Listeners. You'll want to use the ApplicationEventListener and the ApplicationEvent.Type you'll probably want to listen for to print the banner is the INITIALIZATION_FINISHED
public class MyApplicationEventListener
implements ApplicationEventListener {
#Override
public void onEvent(ApplicationEvent event) {
switch (event.getType()) {
case INITIALIZATION_FINISHED:
printBanner();
break;
}
}
#Override
public RequestEventListener onRequest(RequestEvent requestEvent) {
return null;
}
}

Override a Service in Grails using Spring Bean declaration

I am creating a new plugin containing CustomService which is intended to replace an existing service from an existing plugin. Following the pattern found in custom security implementations and shown here, I've added the configuration to the resources.groovy, oldService(path.to.new.CustomService). I've also tried adding all injected classes into the closure for this service.
(Actual service names are RegistrationPersonRegistrationCompositeService and NewRegistrationPersonRegistrationCompositeService in code block)
I dont want the original application code to have any reference to the new plugin. However, BuildConfig at the application level will require plugin.location entry. My resource.groovy mods are in the new plugin. I have not had success in this endeavor. Am I modifying the wrong resources.groovy? If this change is required in the original application code, I've lost the ability to leave the original code unaltered. I'm not extending the original Service nor using override annotation. My intent is to replace the service (Spring bean) on start-up. The new plugin has a dependency on the old plugin in an attempt to manage order of operations in loading these classes.
Does it matter that the old service is previously injected in a controller? this would require me to override the controller in the new plugin in the same fashion and inject the correct service for desired behavior?
I've found documentation showing that within a plugin, the resources.groovy will be ignored. Also, building the resources.groovy into a war is problematic. I have not found a solution. I'm getting no error that I can share, just that the desired behavior is missing; the original service is handling the requests.
//was resource.groovy - now renamed to serviceOverRide.groovy - still located in \grails-app\conf\spring of plugin
//tried this with and without the BeanBuilder. Theory: I'm missing the autowire somehow
import org.springframework.context.ApplicationContext
import grails.spring.BeanBuilder
def bb = new BeanBuilder()
bb.beans {
registrationPersonRegistrationCompositeService(path.to.services.registration.NewRegistrationPersonRegistrationCompositeService) { bean ->
bean.autowire = true
registrationRestrictionCompositeService = ref("registrationRestrictionCompositeService")
registrationPersonTermVerificationService = ref("registrationPersonTermVerificationService")
}
classRegistrationController(path.to.services.registration.ClassRegistrationController) { bean ->
bean.autowire = true
selfServiceLookupService = ref("selfServiceLookupService")
registrationPersonRegistrationCompositeService = ref("registrationPersonRegistrationCompositeService")
}
}
ApplicationContext appContext = bb.createApplicationContext()
Additional information: Added the following lines to the PluginGrailsPlugin.groovy. The original service is still handling these requests
def dependsOn = ['appPersonRegistration': '1.0.20 > *']
List loadAfter = ['appPersonRegistration']
def doWithSpring = {
registrationPersonCourseRegistrationCompositeService(path.to.new.registration.TccRegistrationPersonCourseRegistrationCompositeService)
}
def doWithApplicationContext = { applicationContext ->
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL)
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getBeanFactory()
beanFactory.registerBeanDefinition("registrationPersonCourseRegistrationCompositeService", BeanDefinitionBuilder.rootBeanDefinition(TccRegistrationPersonCourseRegistrationCompositeService.class.getName()).getBeanDefinition())
}
I highly recommend you read the section of the documentation on Plugins. The reason why I recommend this is because plugins:
Do not include, or make use of resources.groovy
Provide a means through doWithSpring to effect the spring application
Following the information in the documentation you should have no issue overriding the service in the application context.
You must implement your changes to the application context using doWithSpring this is the key to solving your issues.
In this implementation, I had a utility method in a service for which I was attempting to provide an override. Problem is, the Aspect works as a proxy and must override a method that is called directly from another class. In my classRegistrationController, I was calling service processRegistration() which in turn called applyRules(). Example-only method names used. Since the service was calling its own utility, there was no opportunity for the proxy/wrapper to circumvent the call to applyRules(). Once this was discovered, I refactored the code in this fashion: Controller calls processRegistration as it always had. After returning, another call is made to the service, processLocalRules(). The new method is an empty placeholder intended to be overridden by the client's custom logic. The plugin with Aspect works now using resources.groovy. I prefer the doWithSpring as Joshua explained for this reason: my intent to get the plugin to work without modification to the original app-config; otherwise resource.groovy is a valid approach. Upvoting Joshua's answer as it does satisfy the requirement and is cleaner. Thanks!

WebAPI: Accessing Child Container as a Service Locator

In normal ASP.MVC projects we configure the dependency resolver with Unity and the Unity.Mvc3 package from http://unitymvc3.codeplex.com/
We have this test service registered with a HierarchicalLifetimeManager
container.RegisterType<ITestService, TestService>(new HierarchicalLifetimeManager());
And we hook up the container with Mvc in Global.asax.cs:
System.Web.Mvc.DependencyResolver.SetResolver(new Unity.Mvc3.UnityDependencyResolver(container));
And we run this test controller:
public class TestController : Controller
{
private readonly ITestService _service;
public TestController(ITestService service)
{
this._service = service;
}
public ActionResult Test()
{
var locatedService = System.Web.Mvc.DependencyResolver.Current.GetService<ITestService>();
if (_service == locatedService)
return View("Success - Same Service");//This is always the result in an MVC controller
else
throw new Exception("Failure - Different Service Located");//This is never the result in an MVC controller
}
}
However, on this project we are adding a number of WebAPI controllers.
We have this configuration in global.asax.cs (using http://unitywebapi.codeplex.com/ for now. But I am open to suggestions):
System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
We have created an ApiTestController similar to TestController inheriting from ApiController rather than from Controller.
However, the ApiTestController fails its test. I understand that the System.Web.Mvc.DependencyResolver class and the System.Web.Mvc.DependencyResolver.Current property are specific to Mvc. But does WebAPI have an equivalent?
System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver.GetService does not work because the System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver instance is the parent container that I configured. It is not the child controller that was used to inject the ITestService into the constructor.
This user seems to have a similar problem: http://unitywebapi.codeplex.com/discussions/359413
But I feel that this probably has more to do with ASP.NET's WebAPI than it has to do with Unity.
Thanks
After looking over the source of http://unitymvc3.codeplex.com/ and http://unitywebapi.codeplex.com/ I created this class:
public class MyUnityDependencyResolver : Unity.Mvc3.UnityDependencyResolver, System.Web.Http.Dependencies.IDependencyResolver
{
public MyUnityDependencyResolver(IUnityContainer container)
: base(container)
{
}
public System.Web.Http.Dependencies.IDependencyScope BeginScope()
{
return this;
}
public void Dispose()
{
Unity.Mvc3.UnityDependencyResolver.DisposeOfChildContainer();
}
}
Configuration in gobal.asax.cs:
var myResolver = new MyUnityDependencyResolver(container);
System.Web.Mvc.DependencyResolver.SetResolver(myResolver);
System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver = myResolver;
Unity.Mvc3.UnityDependencyResolver uses HttpContext.Current.Items to manage child containers. MyUnityDependencyResolver may not be the most "correct" implementation of System.Web.Http.Dependencies.IDependencyResolver, but it seems to work so far.
I will mark this as the answer in a couple days if no one else has any better answers.
Unfortunately, when you call the GlobalConfiguration.Configuration.DependencyResolver.GetService, it completely ignores any scope and resolves using the outer non-child container which is around for the lifetime of the application. This is an issue with Web Api and makes it impossible to use constructor injection for per-request dependencies outside of controllers. Confusingly this is completely different behaviour from MVC as you say.
What you can do is use the GetDependencyScope() extension method off HttpRequestMessage. Anything you resolve using this will be in per request scope when using HierarchicalLifetimeManager in conjunction with Unity.WebApi. The request is available from action filters and handlers so may be a viable workaround.
Obviously this is pure service location rather than dependency injection which is far from ideal but I have not found another way to access per-request dependencies outside of controllers.
See this post for more info.
The DependencyResolver is not the right seam for dependency injection in ASP.NET WebAPI.
Mark Seemann has two really good posts on DI with WebAPI.
Dependency Injection and Lifetime Management with ASP.NET Web API
Dependency Injection in ASP.NET Web API with Castle Windsor
If you want to do it right you should have a look at them.

HttpContext is null when calling Ninject outside of an MVC3 controller

this question Ninject Dependency Injection in MVC3 - Outside of a Controller is close to what I'm experiencing, but not quite.
I have an ASP.NET MVC3 site using Ninject 3 and it works wonderfully with constructor injection. All my dependencies are resolved, including those that pass in HttpContext.Current.
My issue is that in global.asax, I kick off a TaskManager class that periodically performs some tasks on a timer. Inside the TaskManager class, I don't have controllers, so if I need access to one of my dependencies (like my error logging service), I use a static wrapper class that has access to the kernel object:
var logger = MyContainer.Get<ILoggingService>();
logger.Error("error doing something...", ex);
The .Get method simply performs a kernel.Get call resolve my dependency. Works great every time I use this method on my other dependencies. However, ILoggingService has a dependency called MyWebHelper that is injected via it's constructor and includes HttpContext in it's constructor.
public class DefaultLogger : ILoggingService
{
public DefaultLogger(IRepository<Log> logRepository, IWebHelper webHelper)
{
_logRepository = logRepository;
_webHelper = webHelper;
}
}
public class MyWebHelper : IWebHelper
{
public MyWebHelper(HttpContext httpContext)
{
_httpContext = httpContext;
}
}
In the rest of my web site, this all works just fine because all the dependencies are injected into my MVC controllers. But what doesn't work is if I manually call my static wrapper class to get my dependencies that way. I get the error:
Error activating HttpContext using binding from HttpContext to method
Provider returned null.
So, it's not giving me an HttpContext like it does throughout the rest of my MVC application. I hope this makes sense, I'm not a ninject expert yet, but I'm trying...
My issue is that in global.asax, I kick off a TaskManager class that
periodically performs some tasks on a timer.
That's a bad idea as Phil Haack explains in details. Don't do this in your web application. Those recurring tasks should be done in a separate application (Windows Service or some console application which is scheduled to run at regular intervals).
Now the thing is that you are running background threads. Those background threads run outside of any user HTTP request and as a consequence HttpContext.Current is obviously null inside them. So even if you don't follow Phil Haack's advice and continue running background tasks in your ASP.NET application you will have to rearchitecture your method so that it no longer depends on any HttpContext because there's no such thing in those background threads.

Setting Session in MVC3 when the class not inherited from controller or helper

I would like to write and read data to Session even if my class not inherited from controller or helper. Something like this:
public class User
{
public void CreateSession()
{
Session["key"]=data;
}
public void ReadSession()
{
data=(string)Session["key"];
}
}
Important thing - I need to get instance of User class in some actions
and views. Am I be able to inherit User class from controller or
helper. Because I've already try that, but I got some errors.
How can I achive this?
Thanks in advance.
HttpContext.Session will work, it's a static available anywhere to an assembly that references System.Web.
If your code is in your main website assembly, this should work well. If it's not, you'll have to create a dependency on System.Web which you may or may not want to do.
You should do these kind of things in your controller.
You can access HttpContext directly, but that's not "the ASP.NET MVC way", and you loose some of the advantages of using MVC in the first place. Like making testing harder, and directly coupling your application to HttpContext...
Also, if it's a new session, or Session["key"] is not set for some reason, data=(string)Session["key"]; would throw a null reference exception.

Resources