Asp.net core ASP.NET WebAPI传统路由是否可以在不指定操作和HTTP谓词约束的情况下工作?

Asp.net core ASP.NET WebAPI传统路由是否可以在不指定操作和HTTP谓词约束的情况下工作?,asp.net-core,routing,asp.net-core-webapi,Asp.net Core,Routing,Asp.net Core Webapi,在我们的经典ASP.NETWebAPI项目中,我们可以声明一个路由,框架将根据请求中的HTTP谓词选择正确的操作 然而,在.NETCoreWebAPI中,我尝试了以下路由配置 app.UseEndpoints(endpoints => { endpoints.MapControllers(); endpoints.MapControllerRoute( name: "DefaultRoute", pattern: "{controller}/{id?}"

在我们的经典ASP.NETWebAPI项目中,我们可以声明一个路由,框架将根据请求中的HTTP谓词选择正确的操作

然而,在.NETCoreWebAPI中,我尝试了以下路由配置

app.UseEndpoints(endpoints =>
{
   endpoints.MapControllers();
   endpoints.MapControllerRoute(
      name: "DefaultRoute",
      pattern: "{controller}/{id?}"
   );
});
我的控制器有一个方法

public class WeatherForecastController : ControllerBase
{
   [HttpGet]
   public WeatherForecast Get()
   {
      //return weather forecast
   }
}
尝试以下URL时,我得到404,而在类似的经典ASP.NET WebAPI项目中,它会自动执行get方法

https://localhost/weatherforecast
这是否意味着对于传统路由,我们需要添加具有相同模式的多个路由,并带有默认操作和HTTP方法约束,以使其正常工作


这个问题只是关于传统路由,建议切换到属性路由并不是答案。

路由负责将请求URL映射到端点,它有两种类型:传统路由和属性路由

从您的问题来看,您期望使用默认路由的常规路由,您可以使用下面的代码行实现它

app.UseMvc(routes =>
{
    routes.MapRoute("default", "{controller=Search}/{action}/{id?}");
});
注意:但请记住,如果使用[ApiController]属性装饰控制器,传统路由将不起作用

默认情况下,.NET CORE支持属性路由,因此您必须通过在控制器级别上放置[route]属性来为路由添加前缀。请参见下面的示例

    [Route("api/[controller]")]
    [ApiController]
    public class SearchController : ControllerBase
    {

        [HttpGet("{company}")]
        public IActionResult Get(string company) 
        {
            return Ok($"company: {company}");
        }

        [HttpGet("{country}/{program}")]
        public IActionResult Get(string country, string program) 
        {
            return Ok($"country: {country} program: {program}");
        }
    }
上面的代码将按照您预期的属性路由工作

如果您是通过[ApiController]属性来装饰控制器,那么您必须使用属性路由,并且在启动类中定义的任何常规路由都将被覆盖。请查看更多详细信息

这是否意味着对于传统路由,我们需要添加具有相同模式的多个路由,并带有默认操作和HTTP方法约束,以使其正常工作

是的,在asp.net core web api中,如果要使用常规路由,需要先删除[ApiController]属性和[Route]属性,然后使用以下带有默认操作的路由

app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=WeatherForecast}/{action=Get}/{id?}");
    });

更新:使用Url重写

您可以随时编写自己的url重写规则以满足您的要求。请参阅下面的演示,该演示将处理url-like/weatherforecast:

创建重写规则:

public class RewriteRuleTest : IRule
    {
        public void ApplyRule(RewriteContext context)
        {
            var request = context.HttpContext.Request;
            var path = request.Path.Value;// path= "/weatherforecast" for example

            if(path !=null)
            {
                context.HttpContext.Request.Path = path + "/" + request.Method; 
                // "/weatherforecast/post"
            }
        }
    }
Startup.cs

app.UseRewriter(new RewriteOptions().Add(new RewriteRuleTest()));
app.UseRouting();

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
    endpoints.MapControllerRoute(
        name: "GetRoute",
        pattern: "{controller=WeatherForecast}/{action=Get}/{id?}"
    );
});

我在ASP.NET Core中的经典ASP.NET WebAPI中发现了一个试图模拟此行为的问题:

这个例子在.NETCore2和MVC中都有,但在.NETCore3WebAPI中尝试它的效果是一样的

答案似乎是否定的,在ASP.NET Core WebAPI中,如果路由模式中没有操作,并且没有HTTP方法约束,则框架不会自动尝试与请求中基于HTTP谓词的操作匹配。
为了实现这一点,需要添加具有默认操作和动词约束的多个路由。

那么,如果请求是POST或PUT,但url是/weatherforecast,会发生什么情况?在这种情况下,它将执行Get方法,因为这是默认操作,即使Http动词不是Get?@stormtrooper No,上面的配置只是一个示例。它还遵循规则/controller/action处理所有请求,因此它应该是/weatherforecast/post.Ok,您的意思是对于上面的配置,带有url/weatherforecast的POST请求将返回404?这意味着为了使带有URL/weatherforecast的POST请求能够工作,需要配置一个带有HttpMethod约束的额外路由,不是吗?@Stormthoper不太可能,要做的一个技巧是添加{controller=weatherforecast}/{action=POST}/{id}上面的代码对MVC的作用是相同的。为什么不想在url中使用动作名称?@Stormthoper我尝试用url重写,也许这是一个解决方法。请参阅我编辑的答案。