Как я могу восстановить URL / маршрут в ASP.NET MVC из сохраненных данных?
-
05-07-2019 - |
Вопрос
Мое незнание фреймворка ASP.NET MVC и его структуры привело меня сюда, и я ценю терпение, которое потребуется любому, чтобы прочитать и рассмотреть мой вопрос!
Итак, вот сценарий:У меня есть приложение, в котором есть множество страниц с сетками, которые отображают данные на основе поиска, детализации по другим данным, отчеты на основе контекстно-зависимых данных (т.Е.они находятся на странице сведений о Foo, затем нажмите на ссылку, которая показывает таблицу данных, связанных с Foo) и т.д.
С любой из этих страниц, которые есть по всему приложению, пользователь может сохранить "отчет" или таблицу, присвоив ему имя и описание.Это на самом деле не столько сохраняет данные, отображаемые в таблице, сколько сохраняет параметры, которые определяют, как выглядит сетка, сохраняет параметры, которые использовались для получить данные и сохраняет параметры, которые определяют, "где" в приложении они находятся (действие, контроллер, маршрут) - в основном набор метаданных об отчете / сетке и о том, как ее построить.
Все эти сохраненные отчеты доступны в виде единого списка с отображением названия и описания на определенной странице приложения, причем каждый из них ссылается на общий URL-адрес, например "/ Reports /Saved /248" (где 248 - пример идентификатора отчета).
Вот та часть, в которой мне нужна помощь:
Когда я перейду к действию по URL-адресу "/ Reports / Saved / 248" и извлеку метаданные из базы данных для этого конкретного отчета, как я могу перенаправить эти данные и запрос на то же действие, контроллер и маршрут, которые использовались для отображения представления, из которого отчет был первоначально сохранен?По сути, я хочу, чтобы пользователь просматривал отчет в том же виде, с тем же URL-адресом, с которого он был сохранен.Если возможно, было бы неплохо, чтобы я мог в принципе "вызывать" то же самое действие, как если бы я выполнял вызов метода.
Обновить:К сожалению, наши страницы отчетов (т.е.страницы, на которых отображаются эти сетки), НЕ используют RESTful URL-адреса - например, у нас есть то, что мы называем страницей расширенного поиска, которая принимает довольно большое количество потенциальных параметров (почти 30), поступающих из формы, содержащей списки выбора, текстовые поля и т.д.Когда пользователь отправляет эту страницу, мы выполняем публикацию для действия, которое принимает сложный тип, который создает для нас model binder - это то же самое действие, которое я хочу вызвать, когда пользователь выбирает сохраненный Расширенный поиск из базы данных.Этот пример олицетворяет мою проблему.
Спасибо
Решение
Я думаю, что вы захотите использовать RedirectToAction с подписью, которая принимает RouteValueDictionary.Метод, на который вы перенаправляете, должен иметь возможность извлекать значения из ValueProvider на контроллере.Это может выглядеть примерно так:
public ActionResult Saved( int id )
{
var reportParams = db.Reports.SingleOrDefault( r => r.ID == id );
if (reportParams == null)
...handle error...
var routeValues = ParamsToRouteValueDictionary( reportParams );
return RedirectToAction( reportParams.Action, reportParams.Controller, routeValues );
}
private RouteValueDictionary ParamsToRouteValueDictionary( object parameters )
{
var values = new RouteValueDictionary();
var properties = parameters.GetType().GetProperties()
.Where( p => p.Name != "Action" && p.Name != "Controller" );
foreach (var prop in properties)
{
values.Add( prop.Name, prop.GetValue(parameters,null) );
}
return values;
}
Редактировать
Использование модели фильтра в качестве параметра для вашего метода на самом деле может упростить задачу.Вам просто нужно ПОЛУЧИТЬ и ОПУБЛИКОВАТЬ версии вашего действия.
[ActionName("People")]
[AcceptVerbs( HttpVerbs.Get )]
public ActionResult PeopleDisplay( SearchModel filter )
{
return People( filter );
}
[AcceptVerbs( HttpVerbs.Post)]
[ValidateAntiForgeryToken]
public ActionResult People( SearchModel filter )
{
....
}
Затем вы сохранили бы в своей базе данных для отчета параметры фильтра (по имени), Действие ("Люди") и контроллер.Результат перенаправления будет использовать GET и будет направлен методу PeopleDisplay, который, в свою очередь, просто вызывает метод People с правильным параметром.Публикация из формы напрямую вызывает метод People.Использование двух методов позволяет использовать механизм предотвращения CSRF.Возможно, вы сможете использовать флаг в TempData, чтобы гарантировать, что действие GET вызывается только через механизм перенаправления, если вы хотите ограничить доступ к нему.
ОКОНЧАТЕЛЬНАЯ ПРАВКА
Другой альтернативой было бы просто сохранить также используемое представление и вместо выполнения перенаправления просто отобразить соответствующее представление.Одна из вещей, которую вы захотите учесть, заключается в том, что при перенаправлении в конечном итоге будет получен URL, содержащий все параметры, тогда как при рендеринге представления URL останется в покое и просто отобразится тот же вид, что и URL, используемый при создании отчета.
Другие советы
Вы можете использовать метод RedirectToAction для выдачи перенаправления 301 на определенный метод действия на любом контроллере вместе со значениями маршрута:
ReportMeta meta = _reportDataAccess.Get(id);
return RedirectToAction(meta.Action, meta.Controller, meta.RouteData);
где эти значения что-то вроде:
meta.Action = "Bar";
meta.Controller = "Foo";
meta.RouteData = new {
// possibly settings for the grid
start = DateTime.Min,
end = DateTime.Now,
sort = "Date"
// you get the idea
};
Конечно, непосредственная проблема, с которой я могу столкнуться, это то, что происходит, когда ваш контроллер / методы действий со временем меняются, данные отчета будут недействительными. Но тогда вы, наверное, уже подумали об этом.