Как передать запрос.Строка запроса в Url.Action?

#asp.net-mvc-3

#asp.net-mvc-3

Вопрос:

Я создаю URL, используя метод:

 Url.Action("action", "controller");
  

Мне также нравится передавать строку запроса для текущего запроса в этот url.
Что-то вроде следующего (но это не работает):

 Url.Action("action", "controller", Request.QueryString);
  

Преобразование строки запроса в routevalues возможно со следующим расширением:

     public static RouteValueDictionary ToRouteValues(this NameValueCollection queryString)
    {
        if (queryString.IsNull() || queryString.HasKeys() == false) return new RouteValueDictionary();

        var routeValues = new RouteValueDictionary();
        foreach (string key in queryString.AllKeys)
            routeValues.Add(key, queryString[key]);

        return routeValues;
    }
  

С методом расширения работает следующее:

 Url.Action("action", "controller", Request.QueryString.ToRouteValues());
  

Есть ли другой лучший способ?
Спасибо

Комментарии:

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

2. Спасибо, этот вопрос — действительно полезный ответ! Что querystring.IsNull() однако? Это пользовательское расширение? Потому что я нигде этого не вижу.

Ответ №1:

Если вы хотите легко иметь возможность добавлять дополнительные параметры значения маршрута к вашему Url.Action, попробуйте этот метод расширения (основанный на переводе строки), который принимает анонимный объект и возвращает RouteValueCollection:

 public static RouteValueDictionary ToRouteValues(this NameValueCollection col, Object obj)
{
    var values = new RouteValueDictionary(obj);
    if (col != null)
    {
        foreach (string key in col)
        {
            //values passed in object override those already in collection
            if (key != null amp;amp; !values.ContainsKey(key)) values[key] = col[key];
        }
    }
    return values;
}
  

Затем вы можете использовать это следующим образом:

 Url.Action("action", "controller", Request.QueryString.ToRouteValues(new{ id=0 }));
  

Комментарии:

1. Первую строку можно сократить до просто var values = new RouteValueDictionary(obj); . Поскольку RouteValueDictionary(object) принимает nulls (создает экземпляр пустого словаря), троичный не является необходимым.

2. Вы также можете сделать obj параметр необязательным вот так: ToRouteValues(this NameValueCollection col, Object obj = null) . Тогда, если вы хотите отправить только querystring в качестве данных маршрута, вы можете использовать ToRouteValues() без параметров.

Ответ №2:

Метод расширения кажется правильным, и это правильный путь.

Ответ №3:

Вот мое решение, основанное на ответе pwhe23. Я хотел сохранить параметры строки запроса через запросы POST (из-за Mvc.Grid) и использовать только одно действие для HTTP GET. Действия CRUD обрабатываются одной страницей и модальными диалогами внутри (для вставки / обновления / удаления).

Итак, вот мое расширение:

 public static class MvcExtensions
{
    public static RouteValueDictionary ToRouteValues(this NameValueCollection col, Object obj = null)
    {
        var values = obj != null ? new RouteValueDictionary(obj) : new RouteValueDictionary();

        if (col == null) return values;

        foreach (string key in col)
        {
            //values passed in object are already in collection
            if (!values.ContainsKey(key)) values[key] = col[key];
        }
        return values;
    }
}
  

Использование в контроллере (например, действие редактирования):

     [HttpPost]
    public ActionResult Edit(MyModel model)
    {
        // Some stuff
        return RedirectToAction("Index", Request.QueryString.ToRouteValues());
    }
  

Форма для редактирования, созданная в представлении (используется модальный диалог):

  @using (Html.BeginForm("Edit", "SomeControllerName", Request.QueryString.ToRouteValues(), FormMethod.Post))
    {
        // Some stuff... e.g. dialog content
    }