ASP.Net Core Web API 基于约定的路由?
ASP.Net Core Web API convention-based routing?
收到此控制器 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")]
属性。但我不想使用基于属性的路由。一旦我取消该属性,我就会收到 404s。
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
这是行不通的,因为未定义到操作方法的映射。 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 并且:
for ASP.NET Core MVC we decided to adopt MVC 5.x's conventional routing approach and not Web API 2.x's approach. With the conventional routing approach, the route must specify both a controller and an action.
您可以将路线模板更改为
template: "api/{controller}/{action}/{id?}"
但在这种情况下,您的 URL 将是 /api/test/get
。
Update 2(基于guide): you can include the NuGet package for Microsoft.AspNetCore.Mvc.WebApiCompatShim and still use ApiController. The code is on GitHub如果你好奇它做了什么。那么你可以定义WebApi路由:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseMvc(routes =>
{
routes.MapWebApiRoute("DefaultApi", "api/{controller}/{id?}");
});
}
收到此控制器 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")]
属性。但我不想使用基于属性的路由。一旦我取消该属性,我就会收到 404s。
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
这是行不通的,因为未定义到操作方法的映射。 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 并且:
for ASP.NET Core MVC we decided to adopt MVC 5.x's conventional routing approach and not Web API 2.x's approach. With the conventional routing approach, the route must specify both a controller and an action.
您可以将路线模板更改为
template: "api/{controller}/{action}/{id?}"
但在这种情况下,您的 URL 将是 /api/test/get
。
Update 2(基于guide): you can include the NuGet package for Microsoft.AspNetCore.Mvc.WebApiCompatShim and still use ApiController. The code is on GitHub如果你好奇它做了什么。那么你可以定义WebApi路由:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseMvc(routes =>
{
routes.MapWebApiRoute("DefaultApi", "api/{controller}/{id?}");
});
}