Wie erhalte ich eine ASP.NET MVC Ajax-Antwort, um auf eine neue Seite umzuleiten, anstatt eine Ansicht in UpdateTargetId einzufügen?

88

Ich verwende Ajax.BeginForm, um ein Formular zu erstellen, das ein Ajax-Postback für eine bestimmte Controller-Aktion ausführt. Wenn die Aktion erfolgreich ist, sollte der Benutzer auf eine andere Seite umgeleitet werden (wenn die Aktion fehlschlägt, wird eine Statusmeldung mit angezeigt die 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]
   }

Wenn das Löschen erfolgreich ist, gebe ich ein Umleitungsergebnis zurück:

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

Die Home Controller-Indexansicht wird jedoch in die UpdateTargetId geladen, sodass ich eine Seite innerhalb einer Seite habe. Zwei Dinge, über die ich nachdenke:

  1. Entweder entwerfe ich das falsch und sollte diese Art von Aktion anders behandeln (ohne Ajax).
  2. Anstatt ein Redirect-Ergebnis zurückzugeben, geben Sie eine Ansicht mit Javascript zurück, die die Umleitung auf der Clientseite ausführt.

Hat jemand Kommentare zu # 1? Oder wenn # 2 eine gute Lösung ist, wie würde die "Javascript-Ansicht umleiten" aussehen?

Jeff Widmer
quelle

Antworten:

170

Sie können verwenden JavascriptResult, um dies zu erreichen.

So leiten Sie um:

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

So laden Sie die aktuelle Seite neu:

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

Scheint die einfachste Option.

Ben Foster
quelle
4
Super. Hat mir geholfen.
CrazyCoderz
1
Ich stimme zu, das ist der richtige Ansatz. Diese Antwort stackoverflow.com/a/2841608/498969 zeigt, wie Sie diese Funktionalität standardmäßig mithilfe eines Basiscontrollers anwenden können.
Adam Spicer
@ Ben Foster: Mit dieser Suche wird versucht, die URL http :: window.location zu öffnen. Ich habe dies als separate Frage in stackoverflow.com/questions/13896307/…
Andrus
30
Wenn Sie zu einem Controller in Ihrem Projekt umleiten möchten, können Sie den URL-Helfer für Sie verwenden. Zum Beispiel:return JavaScript( "window.location = '" + Url.Action("Edit","Dispatch") + "'" );
Chris Morgan
2
Kurz. Einfach. Ausgezeichnet. Toll!
Vikram Singh Saini
30

Sie können einen JSON mit der URL zurückgeben und die window.location mithilfe von JavaScript auf der Clientseite ändern. Ich bevorzuge diesen Weg, als eine JavaScript-Funktion vom Server aufzurufen, was meiner Meinung nach die Trennung von Bedenken aufhebt.

Serverseite:

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

Client-Seite:

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

Natürlich können Sie weitere Logik hinzufügen, da auf der Serverseite ein Fehler auftreten kann. In diesem Fall kann die Eigenschaft result auf diese Situation hinweisen und die Umleitung vermeiden.

Francisco Goldenstein
quelle
12

Das Verhalten, das Sie erzeugen möchten, lässt sich mit AJAX nicht am besten ausführen. AJAX wird am besten verwendet, wenn Sie nur einen Teil der Seite aktualisieren und nicht vollständig auf eine andere Seite umleiten möchten. Das macht den ganzen Zweck von AJAX wirklich zunichte.

Ich würde vorschlagen, AJAX nicht mit dem von Ihnen beschriebenen Verhalten zu verwenden.

Alternativ können Sie versuchen, jquery Ajax zu verwenden, das die Anforderung sendet, und dann einen Rückruf angeben, wenn die Anforderung abgeschlossen ist. Im Rückruf können Sie feststellen, ob dies fehlgeschlagen oder erfolgreich war, und bei Erfolg auf eine andere Seite umleiten. Ich habe festgestellt, dass jquery Ajax viel einfacher zu verwenden ist, zumal ich die Bibliothek ohnehin schon für andere Zwecke verwende.

Eine Dokumentation zu jquery ajax finden Sie hier . Die Syntax lautet jedoch wie folgt:

jQuery.ajax( options )  

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

jQuery.getJSON( url, data, callback )

jQuery.getScript( url, callback )

jQuery.post( url, data, callback, type)
Joseph
quelle
Führen Sie dann einfach einen regulären POST für die Aktion "Löschen" durch. In den meisten Fällen ist dies erfolgreich, und ich kann zur Seite "Home-Index" umleiten. Zeigen Sie in den Fällen, in denen dies fehlschlagen würde, eine andere Ansicht mit den Fehlermeldungen und der entsprechenden Aktion an, die der Benutzer ausführen soll. Hört sich gut an?
Jeff Widmer
Ja, das klingt nach mehr Sinn.
Joseph
Ich habe dies gemäß Josephs Empfehlung von einem Ajax-Submit in einen regulären POST umgewandelt. Dies hat tatsächlich besser geklappt, da ich die Löschbestätigungsnachricht sauberer handhaben konnte.
Jeff Widmer
12

Obwohl nicht elegant, funktioniert es in bestimmten Situationen für mich.

Regler

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

Modell

    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>
Valamas
quelle
2
Warum nicht elegant? Es ist stark getippt und es fühlt sich klar an. Ich mag diesen Ansatz. +1
T-Moty
6

Die Verwendung JavaScriptwird definitiv den Job machen.

