2008-12-15 39 views
1

有誰知道我怎麼會去這樣做是這樣的:強類型ActionLink的時候,動作方法並不需要一個原始類型

Html.ActionLink(C => c.SomeAction(新MessageObject {ID = 1}))

這應該與輸出的URL的鏈接 「/控制器/ SomeAction/1」,在沿線的一個ActionMethod指點:我已經寫了類似的

public Controller : Controller 
{ 
    public ActionResult SomeMethod(MessageObject message) 
    { 
     // do something with the message 
     return View(); 
    } 
} 

生成表單,但不需要在URL的末尾包含Id值。基本上我想在我的路線中進行某種反向查詢,但是我無法找到任何關於如何執行此操作的doco。我有一個能夠從GET和POST參數構建MessageObject的ModelBinder安裝程序,但我不確定如何反轉該過程。

謝謝, 馬特

回答

0

我不知道正是你正在嘗試做的,因爲你的榜樣URL不匹配您的方法的簽名要求。通常,如果您使用需要複雜對象的方法,則可以傳遞這些值以在查詢字符串中構造該對象或作爲表單參數,並且ModelBinder會根據參數中提供的數據構造對象。如果你只想傳遞id,那麼這個方法通常不會接受任何參數,你從RouteData中提取id,然後在持久存儲器(或緩存)中查找對象。如果你想要做的是後者,你的方法應該是這樣的:

public ActionResult SomeMethod() 
{ 
    int messageObjectID; 
    if (RouteData.Values.TryGetValue("id",out messageObjectID)) 
    { 
     ... get the object with the correct id and process it... 
    } 
    else 
    { 
     ... error processing because the id was not available... 
    } 
    return View(); 
} 
0

我不知道你是什麼 試圖做的,因爲這需要對 你的例子網址 不匹配你方法的簽名。通常,如果 使用需要一個複雜的 對象的方法,你值傳遞給 構建體在查詢 字符串或形式參數對象和ModelBinder的從 構造對象中的參數所提供的數據的 。

大聲笑,這正是我想要做的:)該網址工作正常,並映射到該方法,模型活頁夾能夠將該URL變成一個映射到該行動,並正常工作的路線。 (該路由將「1」映射到名爲Id的RouteValue,模型綁定器隨後將其分配給消息對象的Id字段)。

我想要做的是走另一條路,採取方法調用,並將其轉化爲路線。

1

最後,我最終將下面的代碼包裝在HtmlHelper擴展方法中。這將允許我使用類似於 Html.ActionLink(c => c.SomeAction(new MessageObject {Id = 1}))

並且具有創建爲RouteValues的MessageObject的所有屬性。

public static RouteValueDictionary GetRouteValuesFromExpression<TController>(Expression<Action<TController>> action) 
      where TController : Controller 
     { 
      Guard.Against<ArgumentNullException>(action == null, @"Action passed to GetRouteValuesFromExpression cannot be null."); 
      MethodCallExpression methodCall = action.Body as MethodCallExpression; 
      Guard.Against<InvalidOperationException>(methodCall == null, @"Action passed to GetRouteValuesFromExpression must be method call"); 
      string controllerName = typeof(TController).Name; 
      Guard.Against<InvalidOperationException>(!controllerName.EndsWith("Controller"), @"Controller passed to GetRouteValuesFromExpression is incorrect"); 

      RouteValueDictionary rvd = new RouteValueDictionary(); 
      rvd.Add("Controller", controllerName.Substring(0, controllerName.Length - "Controller".Length)); 
      rvd.Add("Action", methodCall.Method.Name); 

      AddParameterValuesFromExpressionToDictionary(rvd, methodCall); 
      return rvd; 
     } 

     /// <summary> 
     /// Adds a route value for each parameter in the passed in expression. If the parameter is primitive it just uses its name and value 
     /// if not, it creates a route value for each property on the object with the property's name and value. 
     /// </summary> 
     /// <param name="routeValues"></param> 
     /// <param name="methodCall"></param> 
     private static void AddParameterValuesFromExpressionToDictionary(RouteValueDictionary routeValues, MethodCallExpression methodCall) 
     { 
      ParameterInfo[] parameters = methodCall.Method.GetParameters(); 
      methodCall.Arguments.Each(argument => 
      { 
       int index = methodCall.Arguments.IndexOf(argument); 

       ConstantExpression constExpression = argument as ConstantExpression; 
       if (constExpression != null) 
       { 
        object value = constExpression.Value; 
        routeValues.Add(parameters[index].Name, value); 
       } 
       else 
       { 
        object actualArgument = argument; 
        MemberInitExpression expression = argument as MemberInitExpression; 
        if (expression != null) 
        { 
         actualArgument = Expression.Lambda(argument).Compile().DynamicInvoke(); 
        } 

        // create a route value for each property on the object 
        foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(actualArgument)) 
        { 
         object obj2 = descriptor.GetValue(actualArgument); 
         routeValues.Add(descriptor.Name, obj2); 
        } 
       } 
      }); 
     } 
0

如果您不介意在要爲其生成URL的控制器中的每個操作旁邊添加方法,則可按以下步驟操作。與lambda表達式方法相比,這有一些缺點,但也有一些提升。

實現: -

添加到您的控制器您想要強類型的URL生成每個動作方法......

// This const is only needed if the route isn't already mapped 
// by some more general purpose route (e.g. {controller}/{action}/{message} 
public const string SomeMethodUrl = "/Home/SomeMethod/{message}"; 

// This method generates route values that match the SomeMethod method signature 
// You can add default values here too 
public static object SomeMethodRouteValues(MessageObject messageObject) 
{ 
    return new { controller = "Home", action = "SomeMethod", 
       message = messageObject }; 
} 

您可以在路由映射代碼中使用這些.. 。

Routes.MapRoute ("SomeMethod", 
        HomeController.SomeMethodUrl, 
        HomeController.SomeMethodRouteValues(null)); 

而且你可以在任何地方使用它們,你需要生成一個鏈接到行動: - 如

<%=Url.RouteUrl(HomeController.SomeMethodValues(new MessageObject())) %> 

如果你做這種方式...

1)你在你的代碼只是一個地方的參數的任何行動被定義

2)只有一個方式這些參數轉換爲路由,因爲Html.RouteLink和Url.RouteUrl都可以將HomeController.SomeMethodRouteValues(...)作爲參數。

3)很容易設置任何可選路由值的默認值。

4)很容易重構你的代碼而不會破壞任何網址。假設你需要爲SomeMethod添加一個參數。你所要做的就是改變SomeMethodUrl和SomeMethodRouteValues()以匹配新的參數列表,然後在代碼或視圖中修改所有的斷開引用。試着用新的{action =「SomeMethod」,...}來分散你的代碼。

5)您將獲得Intellisense支持,以便您可以查看需要哪些參數來構建任何操作的鏈接或網址。至於「強類型」,這種方法似乎比使用lambda表達式更好,因爲沒有編譯時或設計時錯誤檢查鏈接生成參數是否有效。

缺點是,你仍然需要保持這些方法與實際操作方法同步(但它們可以在代碼中彼此相鄰,以便於查看)。純粹主義者無疑會反對這種方法,但實際上,它發現並修復了一些錯誤,否則這些錯誤需要測試才能找到,並且正在幫助替換我們以前在WebForms項目中使用的強類型Page方法。

相關問題