1

I have an ASP.NET MVC site that uses strongly typed views. In my case, a controller action could look like this:

public ActionResult List(MyStrongType data)

When submitting the page (view) the response will generate a URL that looks something like this (yes, I know routing could generate a nicer 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

If I submit the page again, I can see that the data object in the action is set properly (according to the URL)(default binder).

The problem is: Say that I am to add page buttons (to change the page) for a list on my sitepage, the list will be controlled by settings like filter, sortorder, amount of pages per page and so on (controlled by the querystring). First, I need to include all current query parameters in the URL, and then I need to update the page parameter without tampering with the other query parameters. How can I genereate this URL from the view/"HTML helper"?

I could of course manipulate the URL string manually, but this will involve a lot of work and it will be hard to keep up to date if a route is changed, there must be a easier way? Like some kind of querystring collection that can be altered on service side (like ASP.NET Request.QueryString)?

I would hope to not involve the route, but I post the one I got so far anyway:

    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

Edit 1: It's possible to set the query parameters like this (in view):

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

But this will only generate a URL like this (with the default route):

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

The rest of the parameters will be missing as you can see.

I could of course add every known parameter in this URL action, but if any query parameter is added or changed there will be a lot of work to keep everything up to date.

I have read the article ASP.NET MVC Framework (Part 2): URL Routing, but how do I find an answer to my problem?

4

4 に答える 4

3

あなたが抱えている問題は、現在のリクエストからクエリ文字列の値を簡単に保持し、それらをビュー内のリンクの URL にレンダリングできるようにしたいということのように思えます。1 つの解決策は、いくつかの変更を加えた既存のクエリ文字列を返す 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>

これは基本的に、「現在のリクエストのクエリ文字列を保持しますが、page と parameter2 の値を変更するか、存在しない場合は作成する」ということです。現在のリクエストに「ページ」クエリ文字列パラメーターがある場合、このメソッドは現在のリクエストの値をビューから明示的に渡した値で上書きすることに注意してください。この場合、クエリ文字列が次の場合:

?parameter1=abc&page=1

それは次のようになります。

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

編集: 上記の実装は、おそらく、説明したクエリ文字列パラメーター名の辞書検索では機能しません。オブジェクトの代わりに辞書を使用する実装を次に示します。

    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>
于 2011-03-22T22:46:31.723 に答える
2

私はあなたが必要とすることだけをしました!

このための HTML ヘルパーを作成しました。ヘルパーは、通常のヘルパーと同じパラメーターを取ります。それでも、URL からの現在の値を保持します。私は両方のためにそれを作りましURL helperActionLink 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、辞書に配置します。次に、手動で指定した追加のルート値を取得し、それらも a に配置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=""}) %>

<a> 要素で 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}));
 }

必要なものはほぼ網羅されていると思います。

于 2011-03-24T12:08:15.660 に答える
0

ビューのリンクにクエリ文字列を設定する場合:

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

ポストバック後にブラウザのURLに設定する場合は、次のようなアクションRouteToAction()で Route* を呼び出し、必要なパラメータ キー/値を設定します。

于 2011-03-14T19:34:10.433 に答える
0
  • アクションを使用する場合public ActionResult List(MyStrongType data)、すべてのページ設定 (ページ インデックス、順序付けなど) を 'MyStrongType' のパラメーターとして含める必要があり、データ オブジェクトにはビューのすべての情報が含まれます。

  • ビューでURLを生成する必要がある場合は、CallMeLaNN: のアプローチを使用し ますHtml.ActionLink("LinkName", "Action", "Controller", new { param1 = Model.value1, param2 = Model.param2, ... });。ここですべてのパラメーターを手動で設定するか、URL の入力を支援するヘルパーを作成する必要があります。

  • アドレスに含まれる現在のパラメーターを気にする必要はありません。

  • 次のようにルーティングできます: routes.MapRoute( "custome", "{controller}/{action}/", new { controller = "Home", action = "Index"} ); すべてのパラメーターをクエリ文字列として生成します。

于 2011-03-25T12:20:30.567 に答える