web-dev-qa-db-ja.com

URLに一致する複数のコントローラータイプが見つかりました。これは、複数のコントローラーの属性ルートが要求されたURLと一致する場合に発生する可能性があります

...私がこれについて最初に尋ねたと思いますか?

次のルートがあり、それぞれが異なるコントローラーで宣言されているとします。

[HttpGet, Route("sign-up/register", Order = 1)]
[HttpGet, Route("sign-up/{ticket}", Order = 2)]

... Orderパラメーターを除いて、同じコードを使用してMVC5.0でこれを行うことができます。ただし、MVC 5.1にアップグレードすると、質問のタイトルに例外メッセージが表示されます。

URLに一致する複数のコントローラータイプが見つかりました。これは、複数のコントローラーの属性ルートが要求されたURLと一致する場合に発生する可能性があります。

したがって、新しいRouteAttribute.Orderプロパティはコントローラーレベルのみですか? AttributeRouting.NETではSitePrecedenceも実行できることを知っています。すべてのアクションが同じコントローラー内にある場合、上記のようなルートを作成する唯一の方法はありますか?

更新

申し訳ありませんが、これらのルートはWebAPIではなくMVCコントローラー上にあると言っておく必要があります。これがApiControllersにどのように影響するかわかりません。

15
danludwig

属性ルーティングの場合、WebAPIはリクエストに一致するすべてのコントローラーを見つけようとします。複数のコントローラーがこれを処理できることがわかった場合、これはユーザーエラーである可能性があると見なされるため、例外がスローされます。このルートプロービングは、最初の一致が勝つ通常のルーティングとは異なります。

回避策として、同じコントローラー内にこれら2つのアクションがある場合、Web APIはルートの優先順位を尊重し、シナリオが機能していることを確認する必要があります。

12
Kiran Challa

ticketintになることがわかっている場合は、ルートでそのタイプを指定して、ルートの解決に役立てることができます。

[HttpGet, Route("sign-up/register")] [HttpGet, Route("sign-up/{ticket:int}")]

同じルートプレフィックスASP.NET Web Apiを持つ複数のコントローラータイプ へのリンクを含むuser1145404のコメントによると、このアプローチは私にとってはうまくいきました。

16
Tony Borres

これを修正する方法は2つあります。

ここのような正規表現の制約: 2つの異なるルートでのMVCルート属性エラー

または、次のようなカスタムルート制約: https://blogs.msdn.Microsoft.com/webdev/2013/10/17/attribute-routing-in-asp-net-mvc-5/

IRouteConstraintインターフェイスを実装することにより、カスタムルート制約を作成できます。たとえば、次の制約は、パラメーターを有効な値のセットに制限します。

public class ValuesConstraint : IRouteConstraint
{
    private readonly string[] validOptions;
    public ValuesConstraint(string options)
    {
        validOptions = options.Split('|');
    }

    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        object value;
        if (values.TryGetValue(parameterName, out value) && value != null)
        {
            return validOptions.Contains(value.ToString(), StringComparer.OrdinalIgnoreCase);
        }
        return false;
    }
}

次のコードは、制約を登録する方法を示しています。

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        var constraintsResolver = new DefaultInlineConstraintResolver();

        constraintsResolver.ConstraintMap.Add("values", typeof(ValuesConstraint));

        routes.MapMvcAttributeRoutes(constraintsResolver);
    }
}

これで、ルートに制約を適用できます。

public class TemperatureController : Controller
{
    // eg: temp/celsius and /temp/Fahrenheit but not /temp/kelvin
    [Route("temp/{scale:values(celsius|Fahrenheit)}")]
    public ActionResult Show(string scale)
    {
        return Content("scale is " + scale);
    }
}

私の意見では、これは素晴らしいデザインではありません。自分で明示的に設定しない限り、意図したURLについての判断や、照合時の特定のルールはありません。しかし、少なくともあなたはあなたのURLをあなたが望むように見せることができます。制約リストが長すぎないことを願っています。そうである場合、またはルート文字列パラメーターとその制約をハードコーディングしたくない場合は、actionメソッドの外部でプログラムでビルドし、変数としてRoute属性にフィードすることができます。

3
nmit026