AmbiguousMatchException 是什么原因导致的?

huangapple go评论68阅读模式
英文:

Why do I get this AmbiguousMatchException?

问题

I will provide a translation of the code snippet you shared:

我正在编写一个简单的.NET 7 Web应用程序,它将通过提供相同的Razor页面来响应任何GET请求。这是我的Program.cs:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();

var app = builder.Build();

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.MapFallbackToPage("/Index");
app.Run();

Please note that I won't respond to further translation requests as per your instructions. If you have any other questions or need assistance, feel free to ask.

英文:

I am writing a simple .NET 7 web application that will respond to any GET request by serving the same Razor page. This is my Program.cs:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();

var app = builder.Build();

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.MapFallbackToPage("/Index");
app.Run();

A request to https://localhost:7024/ returns my Razor page as expected. However, a request to https://localhost:7024/anythingelse throws an exception:

> Microsoft.AspNetCore.Routing.Matching.AmbiguousMatchException: The request matched multiple endpoints. Matches:
>
> /Index
> /Index
>
> at Microsoft.AspNetCore.Routing.Matching.DefaultEndpointSelector.ReportAmbiguity(CandidateState[]
> candidateState) at
> Microsoft.AspNetCore.Routing.Matching.DefaultEndpointSelector.ProcessFinalCandidates(HttpContext
> httpContext, CandidateState[] candidateState) at
> Microsoft.AspNetCore.Routing.Matching.DefaultEndpointSelector.SelectAsync(HttpContext
> httpContext, CandidateSet candidateSet) at
> Microsoft.AspNetCore.Routing.Matching.DfaMatcher.SelectEndpointWithPoliciesAsync(HttpContext
> httpContext, IEndpointSelectorPolicy[] policies, CandidateSet
> candidateSet) at
> Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.<Invoke>g__AwaitMatch|8_1(EndpointRoutingMiddleware
> middleware, HttpContext httpContext, Task matchTask) at
> Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext
> context) at
> Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext
> context)

答案1

得分: 1

You can use a middleware that will redirect all requests:

app.Use(async (context, next) =>
{
    var wipPath = "/Home/WorkInProgress";
    if ((string)context.Request.Path != wipPath)
    {
        context.Response.Redirect(wipPath);
        return;
    }
    await next();
});

Source: https://www.ryadel.com/en/asp-net-core-redirect-requests-single-url-route/

英文:

You can use a middleware that will redirect all requests:

app.Use(async (context, next) =&gt;
{
    var wipPath = &quot;/Home/WorkInProgress&quot;;
    if ((string)context.Request.Path != wipPath)
    {
        context.Response.Redirect(wipPath);
        return;
    }
    await next();
});

Source: https://www.ryadel.com/en/asp-net-core-redirect-requests-single-url-route/

答案2

得分: 1

抱歉,代码部分不需要翻译。

英文:

My initial answer did not address your question: "Why do I get this...?" It just provided how to resolve the AmbiguousMatchException error. Here's an explanation of why this error occurs, along with a code sample that shows what's happening.

