I need to add a controller action on runtime.
In a plugin i add a dynamic method using doWithDynamicMethods but i can't invoke as an action.
I try using a mixin but it doesnt work. There is a bug with #grails.web.Mixin and is useless for me. And i'm not sure if i can call it as an action.
I understood that i need to add the #Action annotation to method that i create dynamiclly in the doWithDynamicMethods.
Should i use an AstTransformation. Or i miss something
I need to add a controller action on runtime.
No, you don't. You've got some other problem, and you think you can solve it by adding a controller action during runtime. But as you've learned, adding controller actions during runtime is really hard. You should solve your problem in some other way.
I don't know what your problem is, so I can't be too specific. But here's a generically useful trick. In UrlMappings.groovy, you can do this:
"awesome/$stuff"(controller: 'awesome', action: 'doStuff')
And then in AwesomeController.groovy:
public doStuff(String stuff) {
// whatever arbitrary dynamic dispatch logic you want goes here
}
Hope that helps.
Related
I'm kind of new to grails and I'm trying to just map a basic URL request to a view.
So, say I have a view, /x/index.gsp and I want the user to be able to go to it. There will also be /y/index.gsp, /z/index.gsp, etc.
I defined it like so:
"/$customer/index" { view = {params.customer+"/index"} }
This seems to throw an exception though. I also have :
"/$customer/$controller/$action?/$id?" { }
which does work and I don't want to have to create a controller that doesn't really do anything but handle the index call and show it.
I'm sure I'm missing something simple but I don't know what it is.
The reason the first mapping fails is because it can't figure out what controller to route the request to.
To fix it, you need to define what controller you want the top mapping to route to. This is how I did this in a recent project of mine:
"/uploaders/$id" {
controller: "uploader"
}
To map to just a view:
"/$customer/index"(view: "/${params.customer}/index")
I would like to code some logic into my views that depends on the name of the controller action used to call the view. Is there a way I can find out this name.
Hope somebody can help me with that. Please note that it's MVC3 I am using.
Get the name of the controller
#ViewContext.Controller.ValueProvider.GetValue("controller").RawValue
Get the name of the action
#ViewContext.Controller.ValueProvider.GetValue("action").RawValue
I found that here.
#ViewContext.RouteData.Values["Controller"]
#ViewContext.RouteData.Values["Action"]
While this works, I'd suggest it's a little inelegant. Personally I'd add these options as flags to a ViewModel and pass that to my View.
ViewContext.RouteData.Values["action"] may be used, but it is bad choise to let view decide such things. You could use display and editor templates to generate different views and then let action choose its view. Views should be very simple and rely on data that that receive via ViewData or their model. Best to let controller decide such things as differenciate some views with action
I'm working on an ASP.NET MVC controller with several action methods, all of which need the same bit of data. This data requires a lookup that can only be done with the route values (so, I can't do the lookup in the constructor). I'm sure this has been discussed at length, but I've yet to find a satisfactory recommendation.
What's the best way to get this data without repeating myself in each action method? I'm working through:
Create an Action Filter, this seems like the best bet, but where do I store the object, in the action parameters? Is it appropriate to create a ViewModel object in an action filter and pass it directly to the action methods, for them to fill out the rest of the ViewModel object?
Create a child action (Html.RenderAction) to render this data, but this requires a second set of lookups since the child action requires another full cycle of instantiating the controller.
Helper method/property called in each action method.
Thought or opinions on a best approach here?
A filter is probably your best bet and you can store the object in ViewData.
Another option (not a better one) is to create your own controller base class that overrides the ExecuteCore method and does the lookup there.
I did this for logging since I want to log each page view and I didn't want to have to add a filter to each and every controller I made. In mvc 3 there will be a way to declare global filters which can fix this as well.
Ok, so given what you've told me, I would suggest using a custom ModelBinder.
It's the best fit for the situation. I would argue that using a filter is the wrong approach because a filter's job isn't to bind data - that's a job for a ModelBinder.
HTHs,
Charles
EDIT: I've just been thinking about it and I'm a little bit torn if you should use a model binder or not.
The general rule of thumb I just came up with is that if you need the ProjectDetails inside the action itself, use a ModelBinder but if you don't need the ProjectDetails inside the action, use an ActionFilter to just add it to your model / viewdata.
Maybe someone else could throw their 2c in.
You could override the OnActionExecuting() method in your controller and get the data there.
Is it possible in ASP.NET MVC via some extension/override points to allow a "delegate field" to be used as an "action"?
Something like:
using System;
using System.Web.Mvc;
namespace Company.Web.Controllers
{
public class SwitchboardController : BaseController
{
public Func<ActionResult> Index, Admin, Data, Reports;
public SwitchboardController()
{
// Generic views
Index = Admin = Data = Reports =
() => View();
}
}
}
I know I'm a little hell-bent for this one but if this is possible it'd open up many new ways of making actions. You could, for example, have Django-style generic views in MVC with only a single line of code to define the action or have different ways to factor duplicate logic across multiple controllers.
I'm not quiet sure where would be the place to slap this logic into or how much work would be required to alter something so fundamental in the framework.
You will probably have to build your own Controller factory. This class builds controllers, and implements IControllerFactory. You can inherit from DefaultControllerFactory. Override CreateController() to return your own IController.
Register your controller factory in Application_Start() of MvcApplication using this line:
ControllerBuilder.Current.SetControllerFactory(typeof(MyControllerFactory));
In your implementation of IController, override the Execute method. You can use the RequestContext to decide which delegate to invoke. It would probably be easiest to inherit from ControllerBase, and override Execute in there if you don't want to fully implement IController.
The RequestContext passed into Execute carries a RouteData object. This is a dictionary populated by the routing engine that tells you what action should be invoked, and any parameters. You can get the action name like this:
//context is a RequestContext object passed to IController.Execute()
string actionName = requestContext.RouteData.Values["action"];
You could even define your action as a dictionary, and just pull them out once you get the action name.
One last thing, normal action methods return an ActionResult, which the framework uses to decide which view to render. Once you execute your delegates, I think you'll have to set some stuff manually in your special base controller. I'm not exactly sure what to set or how to get your View executed from here without cracking open the MVC source.
Good luck! This looks like an interesting idea.
As you seem to be implementing a BaseController in your code sample, if you override the Execute (from the IController) you'll be able to interpret the request => action however you like.
No, it isn't. The base controller is looking for methods and not for fields to dispatch an action.
EDIT:
Sorry, I was a bit fast and fixed to the standard classes provided.
You can do that but you have to overwrite the Execute Method in your controller or implement and provide your own IActionInvoker to dispatch the action to fields. Look into the post action processing in detail. It explains the dispatching in detail.
I'm working on a menu-generating HtmlHelper extension method. This method will need to know which Action is being executed. So if Home/Index is executing, the extension method would show all links to other actions that're "coordinated." In a sense, all I need to know during the execution of the Home controller's Index action is the name of the Controller and the name of the Action that are being executed so that other logic can be executed. Is this possible?
Try this
var action = HtmlHelper.ViewContext.RouteData.Values["action"];
var controller = HtmlHelper.ViewContext.RouteData.Values["controller"];
I do something similar with a filter attribute. You can get the action name like this:
filterContext.RouteData.Values["action"].ToString();
I use this to disable the menu item that represents the current context.
I need something like this, but not quite. I would love to be able to get some strongly typed way of knowing which action is executing.
So clarify in doing AOP where i only allow access to a given action if the user has rights for that action.
The problem with using a string for determining which rule to check for, is that if some developer renames an action, I wont get a compile error telling me that my rule is broken.