ASP.NET MVC, Querystring, маршруты и связыватель по умолчанию, как мне это объединить? - PullRequest
1 голос
/ 14 марта 2011

У меня есть сайт ASP.NET MVC, который использует строго типизированные представления.В моем случае действие контроллера может выглядеть следующим образом:

public ActionResult List(MyStrongType data)

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

http://localhost/Ad/List?F.ShowF=0&ALS.CP=30&ALS.L=0&ALS.OB=0&ALS.ST=0&S=&LS.L1=&LS.L2=&CS.C1=32&CS.C2=34&CS.C3=&ALS.ST=0

Если я снова отправлю страницу, я вижу, что объект данных в действии настроен правильно (в соответствии с URL) (связыватель по умолчанию).

Проблемаis: скажем, я должен добавить кнопки страницы (чтобы изменить страницу) для списка на странице моего сайта, список будет управляться такими настройками, как фильтр, сортировщик, количество страниц на странице и т. д. (управляется строкой запроса).Сначала мне нужно включить все текущие параметры запроса в URL, а затем мне нужно обновить параметр страницы, не затрагивая другие параметры запроса.Как я могу сгенерировать этот URL из представления / «помощника HTML»?

Конечно, я мог бы вручную манипулировать строкой URL, но это потребует много работы, и будет сложно поддерживать актуальность, еслимаршрут изменился, должен быть более легкий путь?Например, какая-то коллекция строк запросов, которую можно изменить на стороне службы (например, ASP.NET Request.QueryString)?

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

    routes.MapRoute(
        "Default",
        "{controller}/{action}/{id}",
        new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );

    routes.MapRoute(
        "TreeEditing",
        "{controller}/{action}/{name}/{id}",
        new { controller = "MyCategory", action = "Add", name = string.Empty, id = -1 }
    );

BestRegards

Редактировать 1: можно задать параметры запроса следующим образом (в поле зрения):

<%= url.Action(new {controller="search", action="result", query="Beverages", Page=2})%>

Но это будетгенерировать только URL-адрес, подобный этому (с маршрутом по умолчанию):

/search/result?query=Beverages&page=2

Остальные параметры будут отсутствовать, как вы можете видеть.

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

Я прочитал статью ASP.NET MVC Framework (часть 2): маршрутизация URL , но как мне найти ответ на мою проблему?

Ответы [ 4 ]

3 голосов
/ 23 марта 2011

Мне кажется, что проблема в том, что вы хотите иметь возможность легко сохранять значения строки запроса из текущего запроса и отображать их в URL-адресах ссылок в вашем представлении. Одним из решений будет создание метода HtmlHelper, который возвращает существующую строку запроса с некоторыми изменениями. Я создал метод расширения для класса HtmlHelper, который принимает объект, объединяет имена и значения его свойств со строкой запроса из текущего запроса и возвращает измененную строку запроса. Это выглядит так:

public static class StackOverflowExtensions
{
    public static string UpdateCurrentQueryString(this HtmlHelper helper, object parameters)
    {
        var newQueryStringNameValueCollection = new NameValueCollection(HttpContext.Current.Request.QueryString);
        foreach (var propertyInfo in parameters.GetType().GetProperties(BindingFlags.Public))
        {
            newQueryStringNameValueCollection[propertyInfo.Name] = propertyInfo.GetValue(parameters, null).ToString();
        }

        return ToQueryString(newQueryStringNameValueCollection);
    }

    private static string ToQueryString(NameValueCollection nvc)
    {
        return "?" + string.Join("&", Array.ConvertAll(nvc.AllKeys, key => string.Format("{0}={1}", HttpUtility.UrlEncode(key), HttpUtility.UrlEncode(nvc[key]))));
    }
}

Он будет циклически перебирать значения строки запроса из текущего запроса и объединять свойства, определенные для объекта, который вы передали. Таким образом, код вашего представления может выглядеть следующим образом:

<a href='/SomeController/SomeAction<%=Html.GetCurrentQueryStringWithReplacements(new {page = "2", parameter2 = "someValue"})%>'>Some Link</a>

По сути, это означает "сохранить строку запроса в текущем запросе, но изменить значения страницы и параметра2 или создать их, если они не существуют". Обратите внимание, что если ваш текущий запрос имеет параметр строки запроса «page», этот метод перезапишет значение из текущего запроса на тот, который вы явно передали из представления. В этом случае, если ваша строка запроса была:

?parameter1=abc&page=1

Это станет:

?parameter1=abc&page=2&parameter2=someValue