ASP.NET Core is creating multiple routes for /Index: 1. for the Razor Page with the file name Index.cshtml; and 2. for the root URL of the web app (or https://localhost:7024/ in your question).

AmbiguousMatchException 是什么原因导致的?

Navigating to https://localhost:7024/ or https://localhost:7024/index works because these two route patterns have a clear match.

When app.MapFallbackToPage(&quot;/Index&quot;); is set in program.cs, with the first parameter set to the page name: /Index, the request is routed to the page endpoint /Index. The ambiguous exception occurs because there are two routes that match the endpoint for /Index.

Add a catch-all route template

Adding a catch-all route template (i.e. starting a route template with an asterik * followed by any word) as @Mike added in his answer, removes ambiguity.

@page &quot;{*anyword}&quot;

The catch-all route pattern, the second list item in the image below, matches https://localhost:7024/anythingelse.

Using a catch-all route pattern, however, in the @page directive in the Index.cshtml file in the root folder makes app.MapFallbackToPage(&quot;/Index&quot;); redundant. All request paths will be processed by the catch-all route pattern.

AmbiguousMatchException 是什么原因导致的?

Add "/Index" template

Add "/Index" to the @page directive in the main index page also removes ambiguity. Only one endpoint to /Index is registered.

@page &quot;/Index&quot;
@model WebApplication1.Pages.IndexModel
@{
}
&lt;h1&gt;Welcome&lt;/h1&gt;

AmbiguousMatchException 是什么原因导致的?

EndpointDataList code sample

The following code sample was used generate the image results above. Replace the first line in Index.cshtml, that is, the @page directive with any of the following to get the output of the images above, in order:

@page
@page &quot;{*anyword}&quot;
@page &quot;/Index&quot;

Index.cshtml

@page &quot;/Index&quot;
@model WebApplication1.Pages.IndexModel
&lt;table class=&quot;table&quot;&gt;
    &lt;thead&gt;
        &lt;tr&gt;
            &lt;th&gt;Display Name&lt;/th&gt;
            &lt;th&gt;Route Pattern&lt;/th&gt;
            &lt;th&gt;Url&lt;/th&gt;
        &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
        @foreach (EndpointData endpointData in @Model.EndpointDataList)
        {
            &lt;tr&gt;
                &lt;td&gt;@endpointData.DisplayName&lt;/td&gt;
                &lt;td&gt;@endpointData.RoutePattern&lt;/td&gt;
                &lt;td&gt;@endpointData.URL&lt;/td&gt;
            &lt;/tr&gt;
        }
    &lt;/tbody&gt;
&lt;/table&gt;

Index.cshtml.cs

using Microsoft.AspNetCore.Mvc.RazorPages;

namespace WebApplication1.Pages
{
    public class IndexModel : PageModel
    {
        private readonly IEnumerable&lt;EndpointDataSource&gt; _endpointSources;
        public IndexModel(
            IEnumerable&lt;EndpointDataSource&gt; endpointDataSources)
        {
            _endpointSources = endpointDataSources;
        }

        public IEnumerable&lt;RouteEndpoint&gt; EndpointSources { get; set; }
        public List&lt;EndpointData&gt; EndpointDataList { get; set; }

        public void OnGet()
        {
            EndpointSources = _endpointSources
                        .SelectMany(es =&gt; es.Endpoints)
                        .OfType&lt;RouteEndpoint&gt;();

            EndpointDataList = new List&lt;EndpointData&gt;();

            foreach (RouteEndpoint routeEndpoint in EndpointSources)
            {
                // If the route pattern is an empty string then
                // it represents the home page. The home page is
                // represented by the route pattern &#39;/Index&#39;.

                EndpointData pageData = new()
                {
                    DisplayName = routeEndpoint.DisplayName,
                    RoutePattern = routeEndpoint.RoutePattern.RawText,
                    URL = routeEndpoint.ToString()
                };
                EndpointDataList.Add(pageData);
            }
        }
    }

    public class EndpointData
    {
        public string DisplayName { get; set; }
        public string RoutePattern { get; set; }
        public string URL { get; set; }
    }
}

Program.cs

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();

var app = builder.Build();

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.MapFallbackToPage(&quot;/Index&quot;);
app.Run();

答案3

得分: 0

I'll provide the translation for the code part:

如果你想要一个单一页面来处理所有请求,请为它添加一个"catchall"路由模板:

@page "{*catchall}"

你可以检查 Request.Path 来获取实际的URL,或者你可以添加一个公共属性,命名为 CatchAll,并使用 BindProperty 属性,并设置 SupportsGet = true,如果你更喜欢使用模型绑定:

[BindProperty(SupportsGet=true)]
public string CatchAll { get; set; }
英文:

If you want a single page to process all requests, add a "catchall" route template to it:

@page &quot;{*catchall}&quot;

You can inspect Request.Path for the actual URL, or you can add a public property named CatchAll with a BindProperty attribute with SupportsGet = true if you prefer to use model binding:

[BindProperty(SupportsGet=true)]
public string CatchAll { get; set; }

huangapple
  • 本文由 发表于 2023年4月6日 21:23:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/75950048.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定