Sie können auch verwenden, Contentwenn dies mehr Ihr Stil ist.

Beispiel:

MVC-Controller

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

Javascript

$.ajax({
    type: 'POST',
    url: '/AjaxMethod',
    success: function (redirect) {
        window.location = redirect;
    }
});
christo8989
quelle
Danke dir! Das hat mir wirklich geholfen.
Dee
5

Sie können einfach wie folgt in Ajax Success schreiben:

 $.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");
            }
});
Hiren Patel
quelle
2

Wie wäre es damit :

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

Und dann

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

Oder

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

Ich musste dies tun, weil ich ein Ajax-Anmeldeformular habe. Wenn sich Benutzer erfolgreich anmelden, leite ich auf eine neue Seite um und beende die vorherige Anforderung, da auf der anderen Seite die Weiterleitung an die vertrauende Partei erfolgt (da es sich um ein STS-SSO-System handelt).

Ich wollte jedoch auch, dass es mit deaktiviertem Javascript funktioniert, da es der zentrale Login-Hop ist und so weiter.

    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);

    }
Ryan Mann
quelle
1

Sie können einfach eine Art Ajax-Antwortfilter für eingehende Antworten mit $ .ajaxSetup ausführen . Wenn die Antwort eine MVC-Umleitung enthält, können Sie diesen Ausdruck auf der JS-Seite auswerten. Beispielcode für JS unten:

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

Wenn die Daten lauten : "window.location = '/ Acount / Login'" über dem Filter, wird dies abgefangen und ausgewertet, um die Umleitung vorzunehmen.

Przemek Marcinkiewicz
quelle
0

Ich bin nicht zufrieden mit der besten Antwort von Joseph, anstatt das richtige Problem zu beheben, sagte er, dass dies ein falscher Anwendungsfall ist. In der Tat gibt es viele Orte, zum Beispiel, wenn Sie eine alte Codebasis in ajaxifizierten Code konvertieren und dort brauchen Sie es, dann brauchen Sie es. Bei der Programmierung gibt es keine Entschuldigung, denn nicht nur Sie programmieren die schlechten und guten Entwickler und Sie müssen Seite an Seite arbeiten. Wenn ich die Umleitung in Ajax nicht codiere, kann mein Entwickler mich zwingen, eine Lösung dafür zu finden. Genauso wie ich alle AMD-gemusterten Sites oder mvc4 verwenden möchte und meine Firma mich ein Jahr lang davon fernhalten kann.

Sprechen wir jetzt über die Lösung.

Ich habe verdammt viel Ajax-Anfragen und -Antworten bearbeitet und der einfachste Weg, den ich herausgefunden habe, war, Statuscodes an den Client zu senden und eine Standard-Javascript-Funktion zu haben, um diese Codes zu verstehen. Wenn ich zum Beispiel einfach Code 13 sende, könnte dies eine Weiterleitung bedeuten.

Für eine JSON-Antwort wie {statusCode: 13, messsage: '/ home / logged-in'} werden natürlich unzählige Variationen vorgeschlagen, wie {status: 'success', code: 13, url: '/ home / logged-in ', Nachricht:' Sie sind jetzt angemeldet '}

usw., also bis zu Ihrer eigenen Auswahl an Standardnachrichten

Normalerweise erbe ich von der Basis-Controller-Klasse und stelle meine Auswahl an Standardantworten wie folgt ein

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);
    }

Über die Verwendung von $ .ajax anstelle von Ajax.BeginForm Ich würde gerne Jquery Ajax verwenden, aber ich bin es nicht auf der ganzen Welt, um Entscheidungen zu treffen. Ich habe eine Anwendung voller Ajax.BeginForm und natürlich habe ich das nicht getan. Aber ich muss damit leben.

Es gibt also auch einen erfolgreichen Rückruf in der Startform. Sie müssen jquery ajax nicht verwenden, um Rückrufe zu verwenden. Ajax.BeginForm, Calls Action, Rückgabe von JSON, Wie greife ich in meiner OnSuccess JS-Funktion auf das JSON-Objekt zu?

Vielen Dank

Asif Ashraf
quelle
0

Wenn Sie von der JavaScript-Klasse umleiten

gleiche Ansicht - unterschiedliche Steuerung

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

ist nicht die gleiche Ansicht

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

Fügen Sie eine Hilfsklasse hinzu:

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));
        }
    }

Rufen Sie dann Ihre Aktion auf:

this.RedirectTo ("Index", "Zement");

Fügen Sie Javascript-Code zu jeder globalen Javascript-Datei oder Layout-Datei hinzu, um alle Ajax-Anforderungen abzufangen:

<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>

faisale
quelle
0

Wie Ben Foster sagt, können Sie die Javascripts zurückgeben und es wird Sie zur gewünschten Seite weiterleiten.

So laden Sie eine Seite auf der aktuellen Seite:

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

So laden Sie die Seite auf der neuen Registerkarte:

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

Sie können eine nicht auf js basierende Umleitung von einem Ajax-Aufruf erhalten, indem Sie eines dieser Meta-Refresh-Tags eingeben. Das hier scheint zu funktionieren: return Content("<meta http-equiv=\"refresh\" content=\"0;URL='" + @Url.Action("Index", "Home") + "'\" />");

Hinweis: Ich habe festgestellt, dass Meta-Aktualisierungen von Firefox automatisch deaktiviert werden, was dies nicht sehr nützlich macht.

Vasily Hall
quelle