At this moment I am calling my index view in one of two ways. Using the normal http view and serializing it JSON. In order to test it I am using the code below, and it works. I want to get it with a http get call. Like (http://localhost/article,json or something similar. Any ideas.
$.getJSON("/Article", function(json) {
$.each(json, function(i, article) {
alert(article.title);
});
});
At this moment the index called to /article is being differentiated with the following IsAjaxRequest method. but my real question is if I am able to get around the .getJSON method in JQuery to test the following code.
if (Request.IsAjaxRequest()) {
return Json(articles);
} else {
return View(articles);
}
If you are trying to reuse the same action method for both a full GET (the page load) and an AJAX call (via getJSON), you'll run into issues because each action method should have a unique name. Otherwise, the MVC engine can't tell which action method should be called when a particular Url is requested.
You'll need two separate actions: one for the full page load that returns a ViewResult and the other for the AJAX call that returns a JsonResult. If you need the Urls for these actions to look the same, you can also play around with mapped routes that direct to different action methods.
So, how about:
/Article/Index
Maps to the default Index action (full page load)
/Article/Refresh
Maps to the Refresh action (asynchronous JSON call)
I'm not sure I understand the question correctly, but can't you make an optional parameter called "format", so that you pass in ?format=json to switch what reply type you get back?
if(Request.IsAjaxRequest() || (!string.IsNullOrEmpty(format) && format.Equals("json"))
{
...
}
If you're wondering how to test your action and you're talking about doing automated testing, see if this post answers your question.
Related
I have a couple of "before" type filters, which I would like to trigger only when a real, non-forwarded request arrives at my server. And not, when I sometimes am forwarding a request to another controller/action for further processing.
My questions if if there is a simple way to detect this particular kind of requests caused by a "forward()" call?
Alternatively, I am considering to parse the request url and check if controller and action match with the current controller/action, but I am not sure if this will work - and it sure is quite an ugly way to handle this issue...
From within my controller action I have tried to see if there were any useful attributes for this purpose on the request object, but could not find any, except from "javax.servlet.forward.request_uri" and "org.codehaus.groovy.grails.CONTROLLER_NAME_ATTRIBUTE" +"org.codehaus.groovy.grails.ACTION_NAME_ATTRIBUTE".
However, it seems like comparing these values with each other will not work if the request uri originates from a UrlMapping,(in which case it might not match with the controller/action)
You can determine if a request was forwarded by looking up the servlet attribute org.grails.FORWARD_CALLED:
request.getAttribute('org.grails.FORWARD_CALLED')
Minimal example (in Grails 3.3.9, though same attribute in 2.5.x):
def index() {
forward action: 'fwd'
}
def fwd() {
if (request.getAttribute('org.grails.FORWARD_CALLED')) {
render 'was called by forward'
} else {
render 'called directly'
}
}
Calling the endpoints:
$ curl localhost:8080/foo/index
was called by forward
$ curl localhost:8080/foo/fwd
called directly
Can't I just call then function "second" with no redirect action if I in the same class to get the same result i would get with redirect action in the following code?
class SampleController {
def first() {
// redirect to the "second" action...
redirect action: "second"
}
def second() {
// ...
} }
Can't I just call then function "second" with no redirect action if I
in the same class to get the same result i would get with redirect
action in the following code?
Of course you can call a method from within a controller action but whether or not you get the same result depends on a number of factors. The best way to approach this is to understand the differences between a redirect, a forward and invoking a method. Understanding those will help you understand when each of them makes sense.
When you initiate a redirect the response is sent back to the client with information which causes the client to send a separate request back to your application. A full HTTP round trip is made. A forward is similar to a redirect except it all happens within the first request. Control is sent to the forwarded action without needing to go back to the client and having it send a second request. Invoking a method is different than all of that. Invoking a method is just invoking a method and there are a number of things that won't happen when you do that. For example, filters (Grails filters or regular servlet filters) will not be involved in that method call, even if the method you are calling is a controller action and there are filters configured that would normally apply to calls to that action. You really should never invoke a controller action method directly. If the method includes helper code that you might want to call, put that code in a regular non-action method (make it non-public) and then invoke it from wherever that makes sense. Usually a better idea is to move that method out of the controller altogether and put it in a helper class where it will have a number of a benefits including that it can be re-used wherever appropriate, tested separate from a controller, etc. This helper class might or might not be a Grails service, depending on how it is used and what it is doing.
I hope that helps.
You can use
forward action: "second"
Forwards a request without issuing an HTTP redirect.
When I use RedirectToAction("MyView", "MyController") sometimes the redirection is very slow to render the destination view.
It doesn't always happen.
I am using ASP.net MVC4 with IIS7.5
How can I prevent this problem and speed up the redirection?
I will put this here as code will not show very well in the comments section. If the action method you are redirecting to is in the same controller you are currently in, it is simpler and more efficient to call that method directly and return its results instead of the redirect response generated by the RedirectToAction method. Just to make sure we are on the same page, RedirectToAction actually returns a redirect response (302) to the client asking it to issue a new request to the action method you have specified as per MSDN http://msdn.microsoft.com/en-us/library/system.web.mvc.controller.redirecttoaction(v=vs.108).aspx. Some code to illustrate:
public ActionResult MyAction(){
//do some work here
Return View(MyModel);
}
public ActionResult ActionIAmCurrentlyIn(){
//Do Soe work here
return RedirectToAction ("MyAction", "MyController"); //This costs an extra trip across the wire
return MyAction(); // Does same thing but without the extra trip to the client
}
This overhead of the extra trip becomes more significant if there are parameters being passed along to "MyAction" and as the network speed goes down.
Responding as an answer because I don't have enough rep to add a comment...
#JTMon In your code the "return MyAction();" can cause potential issues because the "MyAction" action will actually try to load a view named "ActionIAmCurrentlyIn" since that is the action that's specified in the route values (at least I assume that's where it's getting it from, I haven't actually dug into the code to find out).
This can be resolved by specifying the view name in MyAction:
return view("MyAction", MyModel);
To prevent this problem and speed up the redirection use:
return Redirect("~/MyController/MyView");
This approach will not change client-server interaction.
You can use RedirectToActionPermanent("View","Controller"); for it.
In the file FirstView.cshtml I have an event - clicking to a cell of a table redirects you to a method:
$.get('#Url.Action("MyMethod", "MyController")', { someParameters });
In the method MyMethod, which is void, I call and event DownloadStringCompleted in which I have:
Response.Redirect(Url.Action("Second", "MyController"));
Second is an action method which returns SecondView. SecondView is my desired view but it never shows on the browser. The breakpoint enters in it, passes it and I get FirstView in the browser.
What could be the reason? Can it be because they are in the same controller?
The methods are like this:
Second return View. In its body, I pass some ViewData parameters.
The event:
I read some JSON data and call the redirection.
The strange thing is that the breakpoint moves through the correct view, but I get the wrong one in my browser.
Srcee,
I believe this is due to the fact that your ajax function is 'done' once it has hit the MyMethod action. The redirect doesn't get fired as it's not part of the pipeline due to the ajax call (at least, this is my basic understanding). An alternative for you would be to do something along the following lines:
$.ajax({
url: '#Url.Action("MyMethod", "MyController")',
data: { id: 123 }, // i.e. someParameters
context: document.body,
success: function(){
window.location = '#Url.Action("Second", "MyController")';
}
});
this is all top of the head stuff and may not work, but is an alternative approach.
[edit] - based on your later edit, i would actually suggest that you don't use ajax at all as it's impossible (as per my comments below) to redirect on the server via an ajax call. see:
asp.net mvc ajax post - redirecttoaction not working
and also:
How can I RedirectToAction within $.ajax callback?
for confirmation on this.
Try not calling Response.Redirect(...) in MyMethod. Instead, call:
public ActionResult MyMethod()
{
return Redirect(Url.Action("Second"));
}
Note that if the controller name is the same as the one you are in, you don't need to explicitly include it.
I just did a test on my dev box, and this works (assuming I correctly modeled your problem).
In ASP.NET MVC, there is a useful method Request.IsAjaxRequest that I can use to determine whether the request is made via AJAX. However, RenderAction method seems to be calling the controller/action via AJAX as well.
I would like the calls via RenderAction to return a View, whereas calls via AJAX to return a Json object. Is there any way I can distinguish calls from those two sources?
EDIT:
Re. jim: I simply call a RenderAction within a View:
In SomeView.ascx:
Html.RenderAction("Action", "AnotherController", new { id = "some ID" });
I believe you could use ControllerContext.IsChildAction to determine if a method was called by RenderAction().