Умный способ обработки возвращаемых URL-адресов в среде MVC

Проблема, с которой я сталкиваюсь снова и снова, обрабатывает перенаправление на предыдущую страницу после того, как пользователь выполнил некоторые действия, такие как нажатие ссылки "Назад..." или сохранение записи, которую они редактируют.

Ранее, когда мне нужно было знать, на какой странице вернуться, я бы предоставил параметр returnURL для моего текущего представления.

http://blah.com/account/edit/1?returnURL="account/index"

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

http://blah.com/account/edit/1?returnURL="account/index?search="searchTerm""

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

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

Итак, мой вопрос: кто-нибудь нашел умный способ справиться с такой ситуацией, особенно в среде MVC?

Примечание. Я использую ASP.NET MVC, поэтому, если возможно, мне бы хотелось, чтобы ответы на них были связаны, однако любые идеи приветствуются.

Ответы

Ответ 1

Что случилось с настройкой файла cookie или использованием переменной сеанса? Единственная причина, по которой вы этого не сделаете, - это не управлять страницей, которая вызывает вас, и в этом случае вашими единственными параметрами являются строки запроса, значения post или referrer.

Ответ 2

Я думал, что могу добавить свой ответ на вопрос, чтобы убедиться, что другие считают это хорошей идеей.

Я просто передаю его контроллеру с помощью TempViewData:

@{
   TempData["returnURL"] = Request.Url.AbsoluteUri;
}

а затем доступ к нему аналогично этому (в моей реальной версии я проверяю, что ключ находится в TempData и что returnURL - настоящий URL-адрес):

return Redirect(TempData["returnURL"].ToString());

Если это необходимо для продолжения первой смены страницы (то есть страницы поиска → Страница "Редактировать" → Страница "Редактировать раздел" ), я добавляю ее снова

TempData["returnURL"] = TempData["returnURL"];

Ответ 3

Отметьте мой пост в блоге: Использование файлов cookie для управления страницей возврата после входа в asp.net mvc 3

Как упоминал @Mystere Man, вы можете просто использовать для него cookie или сеанс. Я отправился за печеньями, когда у меня была подобная ситуация некоторое время назад.

Ответ 4

Попробуйте зарегистрировать новый маршрут, по которому URL-адрес /{controller}/{action}/{id}/returnurl/{*url}, а затем используйте RedirectToAction в действии, которое принимает URL-адрес в качестве параметра

Ответ 5

Request.UrlReferrer.AbsoluteUri

хотя я бы все же утверждал, что вы не должны создавать свою собственную кнопку "назад".

Ответ 6

Используйте перехватчик или аспект:

  • Перехватить каждый запрос в некотором роде (например, аспект @Before) и сохранить запрошенный URL-адрес на сеанс, каждый раз переписывая его
  • В вашем слое просмотра, при необходимости, получите доступ к этому объекту сеанса в вашем случае для обратной ссылки.

Этот вид дизайна позволяет всегда иметь самый последний запрос, если вы хотите его использовать. Вот пример, чтобы написать аспект/перехватчик в .NET. Дополнительно, PostSharp - это проект аспект .NET.

Ответ 7

В настоящее время быстрый и грязный метод ускользнул от меня... поэтому я использую практический метод.

На концептуальном уровне "обратная способность" страницы должна определяться страницей, на которой вы сейчас находитесь. Вид может сделать это (в большинстве случаев), если параметры, захваченные в контроллере, передаются ему через ViewModel.

Пример:

Посетив Foo, я перейду к Bar, чтобы просмотреть некоторые вещи, а кнопка назад должна вернуться к Foo.

контроллер

public ActionResult Foo(string fooId) // using a string for your Id, good idea; Encryption, even better.
{
    FooModel model = new FooModel() { fooId = fooId }; // property is passed to the Model - important.
    model.Fill();
    return View("FooView", model);
}

public ActionResult Bar(string fooId, string barId)
{
    BarModel model = new BarModel() { fooId = fooId; barId = barId };
    model.Fill()
    return View("BarView", model)
}

ViewModels

public class FooModel
{
    public string fooId { get; set; }

    public void Fill()
    {
        // Get info from Repository.
    }
}

public class BarModel
{
    public string fooId { get; set; }
    public string barId { get; set; }

    public void Fill()
    {
        // Get info from Repository.
    }
}

Просмотр (частичный) // No pun intended... or maybe it was. :)

Теперь ваш BarView может интерпретировать из своей модели, где ему нужно вернуться (используя fooId).

На вашем BarView (с использованием синтаксиса MVC2):

<a href="<%= string.Format("/Foo?fooId={0}", Model.fooId) %>">Back</a>

Вы также можете использовать Html.ActionLink.

В качестве альтернативы:

Вы можете наследовать свои ViewModels из BaseViewModel, который может иметь защищенное свойство returnURL. Установите это, если необходимо.

Пример:

На вашем ViewModel:

public class BarModel : BaseViewModel
{
    public string fooId { get; set; }
    public string barId { get; set; }

    public void Fill()
    {
        returnURL = string.Format("/Foo?fooId={0}", fooId)
        // Get info from Repository.
    }
}

В представлении:

<a href="<%=returnURL %>">Back</a>

Ответ 8

Будет ли это лучше обрабатываться частичными действиями, которые отображаются без выхода из страницы и с помощью JQuery, чтобы создать рабочий процесс диалога/мастера?

Затем вам нужно только отреагировать на кнопку "Готово" в диалоговом окне, чтобы обновить исходный вид.

Ответ 9

В части вашего вопроса относительно сохранения записи, которую они редактируют, я бы подумал, что шаблон post-redirect-get (PGR) применим к вам.

Это может быть хорошим местом, чтобы прочитать об этом, если вы не знакомы с ним.

Ответ 10

  • Кодировать returnUrl, используя Url.Encode(returnUrl) для включения в URL.
  • Когда вы готовы перенаправить, используйте Url.Decode(returnUrl) и используйте значение для фактического перенаправления.