EDIT: Вышеприведенная реализация, вероятно, не будет работать с поиском в словаре имен параметров строки запроса, которые вы описали. Вот реализация, которая использует словарь вместо объекта:

    public static string UpdateCurrentQueryString(this HtmlHelper helper, Dictionary<string, string> newParameters)
    {
        var newQueryStringNameValueCollection = new NameValueCollection(HttpContext.Current.Request.QueryString);
        foreach (var parameter in newParameters)
        {
            newQueryStringNameValueCollection[parameter.Key] = parameter.Value;
        }

        return ToQueryString(newQueryStringNameValueCollection);
    }

Ваше представление вызвало бы функцию, выполнив встроенную инициализацию словаря и передав ее вспомогательной функции следующим образом:

<a href='/SomeController/SomeAction<%=Html.GetCurrentQueryStringWithReplacements(new Dictionary<string,string>() {
{ QuerystringHandler.Instance.KnownQueryParameters[QuaryParameters.PageNr], "2" },
{ QuerystringHandler.Instance.KnownQueryParameters[QuaryParameters.AnotherParam], "1234" }})%>'>Some Link</a>
2 голосов
/ 24 марта 2011

Я сделал ТОЛЬКО то, что тебе нужно!

Я создал помощник HTML для этого. Помощник принимает те же параметры, что и обычный помощник. Тем не менее, он сохраняет текущие значения из URL. Я сделал это для URL helper как ActionLink helper.

Это заменяет: Url.Action()

<a href='<%= Html.UrlwParams("TeamStart","Inschrijvingen", new {modID=item.Mod_ID}) %>'  title="Selecteer">
    <img src="<%= Url.Content("~/img/arrow_right.png") %>" alt="Selecteer" width="16" /></a>

и это заменяет Html.ActionLink()

<%: Html.ActionLinkwParams("Tekst of url", "Action", new {test="yes"}) %>

Вот помощник:

using System;
using System.Web.Mvc;
using System.Web.Routing;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Web.Mvc.Html;

namespace MVC2_NASTEST.Helpers {
    public static class ActionLinkwParamsExtensions {
        public static MvcHtmlString ActionLinkwParams(this HtmlHelper helper, string linktext, string action, string controller, object extraRVs, object htmlAttributes) {

            NameValueCollection c = helper.ViewContext.RequestContext.HttpContext.Request.QueryString;

            RouteValueDictionary r = new RouteValueDictionary();
            foreach (string s in c.AllKeys) {
                r.Add(s, c[s]);
            }

            RouteValueDictionary htmlAtts = new RouteValueDictionary(htmlAttributes);

            RouteValueDictionary extra = new RouteValueDictionary(extraRVs);

            RouteValueDictionary m = RouteValues.MergeRouteValues(r, extra);

            //return System.Web.Mvc.Html.LinkExtensions.ActionLink(helper, linktext, action, controller, m, htmlAtts);
            return helper.ActionLink(linktext, action, controller, m, htmlAtts);
        }

        public static MvcHtmlString ActionLinkwParams(this HtmlHelper helper, string linktext, string action) {
            return ActionLinkwParams(helper, linktext, action, null, null, null);
        }

        public static MvcHtmlString ActionLinkwParams(this HtmlHelper helper, string linktext, string action, string controller) {
            return ActionLinkwParams(helper, linktext, action, controller, null, null);
        }

        public static MvcHtmlString ActionLinkwParams(this HtmlHelper helper, string linktext, string action, object extraRVs) {
            return ActionLinkwParams(helper, linktext, action, null, extraRVs, null);
        }

        public static MvcHtmlString ActionLinkwParams(this HtmlHelper helper, string linktext, string action, string controller, object extraRVs) {
            return ActionLinkwParams(helper, linktext, action, controller, extraRVs, null);
        }

        public static MvcHtmlString ActionLinkwParams(this HtmlHelper helper, string linktext, string action, object extraRVs, object htmlAttributes) {
            return ActionLinkwParams(helper, linktext, action, null, extraRVs, htmlAttributes);
        }
    }

    public static class UrlwParamsExtensions {
        public static string UrlwParams(this HtmlHelper helper, string action, string controller, object extraRVs) {
            NameValueCollection c = helper.ViewContext.RequestContext.HttpContext.Request.QueryString;

            RouteValueDictionary r = RouteValues.optionalParamters(c);

            RouteValueDictionary extra = new RouteValueDictionary(extraRVs);

            RouteValueDictionary m = RouteValues.MergeRouteValues(r, extra);

            string s = UrlHelper.GenerateUrl("", action, controller, m, helper.RouteCollection, helper.ViewContext.RequestContext, false);
            return s;
        }

        public static string UrlwParams(this HtmlHelper helper, string action) {
            return UrlwParams(helper, action, null, null);
        }

