Hi have the following code on my view (JQuery):
$.post('<%=Url.Content("~/Customer/StartLongRunningProcess")%>');
Wich invokes an asynchronous call (C#):
public void StartLongRunningProcess()
{
ProcessTask processTask = new ProcessTask();
processTask.BeginInvoke(new AsyncCallback(EndLongRunningProcess), processTask);
}
Finally, the result of the call:
public void EndLongRunningProcess(IAsyncResult result)
{
ProcessTask processTask = (ProcessTask)result.AsyncState;
string id = processTask.EndInvoke(result);
RedirectToAction("~/SubscriptionList/SubscribedIndex/" + id);
}
The redirect is ignored. Response.Redirect also fails, since the HTTP headers has been already sent. I've tried change the window.location from javascript, this works, but I'm unable to pass the parameter id by ViewData. Any idea to resolve this?
Are you sure the headers have already been sent? I'm not really up on asynchronous controllers, but I would doubt that it would start sending any headers right away. My first thought would be that a redirect response to an ajax call isn't handled by the browser. You will probably need to implement some logic that sends back a result with the URL and have your success delegate in jQuery look for that piece of data and then do the redirect through javascript (i.e. window.location).
HTH
Related
I am wondering if (HTML.Action) send another request to the server other than the main request.
For example, when Razor renders the below view. Does it send a new request to the server to execute the action (SearchResults)?
#Html.Action("SearchResults", "MySearch",
new { query = new QueryParameters(Request.QueryString["search"]) })
You can see whether it send another request or not using network tab under developer tools.Html.Action is just a helper method like any other ,purpose of it is rendering view via calling another action , all it happens when razor renders page.So complete html send to browser in a single request so main request.
When you are rendering actions/partials in a View there is only one request.
If you want to test this you can debug it in your global.asax with this method:
protected void Application_BeginRequest(object sender, EventArgs e)
{
}
i have an best practice question.
Its clear what Post/Redirect/Get does, but what will be the bestpractice to handle them?
I think there are 2 methods to handle them.
1.) We call the prg plugin at first on controller action
2.) We first validate the post data, and only redirect to the prg-response if successfull?
My problem about this is, at
1.) We enlarge the response time because of the redirect, this is by default so i think not the best solution
2.) will create an overhead by the every time validation of the form
What did you mean is the better solution aber this case?
regards
UPDATE:
What i mean is, the normal(standard) case is something like this - http://framework.zend.com/manual/2.0/en/modules/zend.mvc.plugins.html#the-post-redirect-get-plugin.
$prg = $this->prg('url');
if ($prg instanceof Response) {
return $prg;
} elseif ($prg === false) {
return new ViewModel(array(...));
}
$form->setData($prg);
This means, that theres after every form submit an redirect executes.
Now, my idea was something like this:
$prg = $this->prg();
$form = $this->getFormLogin();
$data = ($prg instanceof ResponseInterface)
? $this->getRequest()->getPost()
: $prg;
if (false !== $data) {
$form->setData($data);
if (true === $form->isValid()) {
if ($prg instanceOf ResponseInterface) {
return $prg;
}
// Make something within the loginservice or something else
}
The idea behind this was, to only redirect for the PRG only if the form is valid, to save response time and other things (because of bootstrapping settings etc.)
The Zend Framework is designed based on Front-Controller pattern so its essential to redirect the page when you access different resources(controller-action).
moreover when you fire redirect(URL) function from your source code it takes minimal time when you compared the time to access the same(URL) from your browser.
You could reduce the response time to considerable amount when you use classmap_autoloading.
Updated:
for an example i take login process, in the below code i implement both HTTP get and post methods in the same action() but, you can refactor this function based on HTTP methods.
LoginController.php
public function loginAction()
{
//code
if ($request->isPost()) {
//code
if ($isValid) {
return $this->redirect()->toUrl('urUrl');
}
return $this->redirect()->toUrl('urUrl');
}
//code
return $viewModel;
}
After refactoring above code
//it used for HTTP get
public function loginAction()
{
//code
return $viewModel;
}
//it used for HTTP POST
public function loginPostAction()
{
//code
if ($notValid) {
return $this->redirect()->toUrl('urUrl');
}
$viewModel->setTemplate($viewpath);
return $viewModel;
}
You need to modify your routing configuration in such a way to handle for both HTTP get and post methods. if the request is HTTP-get the controller process the loginAction() but if its HTTP-post it process the loginPostAction()
Zend framework 2 - HTTP method Routing
Updated:
The purpose of plugin is to avoid the user to POST the data again to the browser. In your case you are trying to enable the option to POST their data when the form is not valid (you are trying to change the behaviour of PRG plugin). if you really worried about response time don't use PRG plugin. create your custom logic inside your controller-action.
--SJ
When you do return Json(...) you are specifically telling MVC not to use a view, and to serve serialized JSON data. Your browser opens a download dialog because it doesn't know what to do with this data.
i got the above information from below link
How to return Json object from MVC controller to view
when i give this below code in some action result
return Json(new { Url = "sep/employee"}
whether it will redirect to specified action ? how it redirects to the URl ?
for this case why i cant use return RedirectToAction("sep/employee").
how return Json code redirects to action which specified in the Url.
ex:
public ActionResult Index()
{
................................
return Json(new { Url = "sep/employee"}
}
public ActionResult employee()
{
....................
}
what is the difference b/s redirectaction and return Json
You return the following line to an ajax success call
return Json(new { Url = "sep/employee"});
you then need to specify where to redirect to the new page
success: function(result) {
window.location.href=result.Url;
}
RedirectToAction simply returns 302 code to your browser with URL telling where the browser should redirect to. The browser immediately makes yet another call to the server to that URL obtained from redirection response.
RedirectToAction internals are:
Construct redirection url from parameters passed to RedirectToAction
Return new RedirectToRouteResult
In ExecuteResult of RedirectToRouteResult you can find the following line:
context.HttpContext.Response.Redirect(destinationUrl, endResponse: false);
which is merely returning 302 with redirection URL. More info - look at source code here.
Returning JSON data simply returns JSON serialized object to your browser. Is not meant to do any redirect. To consume such a result you will likely call the server using $.ajax:
$.ajax({
url: 'sep/employee',
type: 'POST'
success: function(result) {
// handle the result from the server, i.e. process returned JSON data
}
});
ExecuteResult of JsonResult just serializes passed CLR object to the response stream, which lands in your browser after response is fully received. Then you can handle such response in JavaScript code.
EDIT:
You of course can mimic 302 redirection by returning Json like
return Json(new { Url = "redirectionUrl"}
and at client side handle it like
$.ajax({
url: 'sep/employee',
type: 'POST'
success: function(result) {
// mimic the 302 redirection
windows.location.href = result.Url
}
});
although IMHO it should be avoided since you reinvent MVC infrastructure and enlarge your code base.
whether it will redirect to specified action ? how it redirects to the URl ?
I assume you mean to ask, "will it redirect to specified action? how will it redirect the the URI?"
To answer your question: How it redirects to the URL?
In your example it will redirect to the URL, if you made the HTTP request as AJAX and that you will explicitly handle the resulting HTTP response to actually redirect to the URL that you received. So your view should have something like this:
$.ajax({
url: '{your controller}/index',
type: 'GET'
success: function(url) {
// write code to redirect to the URL
// example:
// window.navigate(url)
}
});
If your view does not have anything that, then it will not redirect. You did not post your view, so I am assuming it just a normal page load.
Your next question, what is the difference b/s redirection and return Json?
If you really just want to redirect then do RedirectToAction from your controller, that is exactly what it is for. You can do the same effect using AJAX and JSON to be able to redirect, but AJAX and JSON serves a much wider purpose than just redirecting and in most cases (unless you have very good reasons) you probably will not want replace RedirectToAction with that approach.
I'm using the "Redirect After Post" (http://en.wikipedia.org/wiki/Post/Redirect/Get) pattern to solve the problems with refreshing that it solves, but I'm not seeing the URL change after the POST and subsequent GET.
Here is my setup:
I have a form with some pretty extensive client-side validation, then submit.
#using (Html.BeginForm("AddItem", "Order", FormMethod.Post, new { Id = "addItemForm" }))
{
// form stuff
}
Client-side validation:
$('#addToOrder').click(function () {
// do a bunch of validation stuff.
}
if (criteriaMet) {
$('#addItemForm').submit();
}
"AddItem" controller:
public class OrderController {
[HttpPost]
public ActionResult AddItem(long? orderId, long menuItemId)
{
if (oneConditionIsTrue)
{
return RedirectToRoute("NamedRoute1", new { RouteValueDictionary values });
}
else
{
return RedirectToRoute("NamedRoute2", new { RouteValueDictionary values });
}
}
public class NamedRouteController
{
public ActionResult NamedRouteAction
{
// do some stuff
if (mobile)
{
return View("MobileView", model);
}
else
{
return View("RegularView", model);
}
}
After redirecting from the POST action (AddItem), I can step things through the GET action to the return (either one). I would expect the URL in the browser after all of this to be http://mydomain.com/NamedRoute/NamedRouteAction but it's http://mydomain.com/Order/AddItem. Why is this? Shouldn't the RedirectToRoute change the URL?
What am I missing?
I suspect that the controller action is somehow invoked with an AJAX request. For example this could happen if you are using jQuery Mobile or something. Or maybe there's some other script that you have written doing this - it hijacks the form submission and sends an AJAX request instead. And since it is an AJAX request, you cannot possibly expect that the url in the client browser would ever change - that's the whole point of AJAX - stay on the same page.
This could be very easily verified by using a javascript debugging tool such as FireBug. Simply look at the Network tab and see if the POST request was an AJAX request. In the Net tab find the request and see if there's the following request header:
X-Requested-With: XMLHttpRequest
jQuery appends this HTTP header to all AJAX requests it sends.
So basically if you expect a redirect to happen after a POST request you shouldn't use AJAX to submit your form. Or to be more precise: the redirect happens on the server side (once again you will be able to see it in FireBug - the 302 status code) and then the XMLHttpRequest simply follows this redirect but the client browser will not change its current location.
For a POST method, the W3 specs say:
If a resource has been created on the origin server, the response
SHOULD be 201 (Created) and contain an entity which describes the
status of the request and refers to the new resource, and a Location
header (see Section 10.4).
http://www.ietf.org/internet-drafts/draft-ietf-httpbis-p2-semantics-05.txt (section 8.5)
The standard response actually seems to be to send a Redirect to the newly created resource.
I'm building my site with ASP.NET MVC, and tried to follow the spec, so created a ResourceCreatedResult class:
public class ResourceCreatedResult : ActionResult
{
public string Location { get; set; }
public override void ExecuteResult(ControllerContext context)
{
context.HttpContext.Response.Clear();
context.HttpContext.Response.StatusCode = 201;
context.HttpContext.Response.ClearHeaders();
context.HttpContext.Response.AddHeader("Location", Location);
}
}
And my action looks something like this:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreateNew(string entityStuff)
{
Entity newEntity = new Entity(entityStuff);
IEntityRepository entityRepository = ObjectFactory.GetInstance<IEntityRepository>();
entityRepository.Add(newEntity);
ActionResult result = new ResourceCreatedResult()
{ Location = Url.Action("Show", new { id = newEntity.Id }) };
return result;
}
However, IE, Firefox and Chrome all fail to redirect to the new resource. Have I messed up generating the correct response, or do web browsers not expect this type of response, instead relying on servers to send a Redirect response?
To be explicit, browsers (including modern browsers like Firefox 3 and IE8) do not "take the hint" and follow up an HTTP 201: Created response with a GET request to the URI supplied in the Location header.
If you want browsers to go to the URI supplied in the Location header, you should send an HTTP 303: See Other status instead.
Redirect after post or post/redirect/get is something your application must do to be user friendly.
Edit. This is above and beyond the HTTP specifications. If we simply return a 201 after a POST, the browser back button behaves badly.
Note that Web Services requests (which do NOT respond to a browser) follow the standard completely and do NOT redirect after post.
It works like this.
The browser POSTS the data.
Your application validates the data. If it's invalid, you respond with the form so they can fix it and POST.
Your application responds with a redirect.
The browser gets the redirect and does a GET.
Your application sees the GET and responds.
Now -- hey presto! -- the back button works.
My solution is to respond with a '201 Created' containing a simple page with a link to the new resource, and a javascript redirect using location.replace().
This lets the same code work for API and browser requests, plays nicely with Back and Refresh buttons, and degrades gracefully in old browsers.
As stated in the spec the response SHOULD be a HTTP 201 with redirect. So it isn't mandatory for a browser vendor to implement the correct answer...
You should try to change to a 30x code to see if it is correctly redirected. If so, it's a browser problem, else it may come from your code (I don't know anything in ASP.NET so I can't "validate" your code)
Shouldn't that only count for when something is "Created" and therefore a simple redirect to action should be genuinely sufficient?