Come ottenere una risposta Ajax ASP.NET MVC per reindirizzare a una nuova pagina invece di inserire la vista in UpdateTargetId?


88

Sto usando Ajax.BeginForm per creare un modulo che eseguirà un postback ajax su una determinata azione del controller e quindi se l'azione ha successo, l'utente dovrebbe essere reindirizzato a un'altra pagina (se l'azione fallisce, viene visualizzato un messaggio di stato utilizzando AjaxOptions UpdateTargetId).

using (Ajax.BeginForm("Delete", null,
        new { userId = Model.UserId },
        new AjaxOptions { UpdateTargetId = "UserForm", LoadingElementId = "DeletingDiv" },
        new { name = "DeleteForm", id = "DeleteForm" }))
   {
    [HTML DELETE BUTTON]
   }

Se l'eliminazione ha esito positivo, restituisco un risultato di reindirizzamento:

[Authorize]
public ActionResult Delete(Int32 UserId)
{
    UserRepository.DeleteUser(UserId);
    return Redirect(Url.Action("Index", "Home"));
}

Ma la vista Indice dell'Home Controller viene caricata in UpdateTargetId e quindi mi ritrovo con una pagina all'interno di una pagina. Due cose a cui sto pensando:

  1. O sto architettando questo errore e dovrei gestire questo tipo di azione in modo diverso (non usando ajax).
  2. Invece di restituire un risultato di reindirizzamento, restituisci una visualizzazione che contiene javascript che esegue il reindirizzamento sul lato client.

Qualcuno ha commenti su # 1? O se la # 2 è una buona soluzione, come sarebbe la "visualizzazione javascript di reindirizzamento"?

Risposte:


171

Puoi usare JavascriptResultper ottenere questo risultato.

Per reindirizzare:

return JavaScript("window.location = 'http://www.google.co.uk'");

Per ricaricare la pagina corrente:

return JavaScript("location.reload(true)");

Sembra l'opzione più semplice.


4
Fantastico .. Mi ha aiutato.
CrazyCoderz

1
Sono d'accordo, questo è l'approccio giusto. Questa risposta stackoverflow.com/a/2841608/498969 mostra come applicare questa funzionalità per impostazione predefinita utilizzando un controller di base.
Adam Spicer

@ Ben Foster: Utilizzando questa ricerca si tenta di aprire l'URL http :: window.location ... L'ho pubblicata come domanda separata in stackoverflow.com/questions/13896307/…
Andrus

30
Se vuoi reindirizzare a un controller nel tuo progetto puoi usare l'helper Url per te. Ad esempio:return JavaScript( "window.location = '" + Url.Action("Edit","Dispatch") + "'" );
Chris Morgan

2
Corto. Semplice. Eccellente. Grande!
Vikram

30

Puoi restituire un JSON con l'URL e modificare window.location utilizzando JavaScript sul lato client. Preferisco questo modo che chiamare una funzione JavaScript dal server, che penso che rompa la separazione delle preoccupazioni.

Lato server:

return Json(new {result = "Redirect", url = Url.Action("ActionName", "ControllerName")});

Dalla parte del cliente:

if (response.result == 'Redirect')
    window.location = response.url;

Ovviamente puoi aggiungere più logica perché potrebbe esserci un errore lato server e in quel caso la proprietà result potrebbe indicare questa situazione ed evitare il reindirizzamento.


12

Il comportamento che stai cercando di produrre non è davvero meglio farlo usando AJAX. AJAX sarebbe utilizzato al meglio se si desidera aggiornare solo una parte della pagina, non reindirizzare completamente a un'altra pagina. Questo sconfigge davvero l'intero scopo di AJAX.

Suggerirei di non usare AJAX con il comportamento che stai descrivendo.

In alternativa, potresti provare a utilizzare jquery Ajax, che invierà la richiesta e quindi specifichi una richiamata quando la richiesta viene completata. Nella richiamata è possibile determinare se è fallito o è riuscito e reindirizzare a un'altra pagina in caso di successo. Ho trovato jquery Ajax molto più facile da usare, soprattutto perché sto già usando la libreria per altre cose comunque.

Puoi trovare la documentazione su jquery ajax qui , ma la sintassi è la seguente:

jQuery.ajax( options )  

jQuery.get( url, data, callback, type)

jQuery.getJSON( url, data, callback )

jQuery.getScript( url, callback )

jQuery.post( url, data, callback, type)

Quindi esegui un POST regolare per l'azione Elimina e nella maggior parte dei casi avrà successo e quindi posso reindirizzare alla pagina Indice Home. Nei casi in cui fallisse, visualizza una visualizzazione diversa con i messaggi di errore e l'azione appropriata da intraprendere per l'utente. Va bene?
Jeff Widmer,

Sì, sembra che avrebbe più senso.
Joseph,

