4

この質問のフォローアップとしてRouteValueDictionary、特定のルートを動的に変更するために、カスタム ルート制約を実装しようとしています。

私はそこまでの道のりの 95% です。URL で指定されたアクションに一致する指定されたパラメーター パターンに基づいて、任意のルートを一致させることができます。このプロセスの最後のステップは、RouteValueDictionary を上書きして、コントローラー アクションの適切なパラメーターとしてキーの名前を変更することです。

これが私のコードの関連するスニペットです(クラス全体はほぼ300行なので、すべてを追加したくはありませんが、必要に応じて追加できます):

public class CustomRouteConstraint : IRouteConstraint
{
    public bool Match(HttpContextBase httpContext, Route route, string paramName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        if (routeDirection.Equals(RouteDirection.UrlGeneration)) {
            return false;
        }

        //this will grab all of the "actual" parameters out of the RVD, excluding action and controller 
        Dictionary<string, object> unMappedList = values.Where(x => x.Key.Contains("param")).OrderBy(xi => xi.Key).ToDictionary(
            kvp => kvp.Key, kvp => kvp.Value);

        string controller = values["controller"] as string;
        string action = values["action"] as string;

        //this method tries to find the controller using reflection
        Type cont = TryFindController(controller);

        if (cont != null) {
            MethodInfo actionMethod = cont.GetMethod(action);

            if (actionMethod != null) {
                ParameterInfo[] methodParameters = actionMethod.GetParameters();

                //this method validates that the parameters of the action that was found match the expected parameters passed in the custom constraint; it also performs type conversion
                if (validateParameters(methodParameters, unMappedList)) {
                    for (int i = 0; i < methodParameters.Length; i++) {
                        values.First(x => x.Key == unMappedList.ElementAt(i).Key).Key = methodParameters.ElementAt(i).Name; 
                        //above doesn't work, but even if it did it wouldn't do the right thing

                        return true;
                    }
                }
            }
        }

        return false;
    }
}

カスタム制約の使用方法は次のとおりです。

routes.MapRoute(
    name: "Default2",
    url: "{controller}/{action}/{param1}-{param2}",
    defaults: new { controller = "Admin", action = "Index" },
    constraints: new { lang = new CustomRouteConstraint(new RoutePatternCollection( new List<ParamType> { ParamType.INT, ParamType.INT })) }
);

(私がコンストラクターに渡しているのは、基本的に「検索するパラメーター パターンは 2 つの整数です」と言っています。そのため、Matchメソッドが呼び出されると、url で指定されたアクションに 2 つの整数パラメーターが 2 つある場合は true が返されます。実際のパラメーター名。)

では、このリクエストの RouteValueDictionary を上書きする方法はありますか? または、私が行方不明になっているこれを行うことができる他の方法はありますか?

4

2 に答える 2

4

私が正しく理解していれば、質問は何ですか:

では、このリクエストの RouteValueDictionary を上書きする方法はありますか? または、私が行方不明になっているこれを行うことができる他の方法はありますか?

私はあなたのソリューションを採用し、これらの行を変更してパラメーター名を置き換えました。

for (int i = 0; i < methodParameters.Length; i++)
{
    // I. instead of this

    //values.First(x => x.Key == unMappedList.ElementAt(i).Key)
    //    .Key = methodParameters.ElementAt(i).Name; 
    //above doesn't work, but even if it did it wouldn't do the right thing

    // II. do this (not so elegant but working;)
    var key = unMappedList.ElementAt(i).Key;
    var value = values[key];
    values.Remove(key);
    values.Add(methodParameters.ElementAt(i).Name, value);

    // III. THIS is essential! if statement must be moved after the for loop
    //return true;
}
return true; // here we can return true

注:私はあなたのアプローチが好きです。場合によっては、ルーティングを拡張/調整してからコードに進み、「誤ったパラメーター名を修正する」ことがはるかに重要な場合があります。そしてもちろん、それらは間違っていない可能性が高いです。

そして、ここに懸念の分離の力があります。

  • URL アドレスは 1 か所です。
  • コントローラー、アクション、およびパラメーターの名前は他にもあります。
  • そして強力なカスタマイズによるルーティング...

...それを処理する唯一の正しい場所として。これが関心の分離です。Url を提供するためにアクション名を微調整していません...

于 2012-11-17T06:01:28.367 に答える
1

正規表現を使用して、パラメーターを正の整数に簡単に制限できます。

private const string IdRouteConstraint = @"^\d+$";

routes.MapRoute(
   name: "Default2",
   url: "{controller}/{action}/{param1}-{param2}",
   defaults: new { controller = "Admin", action = "Index" },
   constraints: new { param1 = IdRouteConstraint, param2 = IdRouteConstraint});

以前の質問への回答で述べたように、コントローラー アクションのパラメーター名について心配する必要はありません。それらの過度に意味のある名前を付けると、結び目ができます。

于 2012-11-16T21:57:34.720 に答える