web-dev-qa-db-ja.com

ASP.NET MVCでクエリ文字列を使用してURLをルーティングするにはどうすればよいですか?

次の形式で別のシステムからURLを取得するために、MVCでカスタムルートを設定しようとしています。

../ABC/ABC01?Key=123&Group=456

2番目のABCの後の01は、これが変更されるステップ番号であり、キーとグループのパラメーターが変更されます。パラメータとしてステップ番号キーとグループを使用して、これをコントローラーの1つのアクションにルーティングする必要があります。私は次のコードを試しましたが、例外がスローされます:

コード:

routes.MapRoute(
    "OpenCase", 
    "ABC/ABC{stepNo}?Key={key}&Group={group}",
    new {controller = "ABC1", action = "OpenCase"}
);

例外:

`The route URL cannot start with a '/' or '~' character and it cannot contain a '?' character.`
33
Jason Underhill

ルートにクエリ文字列を含めることはできません。次のようなルートで試してください:

routes.MapRoute("OpenCase", "ABC/ABC{stepNo}",
   new { controller = "ABC1", action = "OpenCase" });

次に、コントローラーで次のようなメソッドを追加します。

public class ABC1 : Controller
{
    public ActionResult OpenCase(string stepno, string key, string group)
    {
        // do stuff here
        return View();
    }        
}

ASP.NET MVCは、クエリ文字列パラメーターをコントローラーのメソッドのパラメーターに自動的にマップします。

39
Hector Correa

ルートを定義するとき、ルートの先頭で/を使用することはできません。

routes.MapRoute("OpenCase",
    "/ABC/{controller}/{key}/{group}", <-- Bad; see / at beginning
    new { controller = "", action = "OpenCase" },
    new { key = @"\d+", group = @"\d+" }
    );

routes.MapRoute("OpenCase",
    "ABC/{controller}/{key}/{group}", <-- Good; No /  at beginning
    new { controller = "", action = "OpenCase" },
    new { key = @"\d+", group = @"\d+" }
    );

これを試して:

routes.MapRoute("OpenCase",
    "ABC/{controller}/{key}/{group}",
    new { controller = "", action = "OpenCase" },
    new { key = @"\d+", group = @"\d+" }
    );

次に、アクションは次のようになります。

public ActionResult OpenCase(int key, int group)
{
    //do stuff here
}

stepNoと "ABC"を組み合わせて、ABC1であるコントローラーを取得しているようです。そのため、URLのそのセクションを{controller}に置き換えました。

「キー」と「グループ」を定義するルートもあるため、上記のルートも初期URLをキャッチしてアクションに送信します。

4
George Stocker

新しいASP.NET MVCプロジェクトでクエリ文字列に基づくルーティングを使用する理由はありません。従来のASP.NETプロジェクトから変換された古いプロジェクトで、URLを保持したい場合に役立ちます。

1つのソリューションは、属性ルーティングです。

別のソリューションは、RouteBaseから派生することにより、カスタムルーティングを作成することです。

public class MyOldClassicAspRouting : RouteBase
{

  public override RouteData GetRouteData(HttpContextBase httpContext)
  {
    if (httpContext.Request.Headers == null) //for unittest
      return null;

    var queryString = httpContext.Request.QueryString;

    //add your logic here based on querystring
    RouteData routeData = new RouteData(this, new MvcRouteHandler());
    routeData.Values.Add("controller", "...");
    routeData.Values.Add("action", "...");
  }

  public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
  {
     //Implement your formating Url formating here
     return null;
  }
}

カスタムルーティングクラスを登録します

public static void RegisterRoutes(RouteCollection routes)
{
  ...

  routes.Add(new MyOldClassicAspRouting ());
}
1
Tomas Kubes

クエリ文字列の引数は通常、そのコントローラーとその特定のアプリケーションロジックに固有です。

したがって、これが一般的なルートルールで記述されていない方が良いでしょう。

次の方法で、アクション引数にクエリ文字列の検出を埋め込むことができます。

StepNoを処理するコントローラーが1つある方が良いと思います。

public class ABC : Controller
{
    public ActionResult OpenCase(OpenCaseArguments arg)
    {
        // do stuff here
        // use arg.StepNo, arg.Key and arg.Group as You need
        return View();
    }        
}

public class OpenCaseArguments
{
    private string _id;
    public string id
    {
        get
        {
            return _id;
        }

        set
        {
            _id = value; // keep original value;
            ParseQueryString(value);
        }
    }

    public string  StepNo { get; set; }
    public string Key { get; set; }
    public string Group { get; set; }

    private void ParseQueryString(string qs)
    {
        var n = qs.IndexOf('?');
        if (n < 0) return;
        StepNo = qs.Substring(0, n); // extract the first part eg. {stepNo}
        NameValueCollection parms = HttpUtility.ParseQueryString(qs.Substring(n + 1));
        if (parms.Get("Key") != null) Key = parms.Get("Key");
        if (parms.Get("Group") != null) Group = parms.Get("Group");
    }

}

ModelBinderは、OpenCaseArgumentsのidフィールドに{id}値を割り当てます。 setメソッドはクエリ文字列分割ロジックを処理します。

そして、この方法でルーティングを続けます。ルーティングはid引数でクエリ文字列を取得することに注意してください。

routes.MapRoute(
    "OpenCase", 
    "ABC/OpenCase/{id}",
    new {controller = "ABC", action = "OpenCase"}
);

このメソッドを使用して、コントローラーアクションで複数のフィールドのキー値を取得しました。

0
RFex