ASP.Net Core Web API约定路由是什么?

10

为什么我访问这个控制器时出现了404错误?我不想使用基于属性的路由。我也不想让action成为任何URI的一部分。

我正在使用Visual Studio 2017和.Net Core 1.1。

TestController.cs

using System;
using Microsoft.AspNetCore.Mvc;

namespace Foo.Controllers
{
    public class TestController : Controller
    {
        public long Get() => DateTimeOffset.Now.ToUnixTimeSeconds();
    }
}

请注意,这只适用于[Route("api/Test")]属性。但是我不想使用基于属性的路由。一旦我去掉该属性,我就会得到404错误。

Startup.cs

namespace Foo
{
    public class Startup
    {
        public Startup(IHostingEnvironment env)
        {
            var builder = new ConfigurationBuilder()
                .SetBasePath(env.ContentRootPath)
                .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
                .AddEnvironmentVariables();
            Configuration = builder.Build();
        }

        public IConfigurationRoot Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            // Add framework services.
            services.AddMvc();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            loggerFactory.AddConsole(Configuration.GetSection("Logging"));
            loggerFactory.AddDebug();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "api/{controller}/{id?}"
                    );
            });
        }
    }
}

注意:这里还有一些关于Autofac/DI的内容,但是我已经将其去掉以消除干扰。

请求的调试输出

Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-03-10T14:18:01.3308908Z","tags":{"ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.operation.id":"0HL37O0HBESDL","ai.application.ver":"1.0.0.0"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"Request starting HTTP/1.1 GET http://localhost:50129/api/test","severityLevel":"Information","properties":{"DeveloperMode":"true","Host":"localhost:50129","AspNetCoreEnvironment":"Development","CategoryName":"Microsoft.AspNetCore.Hosting.Internal.WebHost","Path":"/api/test","Protocol":"HTTP/1.1","Method":"GET","Scheme":"http"}}}}
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://localhost:50129/api/test  
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-03-10T14:18:01.3633954Z","tags":{"ai.cloud.roleInstance":"Desktop","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.location.ip":"::1","ai.operation.id":"0HL37O0HBESDM","ai.application.ver":"1.0.0.0","ai.internal.nodeName":"Desktop","ai.operation.name":"GET /api/test"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"Request successfully matched the route with name 'default' and template 'api/{controller}/{id?}'.","severityLevel":"Verbose","properties":{"DeveloperMode":"true","AspNetCoreEnvironment":"Development","CategoryName":"Microsoft.AspNetCore.Routing.RouteBase","RouteName":"default","{OriginalFormat}":"Request successfully matched the route with name '{RouteName}' and template '{RouteTemplate}'.","RouteTemplate":"api/{controller}/{id?}"}}}}
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-03-10T14:18:01.3663952Z","tags":{"ai.cloud.roleInstance":"Desktop","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.location.ip":"::1","ai.operation.id":"0HL37O0HBESDM","ai.application.ver":"1.0.0.0","ai.internal.nodeName":"Desktop","ai.operation.name":"GET /api/test"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"No actions matched the current request","severityLevel":"Verbose","properties":{"DeveloperMode":"true","AspNetCoreEnvironment":"Development","CategoryName":"Microsoft.AspNetCore.Mvc.Internal.MvcRouteHandler","{OriginalFormat}":"No actions matched the current request"}}}}
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-03-10T14:18:01.3693962Z","tags":{"ai.cloud.roleInstance":"Desktop","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.location.ip":"::1","ai.operation.id":"0HL37O0HBESDM","ai.application.ver":"1.0.0.0","ai.internal.nodeName":"Desktop","ai.operation.name":"GET /api/test"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"Request did not match any routes.","severityLevel":"Verbose","properties":{"DeveloperMode":"true","AspNetCoreEnvironment":"Development","CategoryName":"Microsoft.AspNetCore.Builder.RouterMiddleware","{OriginalFormat}":"Request did not match any routes."}}}}
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-03-10T14:18:01.3753962Z","tags":{"ai.cloud.roleInstance":"Desktop","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.location.ip":"::1","ai.operation.id":"0HL37O0HBESDM","ai.application.ver":"1.0.0.0","ai.internal.nodeName":"Desktop","ai.operation.name":"GET /api/test"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"Connection id \"0HL37O0H95P8K\" completed keep alive response.","severityLevel":"Verbose","properties":{"DeveloperMode":"true","ConnectionId":"0HL37O0H95P8K","AspNetCoreEnvironment":"Development","CategoryName":"Microsoft.AspNetCore.Server.Kestrel","{OriginalFormat}":"Connection id \"{ConnectionId}\" completed keep alive response."}}}}
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-03-10T14:18:01.3878990Z","tags":{"ai.cloud.roleInstance":"Desktop","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.location.ip":"::1","ai.operation.id":"0HL37O0HBESDM","ai.application.ver":"1.0.0.0","ai.internal.nodeName":"Desktop","ai.operation.name":"GET /api/test"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"Request finished in 54.7982ms 404","severityLevel":"Information","properties":{"DeveloperMode":"true","ElapsedMilliseconds":"54.7982","AspNetCoreEnvironment":"Development","CategoryName":"Microsoft.AspNetCore.Hosting.Internal.WebHost","StatusCode":"404"}}}}
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 54.7982ms 404

@Nkosi 除了我删除的一些Autofac/DI内容之外,它就是这样的... 这个控制器中没有其他操作甚至方法。 - Matt Thomas
1个回答

5

这不起作用,因为未定义映射到操作方法的内容。据我所知,您只能使用属性路由来实现WebApi REST风格的路由,并且可以在控制器级别上定义它:

[Route("api/[controller]")]
public class TestController : Controller
{
    [HttpGet]
    public long Get() => DateTimeOffset.Now.ToUnixTimeSeconds();
}
更新: 我们发现了这个github问题Web API not working with convention based routin,并且:

对于ASP.NET Core MVC,我们决定采用MVC 5.x的传统路由方法而不是Web API 2.x的方法。在传统路由方法中,路由必须同时指定控制器和操作


您可以更改路由模板为

template: "api/{controller}/{action}/{id?}"

但在这种情况下,你的URL将会是/api/test/get


更新2(基于指南):你可以包含NuGet软件包Microsoft.AspNetCore.Mvc.WebApiCompatShim,并仍然使用ApiController。如果你想知道它的作用,可以查看GitHub上的代码。然后你可以定义WebApi路由:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    app.UseMvc(routes =>
    {
        routes.MapWebApiRoute("DefaultApi", "api/{controller}/{id?}");
    });
}

@Alex使用template: "api/{controller}/{action}{id?}"?但在这种情况下,这不是WebAPI REST风格... - Set
也许它不是REST风格,但在ASP.NET Core WebAPI中仍然是可能的。 - Alexan
感谢你找到了那个 Github 的问题。我从你的答案中得到提示,在 Startup.cs 中的路由注册中添加了 defaults: new { action = "Get" } 。现在它可以在路由模板中不使用 {action} 来调用控制器了。然而,如果我这样做,甚至 HTTP POST 请求也会调用那个 Get 方法。无论如何,我认为你的答案是正确的。 - Matt Thomas
1
@MattThomas已更新答案,发现可以使用Microsoft.AspNetCore.Mvc.WebApiCompatShim来使用WebApi路由行为。 - Set

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接