Sono andato avanti con la conversione di questo da un invio Ajax a un POST regolare secondo la raccomandazione di Joseph. In realtà ha funzionato meglio poiché mi ha dato un modo più pulito per gestire il messaggio di conferma dell'eliminazione.
Jeff Widmer

12

Sebbene non sia elegante, funziona per me in determinate situazioni.

Controller

if (RedirectToPage)
    return PartialView("JavascriptRedirect", new JavascriptRedirectModel("http://www.google.com"));
else
   ... return regular ajax partialview

Modello

    public JavascriptRedirectModel(string location)
    {
        Location = location;
    }

    public string Location { get; set; }

/Views/Shared/JavascriptRedirect.cshtml

@model Models.Shared.JavascriptRedirectModel

<script type="text/javascript">
    window.location = '@Model.Location';
</script>

2
Perché non elegante? È fortemente digitato e sembra chiaro. Mi piace questo approccio. +1
T-moty

6

L'utilizzo JavaScriptfarà sicuramente il lavoro.

Puoi anche usarlo Contentse questo è più il tuo stile.

Esempio:

Controller MVC

[HttpPost]
public ActionResult AjaxMethod()
{
    return Content(@"http://www.google.co.uk");
}

Javascript

$.ajax({
    type: 'POST',
    url: '/AjaxMethod',
    success: function (redirect) {
        window.location = redirect;
    }
});

Grazie! Questo mi ha davvero aiutato.
dee

5

Puoi semplicemente scrivere in Ajax Success come di seguito:

 $.ajax({
            type: "POST",
            url: '@Url.Action("GetUserList", "User")',
            data: { id: $("#UID").val() },
            success: function (data) {
                window.location.href = '@Url.Action("Dashboard", "User")';
            },
            error: function () {
                $("#loader").fadeOut("slow");
            }
});

2

Cosa ne pensi di questo :

public ActionResult GetGrid()
{
   string url = "login.html";
   return new HttpStatusCodeResult(System.Net.HttpStatusCode.Redirect,url)
}

E poi

$(document).ajaxError(function (event, jqxhr, settings, thrownError) { 
   if (jqxhr.status == 302) {
      location.href = jqxhr.statusText;
   }           
});

O

error: function (a, b, c) {
       if (a.status == 302) {
         location.href = a.statusText;
       }  
}

1

Avevo bisogno di farlo perché ho un modulo di accesso ajax. Quando gli utenti accedono con successo, reindirizzo a una nuova pagina e concludo la richiesta precedente perché l'altra pagina gestisce il reindirizzamento alla relying party (perché è un sistema SSO STS).

Tuttavia, volevo anche che funzionasse con javascript disabilitato, essendo l'hop di accesso centrale e tutto il resto, quindi ho pensato a questo,

    public static string EnsureUrlEndsWithSlash(string url)
    {
        if (string.IsNullOrEmpty(url))
            throw new ArgumentNullException("url");
        if (!url.EndsWith("/"))
            return string.Concat(url, "/");
        return url;
    }

    public static string GetQueryStringFromArray(KeyValuePair<string, string>[] values)
    {
        Dictionary<string, string> dValues = new Dictionary<string,string>();
        foreach(var pair in values)            
            dValues.Add(pair.Key, pair.Value);            
        var array = (from key in dValues.Keys select string.Format("{0}={1}", HttpUtility.UrlEncode(key), HttpUtility.UrlEncode(dValues[key]))).ToArray();
        return "?" + string.Join("&", array);
    }

    public static void RedirectTo(this HttpRequestBase request, string url, params KeyValuePair<string, string>[] queryParameters)
    {            
        string redirectUrl = string.Concat(EnsureUrlEndsWithSlash(url), GetQueryStringFromArray(queryParameters));
        if (request.IsAjaxRequest())
            HttpContext.Current.Response.Write(string.Format("<script type=\"text/javascript\">window.location='{0}';</script>", redirectUrl));
        else
            HttpContext.Current.Response.Redirect(redirectUrl, true);

    }

1

Puoi semplicemente fare una sorta di filtro di risposta ajax per le risposte in entrata con $ .ajaxSetup . Se la risposta contiene il reindirizzamento MVC è possibile valutare questa espressione sul lato JS. Codice di esempio per JS di seguito:

$.ajaxSetup({
    dataFilter: function (data, type) {
        if (data && typeof data == "string") {
            if (data.indexOf('window.location') > -1) {
                eval(data);
            }
        }
        return data;
    }
});

Se i dati sono: "window.location = '/ Acount / Login'" sopra, il filtro li rileverà e valuterà per effettuare il reindirizzamento.


0

