ルーティングを変更する
ルーティングに対応し、id
デフォルトを削除してオプションのパラメータにするだけです。
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index" } // defaults
);
ただし、これらのデフォルトが使用されることはありません。
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}" // URL with parameters
);
これは、定義する必要がある実際のルートです。
あなたのcontroller
とは、必要に応じaction
てURLから省略されることはなくid
、URL定義の最後のものです。つまり、最初のペアもそこにある必要があります。
それがまさにあなたが必要としているものであるかどうかはわかりませんが、あなたの質問の現在の状態に基づいて、これはあなたのためにトリックをするはずです。ただし、事前定義された値を持つためにIDが必要な場合は、ルート定義で別の値を指定できます。
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = 1 } // defaults
);
これにより、3つすべてをURLから省略でき、それらすべてに特定の値を設定できます。
id
フォーマットを定義するためのルート制約
ルート制約を使用して、URLパラメータがどのように見えるかをルーティングに指示することもできます。あなたid
は数値でなければならないように見えるので、これも可能性の1つです:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index" }, // defaults
new { id = "\d+" } // constraints
);
編集後
実際には、問題には2つの解決策があります。
id
一部のルートに必要なものを定義するための適切なルーティング
- 特定のパラメーターを必要とするアクションを宣言的にマークするアクションメソッドセレクターフィルター
解決策1:ルーティング
これはいくつかのルーティング定義を定義しますが、id
パラメーターを必要とするアクションをハードコーディングします。
routes.MapRoute(
"RequiresId",
"{controller}/{action}/{id}", // URL with parameters
null,
new { action = "Detail" }
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}" // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new { action = "(?!Detail).+" } // any action except "Detail"
);
最初のルートは、アクションメソッドを持つすべてのコントローラーがパラメーターをDetail
必要とすることを定義しid
ます。これらのアクションを持つすべてのコントローラーが同じ要件を持っている限り、これは簡単です(あなたの場合はそうかもしれません)。ただし、これが当てはまらない場合は、コントローラーごとに制約を指定する必要があるため、より複雑になります。
解決策2:アクションメソッドセレクターフィルター
このソリューションでは、オプションのデフォルトルートのみが必要ですid
。カスタムアクションメソッドセレクターフィルター(ほとんど知られておらず、ほとんど使用されていません)は、次のようなコードを作成するのに役立ちます。
[RequiresRouteValues("id, name")]
public ActionResult Detail(int id, string name)
{
...
}
あなたはそれを必要とするそれらのメソッドにこれを置くでしょう。その特定のパラメーターが存在しない場合、コントローラーアクションの呼び出し元は適切なメソッドを見つけることができないため、404が返されます。
これについては、ブログで詳しく説明しました。また、次のようなフィルターのコードも含まれています。
/// <summary>
/// Represents an attribute that is used to restrict action method selection based on route values.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1019:DefineAccessorsForAttributeArguments")]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public sealed class RequiresRouteValuesAttribute : ActionMethodSelectorAttribute
{
#region Properties
/// <summary>
/// Gets required route value names.
/// </summary>
public ReadOnlyCollection<string> Names { get; private set; }
/// <summary>
/// Gets or sets a value indicating whether to include form fields in the check.
/// </summary>
/// <value><c>true</c> if form fields should be included; otherwise, <c>false</c>.</value>
public bool IncludeFormFields { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to include query variables in the check.
/// </summary>
/// <value>
/// <c>true</c> if query variables should be included; otherwise, <c>false</c>.
/// </value>
public bool IncludeQueryVariables { get; set; }
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="RequiresRouteValuesAttribute"/> class.
/// </summary>
private RequiresRouteValuesAttribute()
{
this.IncludeFormFields = true;
this.IncludeQueryVariables = true;
}
/// <summary>
/// Initializes a new instance of the <see cref="RequiresRouteValuesAttribute"/> class.
/// </summary>
/// <param name="commaSeparatedNames">Comma separated required route values names.</param>
public RequiresRouteValuesAttribute(string commaSeparatedNames)
: this((commaSeparatedNames ?? string.Empty).Split(','))
{
// does nothing
}
/// <summary>
/// Initializes a new instance of the <see cref="RequiresRouteValuesAttribute"/> class.
/// </summary>
/// <param name="names">Required route value names.</param>
public RequiresRouteValuesAttribute(IEnumerable<string> names)
: this()
{
if (names == null || names.Count().Equals(0))
{
throw new ArgumentNullException("names");
}
// store names
this.Names = new ReadOnlyCollection<string>(names.Select(val => val.Trim()).ToList());
}
#endregion
#region ActionMethodSelectorAttribute implementation
/// <summary>
/// Determines whether the action method selection is valid for the specified controller context.
/// </summary>
/// <param name="controllerContext">The controller context.</param>
/// <param name="methodInfo">Information about the action method.</param>
/// <returns>
/// true if the action method selection is valid for the specified controller context; otherwise, false.
/// </returns>
public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
{
if (controllerContext == null)
{
throw new ArgumentNullException("controllerContext");
}
// always include route values
HashSet<string> uniques = new HashSet<string>(controllerContext.RouteData.Values.Keys);
// include form fields if required
if (this.IncludeFormFields)
{
uniques.UnionWith(controllerContext.HttpContext.Request.Form.AllKeys);
}
// include query string variables if required
if (this.IncludeQueryVariables)
{
uniques.UnionWith(controllerContext.HttpContext.Request.QueryString.AllKeys);
}
// determine whether all route values are present
return this.Names.All(val => uniques.Contains(val));
}
#endregion
}
1つ目は、複数のコントローラーとそれらに関連するさまざまな制約があるアプリケーションでは、事態を複雑にします。2つ目はエレガントで、単純なシナリオと複雑なシナリオに適用されます。
もちろん、ソリューション2を選択します。しかし、この場合、私を偏った開発者と見なしてください。