Як отримати відповідь ASP.NET MVC Ajax на перенаправлення на нову сторінку, замість того, щоб вставляти подання в UpdateTargetId?


88

Я використовую 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"));
}

Але подання Index Controller Home завантажується в UpdateTargetId, і, отже, у мене з’являється сторінка всередині сторінки. Дві речі, про які я думаю:

  1. Або я розробляю це неправильно, і повинен поводитися з цим типом дій по-іншому (не використовуючи ajax).
  2. Замість повернення результату переадресації, поверніть подання, в якому є javascript, що робить переспрямування на стороні клієнта.

Хтось має коментарі до No1? Або, якщо №2 є хорошим рішенням, як би виглядав "перегляд переадресації javascript"?

Відповіді:


171

Ви можете використовувати JavascriptResultдля досягнення цього.

Щоб перенаправити:

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

Щоб перезавантажити поточну сторінку:

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

Здається найпростішим варіантом.


4
Чудово .. Допоміг мені.
CrazyCoderz

1
Я згоден, це правильний підхід. Ця відповідь stackoverflow.com/a/2841608/498969 показує, як ви можете застосувати цю функцію за замовчуванням за допомогою базового контролера.
Адам Спайсер

@Ben Foster: Використовуючи цей огляд, намагається відкрити url http :: window.location ... Я опублікував це як окреме запитання в stackoverflow.com/questions/13896307/…
Андрус

30
Якщо ви хочете перенаправити на контролер у своєму проекті, ви можете використовувати помічник Url для вас. Наприклад:return JavaScript( "window.location = '" + Url.Action("Edit","Dispatch") + "'" );
Кріс Морган

2
Короткий. Простий. Відмінно. Чудово!
Вікрам

30

Ви можете повернути 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 може вказувати на цю ситуацію та уникати перенаправлення.


12

Поведінка, яку ви намагаєтесь створити, насправді не найкраще виконувати за допомогою 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)

Тоді просто виконайте звичайний POST до дії Delete, і в більшості випадків це вдасться, і тоді я можу перенаправити на сторінку Домашнього індексу. У тих випадках, коли це не вдається, відобразіть інший вигляд із повідомленнями про помилки та відповідними діями для користувача. Звучить нормально?
Джефф Відмер,

Так, це звучить так, якби це мало більше сенсу.
Джозеф

Я продовжив перетворення цього з подання Ajax на звичайний POST відповідно до рекомендацій Джозефа. Це насправді вийшло краще, оскільки це дало мені більш чистий спосіб обробки повідомлень про підтвердження видалення.
Джефф Відмер,

12

Хоча він не елегантний, він працює у мене в певних ситуаціях.

Контролер

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>

2
Чому не елегантний? Це сильно набрано, і це відчуває себе чітко. Мені подобається такий підхід. +1
T-moty

6

Використовуючи 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;
    }
});

Дякую! Це мені справді допомогло.
dee

5

Ви можете просто написати в 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");
            }
});

2

Як щодо цього:

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

1

Мені потрібно було це зробити, оскільки я маю форму для входу в ajax. Після успішного входу користувачів я перенаправляю на нову сторінку і закінчую попередній запит, оскільки інша сторінка обробляє перенаправлення назад до надійної сторони (оскільки це система STS SSO).

Однак я також хотів, щоб він працював із відключеним 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);

    }

1

Ви можете просто зробити якийсь фільтр відповідей 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 = '/ Account / Login'", вище фільтр вловить це та оцінить, щоб зробити переспрямування.


0

Я не задоволений найкращою відповіддю Джозефа, замість того, щоб виправити правильну проблему, він сказав, що це неправильний варіант використання. Насправді є багато місць, наприклад, якщо ви перетворюєте стару базу кодів у невісний код і там вона вам ПОТРІБНА, то вона вам ПОТРІБНА. У програмуванні немає виправдання, тому що кодуєш його всіх поганих і хороших розробників не тільки ти, і ти повинен працювати поруч. Отже, якщо я не перенаправляю код у ajax, мій колега-розробник може змусити мене знайти рішення для нього. Так само, як я люблю користуватися всіма шаблонами AMD або mvc4, і моя компанія може тримати мене подалі від нього на рік.

Тож поговоримо про рішення зараз.

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

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

і т. д., тож до власного вибору стандартних повідомлень

Зазвичай я отримую спадщину від базового класу Controller і вибираю стандартні відповіді на зразок цього

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, і я, звичайно, цього не робив. Але я повинен жити з цим.

Отже, є успішний зворотний виклик і у формі start , вам не потрібно використовувати jquery ajax для використання зворотних викликів. Щось про це тут Ajax.BeginForm, Calls Action, Returns JSON, Як отримати доступ до об'єкта JSON у моїй функції OnSuccess JS?

Дякую


0

Якщо ви переспрямовуєте з класу JavaScript

той самий вигляд - інший контролер

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

не однаковий погляд

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

0

Додайте допоміжний клас:

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>


0

Як сказав Бен Фостер, ви можете повернути Javascripts, і він перенаправить вас на потрібну сторінку.

Щоб завантажити сторінку на поточній сторінці:

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

Щоб завантажити сторінку в новій вкладці:

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

0

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

Примітка: Я виявив, що метаоновлення Firefox автоматично вимикає, що робить це не дуже корисним.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.