ASP.NET MVC: UrlReferrer или куда послать пользователя

ru-RU | создано: 26.03.2013 | опубликовано: 26.03.2013 | обновлено: 01.01.2018 | просмотров за всё время: 9478

Не редко возникает потребность перенаправить пользователя на страницу, с которой он пришел. Например, вы просматриваете список записей и уже дошли до 13-ой страницы, нажимаете редактировать запись номер 138. И скорее всего после сохранения изменений вы захотите вернуться именно на 13 страницу списка. Не так ли?!

Задача на статью

Предыстория описана в описании статьи, а значит сразу к делу. Чтобы вернуть пользователя “обратно”. Надо знать откуда он пришел. Самый просто способ это сделать – использовать

HttpContext.Request.UrlReferrer

А чтобы не писать его создадим кое-какой класс или несколько. Итак первым делом, создадим атрибут (класс) ReferrerHoldAttribute, который унаследуем от ActionFilterAttribute:

public class ReferrerHoldAttribute : ActionFilterAttribute {
  public override void OnActionExecuting(ActionExecutingContext filterContext) {
    var referrer = filterContext.RequestContext.HttpContext.Request.UrlReferrer;
    if (referrer != null) {
      filterContext.RouteData.Values.Add("referrer", referrer);
    }
    base.OnActionExecuting(filterContext);
  }
}

Думаю, пояснений не требуется. Далее просто будем его использовать. Для того чтобы “понять” откуда пришел пользователь, надо поставить атрибут над методом контролера. А затем просто его использовать:

[ReferrerHold]
public ActionResult Edit(int id) {
  var product = _smart.Products.GetById(id);
  if (product != null) {
    TempData["referrer"] = ControllerContext.RouteData.Values["referrer"];
    FillGeneralDictionaries();
    var model = product.MapTo<Product, ProductShowViewModel>();
    return View(model);
  }
  return RedirectToAction("http404", "error");
}

В первой строке поставили, далее в TempData[“referrer”] запихнули значение полученное из маршрута. А потом из POST-метода вызвали Redirect, чтобы перекинуть пользователя обратно:

[HttpPost]
public ActionResult Edit(ProductViewModel model) {
  if (ModelState.IsValid) {
    var product = _smart.Products.GetById(model.Id);
    Mapper.Map(model, product);
    product.UpdatedAt = DateTime.Now;
    product.UpdatedBy = User.Identity.Name;
    _smart.Products.Update(product);
    _smart.Logs.Log("Новый товар \"{0}\" успешно изменен", model.Name);
    _smart.Commit();
    if (TempData["referrer"] != null) {
      return Redirect(TempData["referrer"].ToString()); //"all", "catalog");
    }
    return RedirectToRoute("Catalog");//"all", "catalog");
  }
  FillGeneralDictionaries();
  return View(model);
}

Здесь тоже обойдемся без пояснений.

Развитие темы

Что можно предложить в продолжение темы. Дальше можно сделать свой собственный ActionResult, обозвав его, например, ReferrerResult, и унаследовав от базового класса реализовать обработку:

ControllerContext.RouteData.Values["referrer"];

Или также можно сделать базовый контролер, который всегда будет “знать кто, куда и откуда пришел”.

Заключение

Большое количество поступающих вопросов относительно озвученной тему породило данную статью, которая получилась короткой в силу своей тривиальности.

Комментарии к статье (2)

31.03.2013 0:31:54 Artyom Krivokrisenko

Не понятно, с какой целью вводится ReferrerHoldAttribute

31.03.2013 13:03:26 Calabonga

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