传统路由在ASP.NET Core API中的应用

14
问题:
我正在使用.NET Core 3.1创建API应用程序。 我想避免在每个ApiController和操作上设置路由属性。我尝试了许多组合来设置常规路由,但失败了。
在某些配置下,我无法让API工作,在其他一些配置下,在启动期间会出现以下异常:
InvalidOperationException:操作“ApiIsWorking”没有属性路线。 使用ApiControllerAttribute注释的控制器上的操作方法必须具有属性路由。
如何将startup.cs设置为自动映射控制器与其类名以及操作与其方法名?
谢谢!
一些代码:
startup.cs
...
services.AddControllers()
...

app.UseHttpsRedirection()
   .UseRouting()
   .UseAuthentication()
   .UseEndpoints(endpoints => ?? )
   .UseCoreHttpContext()
   .UseServerConfiguration();

控制器.cs

[ApiController]
public class BaseAPI : ControllerBase 
{
        [HttpGet]
        public string ApiIsWorking()
        {
            return "API is working!";
        }
}

解决方案:

正如Reza Aghaei在解决方案中所说,错误是添加ApiController属性。当我删除它后,UseEndpoints命令开始工作。

我的错误是添加该属性以便识别哪些类应通过API公开。这是不必要的,因为UseEndpoints仅映射继承自ControllerBase的类。

注意事项:

1)传统路由在操作参数中需要使用[FromBody]属性。

2)我强调Zinov的回复关于.NET Core中传统路由与Swashbuckle的问题。


2
要为控制器和操作设置传统路由,您需要从控制器中删除[ApiController]属性,并在UseEndpoints中设置路由。 - Reza Aghaei
长话短说,坐在数千英里之外的平台架构师已经为您做出了使用属性路由的设计决策,并通过使传统路由难以使用来强制执行该决策。 - Greg Graham
4个回答

18
要为您的控制器和操作设置传统路由,您需要从控制器和操作中删除[ApiController]属性和[Route]属性,并在UseEndpoints中设置路由。在文档中已经提到了这一点:

[ApiController]属性使属性路由成为必需。

Startup.Configure中定义的传统路由UseEndpoints, UseMvc,或UseMvcWithDefaultRoute无法访问操作。

示例 这是我为启动设置的工作环境:
public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }
    public IConfiguration Configuration { get; }
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllersWithViews();
    }
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
        }
        app.UseStaticFiles();
        app.UseRouting();
        app.UseAuthorization();
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
        });
    }
}

以下是一个示例API控制器:

public class ValuesController : ControllerBase
{
    // values/getall
    [HttpGet]
    public IEnumerable<string> GetAll()
    {
        return new string[] { "value1", "value2" };
    }

    // values/getitem/1
    [HttpGet]
    public string GetItem(int id)
    {
        return "value";
    }
}

4

如果您打算使用传统路由与.net core,这是我的建议。在完成API实现后,您需要为其添加一些文档。人们通常使用Swashbuckle.AspNetCore这个nuget包,该包实现了OpenAPI(Swagger)的后期标准。但是如果您使用传统路由并希望使用此工具生成文档,则会出现问题。

如果您使用传统路由(而不是属性路由),那些使用传统路由的控制器和这些控制器上的操作将不会被表示在ApiExplorer中,这意味着Swashbuckle无法找到这些控制器并从中生成Swagger操作

更多信息请参阅此链接:Swashbuckle 希望这可以为您的API文档节省很多麻烦。


4

编辑:

我试图在我的机器上设置它。当我从控制器中删除了Route属性后,我遇到了以下错误:

InvalidOperationException: Action'WebAPISample.Controllers.WeatherForecastController.Index(WebAPISample)'没有属性路由。带有ApiControllerAttribute注释的控制器上的操作方法必须使用属性路由。

错误信息本身表明API控制器必须使用属性路由。

我知道这并没有回答你的问题,但是在.NET Core 3 API中,似乎不可能实现这一点。

来自文档:

The [ApiController] attribute makes attribute routing a requirement. For example:

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

Actions are inaccessible via conventional routes defined by UseMvc or UseMvcWithDefaultRoute in Startup.Configure.

请参考 MSDN 上的此页面


这似乎是不可能的。如果要实现,需要从控制器/操作中删除[ApiController][Route(...)]属性,并在UseEndpoints中设置路由。可以参考此帖子中的示例。 - Reza Aghaei

3
你试过这个吗? app.UseEndpoints(endpoints => { endpoints.MapControllers(); });

1
是的,我在启动时遇到了这个异常:“System.InvalidOperationException:'Action ApiIsWorking'没有属性路由。带有ApiControllerAttribute注释的控制器上的操作方法必须具有属性路由。” - Paolo Crociati
@Paolo crociati,你的问题解决了吗?能否在这里分享你的代码。 - Joel Dharansingh

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