(转载非原创)由ASP.NET Core WebApi添加Swagger报错引发的探究

2021-07-12 09:48:01 浏览数 (1)

由ASP.NET Core WebApi添加Swagger报错引发的探究

缘起#

    在使用ASP.NET Core进行WebApi项目开发的时候,相信很多人都会使用Swagger作为接口文档呈现工具。相信大家也用过或者了解过Swagger,这里咱们就不过多的介绍了。本篇文章记录一下,笔者在使用ASP.NET Core开发Api的过程中,给接口整合Swagger过程中遇到的一个异常,笔者抱着好奇的心态研究了一下异常的原因,并解决了这个问题。在这个过程中笔者学到了一些新的技能,得到了一些新的知识,便打算记录一下,希望能帮助到更多的人。

示例#

    从项目渊源上说起,笔者所在项目,很多都是从.Net FrameWork的老项目迁移到ASP.NET Core上来的,这其中做了很多兼容的处理,来保证尽量不修改原有的业务代码,这其中就包含了WebApi相关的部分,这里我们用简单的示例描述现有WebApi的Controller的情况,大致写法如下

代码语言:javascript复制
[Route("api/[controller]/[action]")]
代码语言:javascript复制
[ApiController]
代码语言:javascript复制
public class OrderController : ControllerBase
代码语言:javascript复制
{
代码语言:javascript复制
    private List<OrderDto> orderDtos = new List<OrderDto>();
代码语言:javascript复制
    public OrderController()
代码语言:javascript复制
    {
代码语言:javascript复制
        orderDtos.Add(new OrderDto { Id = 1,TotalMoney=222,Address="北京市",Addressee="me",From="淘宝",SendAddress="武汉" });
代码语言:javascript复制
        orderDtos.Add(new OrderDto { Id = 2, TotalMoney = 111, Address = "北京市", Addressee = "yi", From = "京东", SendAddress = "北京" });
代码语言:javascript复制
        orderDtos.Add(new OrderDto { Id = 3, TotalMoney = 333, Address = "北京市", Addressee = "yi念之间", From = "天猫", SendAddress = "杭州" });
代码语言:javascript复制
    }
代码语言:javascript复制
    /// <summary>
代码语言:javascript复制
    /// 获取订单数据
代码语言:javascript复制
    /// </summary>
代码语言:javascript复制
    public OrderDto Get(long id)
代码语言:javascript复制
    {
代码语言:javascript复制
        return orderDtos.FirstOrDefault(i => i.Id == id);
代码语言:javascript复制
    }
代码语言:javascript复制
    /// <summary>
代码语言:javascript复制
    /// 添加订单数据
代码语言:javascript复制
    /// </summary>
代码语言:javascript复制
    public IActionResult Add(OrderDto orderDto)
代码语言:javascript复制
    {
代码语言:javascript复制
        orderDtos.Add(orderDto);
代码语言:javascript复制
        return Ok();
代码语言:javascript复制
    }
代码语言:javascript复制
    /// <summary>
代码语言:javascript复制
    /// 添加订单数据
代码语言:javascript复制
    /// </summary>
代码语言:javascript复制
    public IActionResult Edit(long id, OrderDto orderDto)
代码语言:javascript复制
    {
代码语言:javascript复制
        var order = orderDtos.FirstOrDefault(i => i.Id == id);
代码语言:javascript复制
        if (order == null)
代码语言:javascript复制
        {
代码语言:javascript复制
            return NotFound();
代码语言:javascript复制
        }
代码语言:javascript复制
        order.Address = orderDto.Address;
代码语言:javascript复制
        order.From = orderDto.From;
代码语言:javascript复制
        return Ok();
代码语言:javascript复制
    }
代码语言:javascript复制
    /// <summary>
代码语言:javascript复制
    /// 删除订单数据
代码语言:javascript复制
    /// </summary>
代码语言:javascript复制
    public IActionResult Delete(long id)
代码语言:javascript复制
    {
代码语言:javascript复制
        var order = orderDtos.FirstOrDefault(i=>i.Id==id);
代码语言:javascript复制
        if (order == null)
代码语言:javascript复制
        {
代码语言:javascript复制
            return NotFound();
代码语言:javascript复制
        }
代码语言:javascript复制
        orderDtos.Remove(order);
代码语言:javascript复制
        return Ok();
代码语言:javascript复制
    }
代码语言:javascript复制
}

