Как получить ответ ASP.NET MVC Ajax для перенаправления на новую страницу вместо вставки представления в UpdateTargetId?

Я использую Ajax.BeginForm для создания формы, которая будет выполнять обратную передачу ajax для определенного действия контроллера, а затем, если действие выполнено успешно, пользователь должен быть перенаправлен на другую страницу (если действие не удается, отображается сообщение о состоянии, используя 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]
   }

Если удаление прошло успешно, я возвращаю результат перенаправления:

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

Но представление индекса Home Controller загружается в UpdateTargetId, и поэтому я получаю страницу внутри страницы. Я думаю о двух вещах:

  1. Либо я спроектировал это неправильно, и должен обрабатывать этот тип действий по-другому (без использования ajax).
  2. Вместо того, чтобы возвращать результат перенаправления, верните представление, в котором есть javascript, который выполняет перенаправление на стороне клиента.

Есть ли у кого-нибудь комментарии по №1? Или, если №2 - хорошее решение, как будет выглядеть «перенаправление просмотра javascript»?


person Jeff Widmer    schedule 08.10.2009    source источник


Ответы (15)


Для этого можно использовать JavascriptResult.

Для перенаправления:

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

Чтобы перезагрузить текущую страницу:

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

Кажется, самый простой вариант.

person Ben Foster    schedule 15.08.2011
comment
Согласен, это правильный подход. В этом ответе stackoverflow.com/a/2841608/498969 показано, как можно применить эту функцию по умолчанию с помощью базового контроллера. - person Adam Spicer; 13.06.2012
comment
@Ben Foster: Используя этот обзор, пытается открыть url http :: window.location ... Я разместил это как отдельный вопрос в stackoverflow.com/questions/13896307/ - person Andrus; 16.12.2012
comment
Если вы хотите перенаправить на контроллер в своем проекте, вы можете использовать помощник URL. Например: return JavaScript( "window.location = '" + Url.Action("Edit","Dispatch") + "'" ); - person Chris Morgan; 23.05.2013
comment
От этого мне хочется плакать. Комбинация идей и идея базового контроллера великолепны. - person secretwep; 03.05.2019

Вы можете вернуть JSON с URL-адресом и изменить window.location с помощью JavaScript на стороне клиента. Я предпочитаю этот способ, чем вызов функции JavaScript с сервера, который, как мне кажется, нарушает разделение задач.

Сторона сервера:

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

Сторона клиента:

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

Конечно, вы можете добавить больше логики, потому что на стороне сервера может быть ошибка, и в этом случае свойство result может указать на эту ситуацию и избежать перенаправления.

person Francisco Goldenstein    schedule 10.07.2014

Хотя это не изящно, но в определенных ситуациях у меня работает.

Контроллер

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

Модель

    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>
person Valamas    schedule 12.07.2011
comment
Почему не элегантно? Он строго типизирован и кажется ясным. Мне нравится такой подход. +1 - person T-moty; 06.05.2015

Поведение, которое вы пытаетесь создать, на самом деле не лучше всего делать с помощью AJAX. AJAX лучше всего использовать, если вы хотите обновить только часть страницы, а не полностью перенаправить на другую страницу. Это действительно противоречит цели AJAX.

Я бы посоветовал просто не использовать AJAX с поведением, которое вы описываете.

В качестве альтернативы вы можете попробовать использовать jquery Ajax, который отправит запрос, а затем вы укажете обратный вызов, когда запрос завершится. В обратном вызове вы можете определить, удалось ли оно или нет, и перенаправить на другую страницу в случае успеха. Я обнаружил, что использовать jquery Ajax намного проще, тем более что я уже использую библиотеку для других целей.

Вы можете найти документацию по jquery ajax здесь, но ее синтаксис следующий:

jQuery.ajax( options )  

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

jQuery.getJSON( url, data, callback )

jQuery.getScript( url, callback )

jQuery.post( url, data, callback, type)
person Joseph    schedule 08.10.2009
comment
Итак, просто выполните обычную POST для действия Delete, и в большинстве случаев оно будет успешным, а затем я могу перенаправить на страницу Home Index. В случаях, когда произойдет сбой, отобразите другое представление с сообщениями об ошибках и соответствующими действиями, которые должен предпринять пользователь. Звук в порядке? - person Jeff Widmer; 08.10.2009
comment
Да, похоже, в этом было бы больше смысла. - person Joseph; 08.10.2009
comment
Я продолжил преобразование этого из отправки Ajax в обычный POST в соответствии с рекомендацией Джозефа. На самом деле это сработало лучше, поскольку дало мне более чистый способ обработки сообщений с подтверждением удаления. - person Jeff Widmer; 08.10.2009

Использование JavaScript определенно сработает.

Вы также можете использовать Content, если это больше вам нравится.

Пример:

Контроллер MVC

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

Javascript

$.ajax({
    type: 'POST',
    url: '/AjaxMethod',
    success: function (redirect) {
        window.location = redirect;
    }
});
person christo8989    schedule 16.03.2015
comment
Спасибо! Это мне действительно помогло. - person dee; 16.04.2020