Non sono soddisfatto della migliore risposta da parte di Giuseppe, invece di risolvere il problema corretto, ha detto che questo è un caso d'uso sbagliato. In effetti ci sono molti posti, ad esempio, se stai convertendo una vecchia base di codice in codice ajaxified e lì ne hai bisogno, quindi ne hai bisogno. Nella programmazione non ci sono scuse perché non sei solo tu a programmare, sono tutti bravi e cattivi sviluppatori e devi lavorare fianco a fianco. Quindi, se non eseguo il reindirizzamento del codice in ajax, il mio collega sviluppatore può costringermi a trovare una soluzione. Proprio come mi piace usare tutti i siti con pattern AMD o mvc4, e la mia azienda può tenermi lontano da esso per un anno.

Quindi parliamo ora della soluzione.

Ho fatto un inferno con la gestione delle richieste e delle risposte ajax e il modo più semplice che ho scoperto è stato quello di inviare codici di stato al client e avere una funzione javascript standard per comprendere quei codici. Se invio semplicemente ad esempio il codice 13, potrebbe significare un reindirizzamento.

Quindi una risposta json come {statusCode: 13, messsage: '/ home / loggato'} ovviamente ci sono tonnellate di varianti proposte come {status: 'success', codice: 13, url: '/ home / loggato ", messaggio:" Hai effettuato l'accesso ora "}

ecc., quindi fino alla tua scelta di messaggi standard

Di solito eredito dalla classe Controller di base e metto la mia scelta di risposte standard come questa

public JsonResult JsonDataResult(object data, string optionalMessage = "")
    {
        return Json(new { data = data, status = "success", message = optionalMessage }, JsonRequestBehavior.AllowGet);
    }

    public JsonResult JsonSuccessResult(string message)
    {
        return Json(new { data = "", status = "success", message = message }, JsonRequestBehavior.AllowGet);
    }

    public JsonResult JsonErrorResult(string message)
    {
        return Json(new { data = "", status = "error", message = message }, JsonRequestBehavior.AllowGet);
    }

    public JsonResult JsonRawResult(object data)
    {
        return Json(data, JsonRequestBehavior.AllowGet);
    }

Sull'utilizzo di $ .ajax invece di Ajax.BeginForm Mi piacerebbe usare Jquery ajax e lo faccio, ma ancora una volta non sono io in tutto il mondo a prendere decisioni, ho un'applicazione piena di Ajax.BeginForm e ovviamente non l'ho fatto. Ma devo conviverci.

Quindi c'è un callback di successo anche nella forma iniziale, non è necessario utilizzare jquery ajax per utilizzare i callback Qualcosa al riguardo qui Ajax.BeginForm, Calls Action, Returns JSON, Come posso accedere all'oggetto JSON nella mia funzione JS OnSuccess?

Grazie


0

Se esegui il reindirizzamento dalla classe JavaScript

stessa vista - controller diverso

<strike>window.location.href = `'Home'`;</strike>

non è la stessa vista

<strike>window.location.href = `'Index/Home'`;</strike>

0

Aggiungi una classe di supporto:

public static class Redirector {
        public static void RedirectTo(this Controller ct, string action) {
            UrlHelper urlHelper = new UrlHelper(ct.ControllerContext.RequestContext);

            ct.Response.Headers.Add("AjaxRedirectURL", urlHelper.Action(action));
        }

        public static void RedirectTo(this Controller ct, string action, string controller) {
            UrlHelper urlHelper = new UrlHelper(ct.ControllerContext.RequestContext);

            ct.Response.Headers.Add("AjaxRedirectURL", urlHelper.Action(action, controller));
        }

        public static void RedirectTo(this Controller ct, string action, string controller, object routeValues) {
            UrlHelper urlHelper = new UrlHelper(ct.ControllerContext.RequestContext);

            ct.Response.Headers.Add("AjaxRedirectURL", urlHelper.Action(action, controller, routeValues));
        }
    }

Quindi chiama la tua azione:

this.RedirectTo ("Indice", "Cemento");

Aggiungi il codice javascript a qualsiasi file globale incluso javascript o file di layout per intercettare tutte le richieste ajax:

<script type="text/javascript">
  $(function() {
    $(document).ajaxComplete(function (event, xhr, settings) {
            var urlHeader = xhr.getResponseHeader('AjaxRedirectURL');

            if (urlHeader != null && urlHeader !== undefined) {
                window.location = xhr.getResponseHeader('AjaxRedirectURL');
            }
        });
  });
</script>


0

Come dice Ben Foster, puoi restituire i Javascript e ti reindirizzerà alla pagina desiderata.

Per caricare la pagina nella pagina corrente:

return JavaScript("window.location = 'http://www.google.co.uk'");'

Per caricare la pagina nella nuova scheda:

return JavaScript("window.open('http://www.google.co.uk')");

0

Puoi ottenere un reindirizzamento non basato su js da una chiamata ajax inserendo uno di questi meta tag di aggiornamento. Questo qui sembra funzionare: return Content("<meta http-equiv=\"refresh\" content=\"0;URL='" + @Url.Action("Index", "Home") + "'\" />");

Nota: ho scoperto che i meta refresh vengono disabilitati automaticamente da Firefox, rendendolo non molto utile.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.