        public static string UrlwParams(this HtmlHelper helper, string action, string controller) {
            return UrlwParams(helper, action, controller, null);
        }

        public static string UrlwParams(this HtmlHelper helper, string action, object extraRVs) {
            return UrlwParams(helper, action, null, extraRVs);
        }
    }
}

Как это работает?

Вызовы такие же, как для Html.ActionLink(), поэтому вы можете просто их заменить.

Метод выполняет следующие действия:

Он берет все необязательные параметры из текущего URL и помещает их в RouteValueDictionary. Он также помещает htmlattributes в словарь. Затем он берет дополнительные значения маршрута, которые вы указали вручную, и помещает их в RouteValueDictionary.

Тогда ключ должен объединить те из URL и те, которые указаны вручную.

Это происходит в классе RouteValues.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Routing;
using System.Collections.Specialized;
using System.Web.Mvc;

namespace MVC2_NASTEST {
    public static class RouteValues {

        public static RouteValueDictionary optionalParamters() {
            return optionalParamters(HttpContext.Current.Request.QueryString);
        }

        public static RouteValueDictionary optionalParamters(NameValueCollection c) {
            RouteValueDictionary r = new RouteValueDictionary();
            foreach (string s in c.AllKeys) {
                r.Add(s, c[s]);
            }
            return r;
        }

        public static RouteValueDictionary MergeRouteValues(this RouteValueDictionary original, RouteValueDictionary newVals) {
            // Create a new dictionary containing implicit and auto-generated values
            RouteValueDictionary merged = new RouteValueDictionary(original);

            foreach (var f in newVals) {
                if (merged.ContainsKey(f.Key)) {
                    merged[f.Key] = f.Value;
                } else {
                    merged.Add(f.Key, f.Value);
                }
            }
            return merged;
        }

        public static RouteValueDictionary MergeRouteValues(this RouteValueDictionary original, object newVals) {
            return MergeRouteValues(original, new RouteValueDictionary(newVals));
        }
    }
}

Это все довольно просто. В конце концов, actionlink создается с объединенными значениями маршрутов. Этот код также позволяет удалять значения из URL.

Примеры:

Ваш URL-адрес localhost.com/controller/action?id=10&foo=bar. Если на этой странице вы разместите этот код

 <%: Html.ActionLinkwParams("Tekst of url", "Action", new {test="yes"}) %>

URL, возвращаемый в этом элементе, будет localhost.com/controller/action?id=10&foo=bar&test=yes.

Если вы хотите удалить элемент, вы просто устанавливаете элемент в виде пустой строки. Например,

 <%: Html.ActionLinkwParams("Tekst of url", "Action", new {test="yes", foo=""}) %>

вернет URL в элементе : localhost.com/controller/action?id=10&test=yes

Полагаю, это все, что вам нужно?

Если у вас есть дополнительные вопросы, просто спросите.

Дополнительно:

Иногда вы захотите также сохранить свои значения внутри своего действия, когда будете перенаправлять на другое действие. С моим классом RouteValues ​​это можно сделать очень легко:

 public ActionResult Action(string something, int? somethingelse) {
                    return RedirectToAction("index", routeValues.optionalParamters(Request.QueryString));
 }

Если вы все еще хотите добавить некоторые дополнительные параметры, нет проблем!

 public ActionResult Action(string something, int? somethingelse) {
                    return RedirectToAction("index", routeValues.optionalParamters(Request.QueryString).MergeRouteValues(new{somethingelse=somethingelse}));
 }

Я думаю, что это охватывает почти все, что вам нужно.

0 голосов
/ 25 марта 2011
  • Если вы используете действие public ActionResult List(MyStrongType data), вам необходимо включить все параметры страницы (индекс страницы, упорядочение, ...) в качестве параметров для MyStrongType, и объект данных будет содержать всю информацию для представления. .

  • В представлении, если вам нужно сгенерировать URL , используя подход CallMeLaNN: Html.ActionLink("LinkName", "Action", "Controller", new { param1 = Model.value1, param2 = Model.param2, ... });. Вам нужно вручную установить все параметры здесь или создать помощника, который поможет вам заполнить URL.

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

  • Вы можете проложить маршрут: routes.MapRoute ( "Custome", "{Контроллер} / {действие} /", new {controller = "Home", action = "Index"} ); для генерации всех параметров в виде строки запроса.

0 голосов
/ 14 марта 2011

Если вы хотите установить строку запроса в ссылке вида:

Html.ActionLink("LinkName", "Action", "Controller", new { param1 = value1, param2 = value2 }, ...)

Если вы хотите установить его в браузере URL после обратной записи, просто вызовите Route * в action like RouteToAction() и установите нужный ключ / значение параметра .

...