Вы можете просто написать в Ajax Success, как показано ниже:

 $.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");
            }
});
person Hiren Patel    schedule 08.09.2016

Как насчет этого :

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

А потом

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

Или

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

Мне нужно было это сделать, потому что у меня есть форма входа в систему с помощью ajax. Когда пользователи успешно входят в систему, я перенаправляю на новую страницу и завершаю предыдущий запрос, потому что другая страница обрабатывает перенаправление обратно проверяющей стороне (потому что это система SSO STS).

Однако я также хотел, чтобы он работал с отключенным javascript, являющимся центральным переходом для входа в систему и всем остальным, поэтому я придумал это,

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

    }
person Ryan Mann    schedule 28.07.2014

Вы можете просто создать своего рода фильтр ответов ajax для входящих ответов с помощью $ .ajaxSetup. Если ответ содержит перенаправление MVC, вы можете оценить это выражение на стороне JS. Пример кода для JS ниже:

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

Если данные: "window.location = '/ Acount / Login'", указанный выше фильтр поймает это и оценит, чтобы выполнить перенаправление.

person Przemek Marcinkiewicz    schedule 27.10.2016

Я не удовлетворен лучшим ответом Джозефа, вместо того, чтобы исправить правильную проблему, он сказал, что это неправильный вариант использования. На самом деле, есть много мест, например, если вы конвертируете старую кодовую базу в ajaxified код, и там она вам НУЖНА, значит, она вам НУЖНА. В программировании нет оправдания, потому что не только вы кодите всех плохих и хороших разработчиков, и вы должны работать бок о бок. Поэтому, если я не кодирую перенаправление в ajax, мой коллега-разработчик может заставить меня найти решение для него. Точно так же, как мне нравится использовать все сайты с узором AMD или mvc4, и моя компания может держать меня подальше от этого в течение года.

Итак, давайте поговорим о решении.

Я чертовски проделал обработку запросов и ответов ajax, и самый простой способ, который я обнаружил, - это отправить коды состояния клиенту и использовать одну стандартную функцию javascript для понимания этих кодов. Если я просто отправлю, например, код 13, это может означать перенаправление.

Итак, ответ json, например {statusCode: 13, messsage: '/ home / logged-in'}, конечно, предлагается множество вариантов, таких как {status: 'success', code: 13, url: '/ home / logged-in ', сообщение:' Вы вошли в систему '}

и т. д., так что на ваш выбор стандартные сообщения

Обычно я наследую от базового класса контроллера и выбираю стандартные ответы, подобные этому

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

Об использовании $ .ajax intead для Ajax.BeginForm Я бы с удовольствием использовал JQuery ajax, и я использую его, но, опять же, это не я во всем мире, чтобы принимать решения. У меня есть приложение, полное Ajax.BeginForm, и, конечно, я этого не делал. Но я должен с этим жить.

Итак, в форме начала есть обратный вызов успеха, вам не нужно использовать jquery ajax для использования обратных вызовов. Что-то об этом здесь Ajax.BeginForm, вызывает действие, возвращает JSON, как мне получить доступ к объекту JSON в моей функции OnSuccess JS?

Спасибо

person Asif Ashraf    schedule 29.04.2012

Если вы перенаправляете из класса JavaScript

тот же вид - другой контроллер

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

это не то же мнение

<strike>window.location.href = `'Index/Home'`;</strike>
person aslanpayi    schedule 22.12.2013

Добавьте вспомогательный класс:

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

Затем призовите к действию:

this.RedirectTo («Индекс», «Цемент»);

Добавьте код javascript в любой глобальный включенный файл javascript или файл макета, чтобы перехватить все запросы 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>

person faisale    schedule 24.08.2015

Как говорит Бен Фостер, вы можете вернуть Javascripts, и он перенаправит вас на нужную страницу.

Чтобы загрузить страницу на текущей странице:

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

Чтобы загрузить страницу в новой вкладке:

return JavaScript("window.open('http://www.google.co.uk')");
person Trilok Pathak    schedule 20.05.2016

Вы можете получить перенаправление не на основе js из вызова ajax, вставив один из этих мета-тегов обновления. Кажется, вот это работает: return Content("<meta http-equiv=\"refresh\" content=\"0;URL='" + @Url.Action("Index", "Home") + "'\" />");

Примечание: я обнаружил, что мета-обновления автоматически отключаются Firefox, что делает это не очень полезным.

person Vasily Hall    schedule 17.04.2017

Принятый ответ работает хорошо, за исключением того факта, что javascript кратко отображается в любом целевом элементе ajax. Чтобы обойти это, создайте частичное представление с именем _Redirect со следующим кодом:

@model string
<script>
   window.location = '@Model';
</script>

Затем в контроллере замените

return Redirect(Url.Action("Index", "Home"));

с участием

return PartialView("_Redirect",Url.Action("Index", "Home"));

Эффект такой же, как у принятого ответа, но без краткого артефакта на дисплее. Поместите _Redirect.cshtml в общую папку, чтобы его можно было использовать откуда угодно.

person Gene Stempel    schedule 29.01.2021