I have my controllers with the following extensions:
Controller_Login extends Controller_Layout
Controller_Layout extends Controller_Template
so that all controllers (processing user urls) will pass through Controller_Layout. In my controller_Layout, I'm trying to retrieve the controller and action url values in order to bind them and display them in my layout view.
Calling this echo $this->request->param('controller'); returns nothing (empty string), while calling echo $this->request->param(); return an empty array. Clearly nothing is found in the request.
I'm wondering if this is because I'm trying to retrieve the request values from the parent controller of where the request is actually handled. Idealy i'd like to handle this through my parent controller (controller_Layout) since every page request will need to make this call to retrieve the controller and action value
Any ideas?
To get the current Requests controller name, use $this->request->controller() instead of $this->request->param('controller'). Same goes for current action, they aren't variable parameters so they're accessed this way.
And yes, you can handle those in the parent controller, keep it DRY :)
Related
I have two controllers. One is login.js and the another one is home.js. I want to redirect to home controller from login controller with a value. To redirect to home controller, i wrote,
response.redirect('/home');
But, i cannot pass value here. When rendering a view with a value,
data = {'value':'hello'};
response.render('view_login',data);
I want to do the same thing. I can pass value while rendering to the view but not when changing controller. Can i do this?
response.redirect('/home',{data: data});
you can use query parameters for this.
When you are redirecting your home page or any other controller then you can write like this
res.redirect(/<some controller>?data=<some data>)
and in that controller where you want to use this value..you can write like this
function login(req,res){
var data = req.query.data;
}
I have a commandLink that do a POST, and the action listener in the bean fill the request map with a new parameter like this
FacesContext.getCurrentInstance().getExternalContext().getRequestMap().put("confirmationWindowMessage","test");
In the view if I make #{param['confirmationWindowMessage']} nothing is presented. Why is this happening?
The action listener does not redirect to another view, so the view is the same.
You can't and shouldn't fill the #{param} object. This is a client-controlled map. Moreover, any attempt should go through getRequestParameterMap(), not getRequestMap(). The getRequestMap() represents the request attribtues, not request parameters.
Request attributes are just available by #{attributeName}. Thus, in your particular case so:
<p>#{confirmationWindowMessage}</p>
An alternative is to just make it a property of a request scoped bean. Or perhaps even better, a faces message.
I have a JSF page contentEdit.xhtml which accepts a request parameter "code" to load the content for editing and other operations related. To provide access control, I create a filter ContentAccessFilter and applies it to contentEdit.xhtml to check whether the current user is authorized to the content which is identified by "code".
Fragment of ContentAccessFilter:
boolean isAuthorized = false;
String userId = httpReq.getRemoteUser();
String code = httpReq.getParameter("code");
if (code != null && !code.isEmpty())
{
ContentDAO dao = ContentDAO.getInstance();
isAuthorized = dao.isContentAuthorized(code, userId);
}
if (!isAuthorized)
{
httpRes.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
For the first entry of the contentEdit.xhtml, the filter works properly as the code parameter always exists during the first entry by calling such as /contentArea.xhtml?code=cnn from an anchor html tag. However, the code parameter is lost when there is subsequent operations on contentEdit.xhtml. For example, I have buttons like these.
<p:commandButton value="Download" action="#{contentView.downloadContent}"/>
<p:commandButton value="Publish" action="#{contentView.publishContent}"/>
Clicking the button will call the same URL as contentEdit.xhtml, while the parameter code is not included in the request URL. This missing parameter fails in the filter.
Is using a Servlet Filter a proper way to achieve the access control in this case? If it is, how to include a request parameter when triggers a commandButton?
Filters are a great way to implement authorization in a web app... you're on the right track.
The best way would be to use your filter but store the code parameter value in a session (javax.servlet.http.HttpSession), that way the parameter doesn't need to be passed in the query string with each request. You would set the code attribute in the session data on the first request and retrieve it whenever a new request is received.
If you must use the query string to pass the code value with each request, you'll need to use the includeViewParams parameter in the query string creation to preserve the code parameter in the generated URLs. BalusC (the JSF God) explains this better than anyone... https://stackoverflow.com/a/17745573/3858863
The MVC project that I am currently working on uses Regions so that we can localise pages etc.
I have spotted a problem with our Error page. We have turned the custom error pages on in the web.config file. If we are on a page lets say : /IT/News/Index and we get an error, when it redirects it will go to /Error and there will be no routevalue attached to it.
Is there away to ensure that the langauge routevalue is retained by the Error page?
I have searched around and cannot find a solution at the moment and was wondering if anyone else could help or point me in the right direction?
Hope that this all makes sense. Any help is much appreciated.
If you're getting physically redirected to /Error then it's not because of the MVC HandleErrorAttribute. It's probably due to your Web.Config having system.web/customErrors defined for error handling. Using the HandleErrorAttribute causes it to inject a specific view instead of the view you would have normally returned but does not redirect you to a different action by default. The problem is when redirected because of customErrors, there is no inherant information available to tell you where they came from. But using HandleErrorAttribute DOES cause some info to be populated for you. Specifically it creates a HandleErrorInfo to use as a view model and passes that to the view you specify. For example, here's one that is reigstered in the /App_Start/FilterConfig.cs file.
public class FilterConfig
{
public static void RegisterFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute {View = "Error"});
}
}
When you redirect to an error View using the HandleErrorAttribute, certain information is populated for you. The HandleErrorInfo view model will contain the ControllerName of the original controller requested, and the ActionName of the original action. Also, the ViewData and the TempData from the original request will be copied into the ViewData and Temp data for the request to the Error view. With that information it should have what you need. Be aware that not all errors happen inside of an Action however, and exceptions that don't happen in an action will not be caught by the HandleErrorAttribute. So you'll still need to use something like customErrors (or system.webServer/httpErrors if you're doing it inside of IIS7+) to handle exceptions that occur elsewhere in your app.
Here's a link to the HandleErrorAttribute file on CodePlex in case you're wondering what it does. HandleErrorAttribute.cs
I'm not sure if this solution meets you requirements. You can override in your base controller OnException and then redirect to a specific page.
protected override void OnException(ExceptionContext filterContext)
{
string controller = filterContext.RouteData.Values["controller"].ToString();
string action = filterContext.RouteData.Values["action"].ToString();
//get other stuff from routing
//here you can do redirect or other stuff
//if handled exception
//filterContext.ExceptionHandled = true;
base.OnException(filterContext);
}
It depends how you're getting to the error pages, really. If you're using an ActionFilter-based method to catch exceptions, then you can get route values from the context that gets passed into the OnException method. If you're using a redirect from a catch block, then you can push the relevant information into TempData or pass it directly as a parameter, depending on how you're doing that redirect.
You can add a custom HandleErrorAttribute or use a base controller to be inherited by all your controllers. Either way, you need to get the RouteData object, like this
var routeData = filterContext.RouteData;
with that object, you can get all the route values accordingly to your needs. Check the object definition in MSDN site for more detail
Say you have the following route
routes.MapRoute(
"Language", // Route name
"{language}/{controller}/{action}/{id}", // URL with parameters
new { language = "en", controller = "Sites", action = "Index", id = UrlParameter.Optional } // Parameter default
Then routeData.Values.Keys will tell you the name of the parameter and routeData.Values.Values the value itself
Then, wherever you handle the exception, you can store the route data in a TempData variable, like this
TempData["RouteData"]
And after that, it will be available on your error page
#model System.Web.Mvc.HandleErrorInfo
#{
ViewBag.Title = "Error";
}
<h2>
Sorry, an error occurred while processing your request.
</h2>
#TempData["RouteData"];
In FubuMVC, when I want a controller action method to return a json result, I use the JsonEndpoint attribute on the method. However there is not a corresponding attribute for a void method that I can see.
For a particular action, I don't want to return anything, but if I have a void return result Fubu fails because it starts looking for a view to match an empty model to.
Is there a attribute or easy change to allow a particular action method to return void?
Thanks
When I updated to a newer version of the framework, one-model-in, zero-model-out controller actions became instantly usable. The only thing I'm not sure how to do is controller-less views.