MVC Action Link Issue - asp.net-mvc-5

I have come across what appears to be an inconsistency in MVC 5 regarding the Html.Actionlink. In different cshtml files I can use the same code, but the url target that is generated is different.
For example, this line of code:
<td>#Html.ActionLink(item.Description, "Edit", new { item.ParentTableID }) </td>
generates this URL
localhost\MyControllerClass\Edit?ParentTableID=35
That then properly calls the ActionView method Edit and feeds the parameter with 35 as expected.
However, in another cshtml file, this line
<td>#Html.ActionLink("Edit", "EditChild", new { id = f.ApplicationTableFieldID})</td>
produces this url
localhost/MyControllerClass/Edit/7
and when it hits the EditChild Action View, the parameter is null.
I have seen this now a couple of times and not yet been able to understand what makes the difference. But I need the first result.
Thanks.

Ensure that your ID parameters are named correctly in both your Action method and your ActionLink Html helper. The visual difference comes from MVC default routing and how it can take a parameter named ID and put it in the URL without the query string (? followed by stuff)
If your action method looks like this
public ActionResult EditChild(int ParentTableID){}
Then you will need to have your ID parameter named ParentTableID when you pass it back in your URL
<td>#Html.ActionLink("Edit", "EditChild", new { ParentTableID = f.ApplicationTableFieldID})</td>
Should now produce the following URL
localhost\MyControllerClass\EditChild?ParentTableID=3

Related

MVC5 Getting a button to call an action method in Controller

As the heading states when I click a button on my main view I need it to call a method in my controller for that view. Ive been trying for hours and Ive changed the specific lines of code many times but all variations seem to give the same errors so im just showing the simplest versions to get my point across. Everytime I try something I get a 404 error that the path is not found. So im assuming something is wrong with the code in my view. Im not using JQuery or any javascipt
The line of code in my index view:
#Html.ActionLink("Button4Pressed", "Button4Pressed", "HomeController");
I know this wont work for getting methods but it works for changing pages so I thought I would start there. Im not sure if I should be doing it as a href or button.
my method in my HomeController:
[HttpPost]
public ActionResult Button4Pressed()
{
state = "year";
MyChart();
return View();
}
heres my Solution Explorer
Im pretty new to MVC and propably doing some pretty stupid stuff so any help is appreciated thanks.
You have two options:
Option A
Remove the [HttpPost] attribute from your controller method and you will be able to create normal links to it, i.e. with #Html.ActionLink()
Option B
Keep the [HttpPost] attribute and use a form or ajax to send the request as a HTTP Post request, i.e.
<form id="Button4Pressed" action="#Url.Action("Button4Pressed", "Home")" method="post"></form>
Button4

#current_page feature in Geb

In WATIRwe use #current_page whenever we lands to page which got created at run time (during test case execution).
I am looking for similar feature in Geb.
Here I have two Pages
RegistrationPage.groovy
where I have provided
static url = "/register.html"
I also have UserProfilePage.groovy
here I can't provide any static url because it gets created once I submit the Registration Page, it changes as per user name
example https://xxxxx.com/paul.html, if two paul's are there then https://xxxxx.com/paul2.html
I want to use
static content = {
defaultprofilePic {$("#userprofilepic")}
}
declared in UserProfilePage.groovy
If I am not using to keyword it would land me back to baseURL and if I use it gives exception that element not available on this page.
But I think if I use could something like #current_page it would pass
You should use at(UserProfilePage) which sets the current page to be an instance of UserProfilePage and also verifies its at checker.

Liferay 6.2 PortletURL.setParameter() prepends underscores to parameter names

I am working on a project using Liferay 6.2 on JBoss ES 6.2. I need to be able to create a action URL inside an action method. The action method is looking up some data, building a JSONArray, and then setting an attribute equal to the resulting JSON string. Part of that JSON data needs an action url to another action within the same portlet.
The problem I am running into is that the generated URL seems to force any parameters I set include two underscores to the parameter name.
For instance:
PortletURL actionUrl = PortletURLFactoryUtil.create(actionRequest, portletId, plid, PortletRequest.ACTION_PHASE);
actionUrl.setPortletMode(LiferayPortletMode.VIEW);
actionUrl.setWindowState(WindowState.NORMAL);
actionUrl.setParameter("guid", guid);
actionUrl.setParameter("javax.portlet.action", "myAction");
Ends up generating something like:
http://localhost:8000/group/mySite/myPortlet?p_auth=fsdweD2&p_p_id=p_p_lifecycle=1&p_p_state=normal&p_p_mode=view&__guid=1234567890&__javax.portlet.action=myAction
Notice the __guid and __javax.portlet.action. As a result, the portlet ends up running the doView() instead of myAction().
I have also tried to create a friendly url to solve the issue, but then I run into the issue of how to generate the friendly url with the proper site context AND the required p_auth value.
URL generated doesn't have portlet ID set properly as I see p_p_id is empty in URL. Please check if you are passing correct portlet ID.

JSF Access control on direct object

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

Can MVC Custom Error pages retain Route Values?

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"];

Resources