【问题标题】:ASP.Net Core Web API convention-based routing?ASP.Net Core Web API 基于约定的路由?
【发布时间】:2017-11-20 03:43:28
【问题描述】:

我错过了什么,我收到了这个控制器的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 东西外,一模一样……这个控制器中没有其他动作甚至方法

标签: c# asp.net-core asp.net-core-webapi asp.net-core-routing


【解决方案1】:

这是行不通的,因为没有定义到动作方法的映射。 AFAIK,您可以仅使用属性路由实现 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(基于 guide):您可以包含 Microsoft.AspNetCore.Mvc.WebApiCompatShim 的 NuGet 包并仍然使用 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 样式...
  • 也许不是 REST 风格,但无论如何在 ASP.NET Core WebAPI 中是可能的
  • 感谢您发现 github 问题。我从您的回答中得到提示,并将defaults: new { action = "Get" } 添加到Startup.cs 的路线注册中。它现在调用路由模板中没有{action} 的控制器。但是,如果我这样做,那么即使是 HTTP POST 也会调用 Get 方法。无论如何,我认为你的答案是正确的
  • @MattThomas 已更新答案,发现可以使用 Microsoft.AspNetCore.Mvc.WebApiCompatShim 使用 WebApi 路由行为
猜你喜欢
  • 2020-01-03
  • 1970-01-01
  • 2017-07-16
  • 2018-08-28
  • 1970-01-01
  • 2023-03-22
  • 2018-08-25
  • 1970-01-01
相关资源
最近更新 更多