虽然是笔者写的demo,但是大致是这种形式,而且直接通过ASP.NET Core运行起来也没有任何的问题,调用也不会出现任何异常。当项目开发完成后,给项目添加Swagger,笔者用的是Swashbuckle.AspNetCore这个组件,添加Swagger的方式大致如下,首先是在Startup类的ConfigureServices方法中添加以下代码

代码语言:javascript复制
services.AddSwaggerGen(c =>
代码语言:javascript复制
{
代码语言:javascript复制
    c.SwaggerDoc("v1", new OpenApiInfo
代码语言:javascript复制
    {
代码语言:javascript复制
        Title = "OrderApi",
代码语言:javascript复制
        Description = "订单服务接口"
代码语言:javascript复制
    });
代码语言:javascript复制
    var xmlCommentFile = $"{AppContext.BaseDirectory}OrderApi.xml";
代码语言:javascript复制
    if (File.Exists(xmlCommentFile))
代码语言:javascript复制
    {
代码语言:javascript复制
        c.IncludeXmlComments(xmlCommentFile);
代码语言:javascript复制
    }
代码语言:javascript复制
});

添加完成之后,在Configure方法中开启Swagger中间件,具体代码如下

代码语言:javascript复制
app.UseSwagger();
代码语言:javascript复制
app.UseSwaggerUI(c =>
代码语言:javascript复制
{
代码语言:javascript复制
    c.SwaggerEndpoint("/swagger/v1/swagger.json", "OrderApi");
代码语言:javascript复制
});

添加完成之后,运行起来项目打开Swagger地址http://localhost:5000/swagger结果直接弹出了一个红色浮窗,看样子有异常,打开.Net Core控制台窗口看到了如下异常

代码语言:javascript复制
fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1] An unhandled exception has occurred while executing the request.
代码语言:javascript复制
Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorException: Ambiguous HTTP method for action OrderApi.Controllers.OrderController.Get (OrderApi). 
代码语言:javascript复制
Actions require an explicit HttpMethod binding for Swagger/OpenAPI 3.0
代码语言:javascript复制
at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GenerateOperations(IEnumerable`1 apiDescriptions, SchemaRepository schemaRepository)
代码语言:javascript复制
at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GeneratePaths(IEnumerable`1 apiDescriptions, SchemaRepository schemaRepository)
代码语言:javascript复制
at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GetSwagger(String documentName, String host, String basePath)
代码语言:javascript复制
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
代码语言:javascript复制
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

其中核心的关键词汇就是Ambiguous HTTP method for action OrderApi.Controllers.OrderController.Get (OrderApi). Actions require an explicit HttpMethod binding for Swagger/OpenAPI 3.0笔者用尽毕生的英语修为,了解到其大概意思是Swagger/OpenAPI 3.0要求Action上必须绑定HttpMethod相关Attribute,否则就报这一大堆错误。这里的HttpMethod其实就是咱们常用HttpGetHttpPostHttpPutHttpDelete相关的Attribute。 正常逻辑来说那就给每个Action添加HttpMethod呗,但是往往情况就出现在不正常的时候。因为项目是迁移的老项目,先不说私自改了别人代码带来的甩锅问题,公司的WebApi项目很多,这意味着Action很多,如果一个项目一个项目的去找Action添加HttpMethod可是一个不小的工作量,而且开发人员工作繁忙,基本上不会抽出来时间去修改这些的,因为这种只是Swagger不行,但是对于WebApi本身来说这种写法没有任何的问题,也不会报错,只是看起来不规范。那该怎么办呢?

探究源码#

又看了看异常决定从源码入手,通过控制台报出的异常可以看到报错的最初位置是在Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GenerateOperations(IEnumerable1 apiDescriptions, SchemaRepository schemaRepository)`那就从这里准备入手了。

Swashbuckle.AspNetCore入手#

在GitHub上找到Swashbuckle.AspNetCore仓库位置,近期GitHub不太稳定,除了梯子貌似也没有很好的办法,多刷新几次将就着用吧,由异常信息可知抛出异常所在的位置SwaggerGenerator类的GenerateOperations方法直接找到源码位置[点击查看源码

0 人点赞