1

我有一個使用強類型視圖的ASP.NET MVC網站。在我的情況下,控制器動作看起來是這樣的:ASP.NET MVC,Querystring,路由和默認綁定,我該如何結合?

public ActionResult List(MyStrongType data) 

在提交頁面(視圖)的反應將產生類似如下的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)(默認綁定器)。

問題是:假設我要爲我的網頁上的列表添加頁面按鈕(更改頁面),列表將由過濾器,排序順序,每頁的頁面數量等設置控制(由查詢字符串控制)。首先,我需要在URL中包含所有當前查詢參數,然後我需要更新頁面參數而不篡改其他查詢參數。我怎樣才能從視圖/「HTML助手」生成這個URL?

我當然可以手動操作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 (Part 2): URL Routing,但是如何找到我的問題的答案?

回答

3

對我來說,聽起來像你的問題是,你想能夠輕鬆地從當前請求中持久查詢字符串值並將它們呈現在視圖中鏈接的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> 

這基本上是說「保留當前請求的查詢字符串,但更改頁面和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> 
+0

非常好的和有用的答案! – 2011-03-23 05:17:57

+0

>這看起來不一樣好,我已經建立了類似的解決方案,但不是那麼花哨;)但是有一個qustion,在我的情況下,我將查詢參數存儲在共享位置,以便知道頁面參數如何看起來像我將運行:QuerystringHandler.Instance.KnownQueryParameters [QuaryParameters.PageNr]在這種情況下,返回值將是「Page」。這可能與您的解決方案結合起來嗎? – Banshee 2011-03-24 10:38:52

+0

您可能需要發佈一些代碼,我不確定我是否理解您的問題。 – KOTJMF 2011-03-24 18:02:42

0

如果你想設置的查詢字符串在視圖中的一個鏈接:

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

如果你想有一個職位後,將其設置在瀏覽器URL回來,只是呼叫路由*在行動RouteToAction()並設置所需的參數鍵/值。

+0

但是如果url已經包含一些querystring參數,我需要包含在url中呢?我知道存在哪些參數,但我不知道哪個參數在URL中不受影響。是否有可能從助手設置? – Banshee 2011-03-14 20:00:24

2

我做了你需要的東西!

我爲此創建了一個HTML助手。該助手採用與普通助手相同的參數。但是,它保留了URL中的當前值。我將它作爲ActionLink helper作爲URL 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由合併的路徑值組成。此代碼還可讓您從網址中移除值。

例子:

您的網址是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
  • 如果使用動作public ActionResult List(MyStrongType data),你需要包括所有的頁面設置(頁索引,排序,...)作爲參數傳遞給「MyStrongType」和數據對象將包含所有信息來源的觀點。

  • 在視圖中,如果你需要生成一個URL,使用CallMeLaNN的方法: Html.ActionLink("LinkName", "Action", "Controller", new { param1 = Model.value1, param2 = Model.param2, ... });。您需要在此處手動設置所有參數,或者創建一個幫助程序來幫助您填充URL。

  • 你並不需要關心包含在地址當前參數。

  • 您可以路線: routes.MapRoute( 「custome」, 「{控制器}/{行動} /」, 新{控制器= 「家」,行動= 「索引」} ); 將所有參數生成爲查詢字符串。