Search code examples
c#asp.net-coreswaggerswagger-uiaspnetboilerplate

Swagger crashes when I add a new Application Service


Before you read this post, know that I have already looked at this post and... The problem is ALMOST the same, and I've tried the solution. So this post is not duplicated.

We used ASP.NET Boilerplate startup template. We've developed some Application Services, which are structured as:

public interface IFooAppService : 
    IAsyncCrudAppService<FooDto, Guid, GetAllFooDto, CreateFooDto, UpdateFooDto>
    // Abp.Application.Services.IAsyncCrudAppService<...>
{
}

[AbpAuthorize("Authorize.Foo")]
public class FooAppService : 
    AsyncCrudAppService<Foo, FooDto, Guid, FooFilterInput, CreateFooDto, FooDto>,
    IFooAppService
{
    private readonly BarManager _barManager;
    public FooAppService(IBarManager barManager, IRepository<Foo, Guid> repository)
        : base (repository)
    {
        _barManager = barManager;
    }

    public override async Task<FooDto> Create(CreateFooDto input)
    {
        // create with repository
    }

    // other overridden Actions and Foo interface implementation
}

Everything is in agreement with the documentation available here.

All methods work well and I can use all Swagger features. Configuration seems to be ok (we inject some post-JavaScript for ABP, ...), etc.

Initially, I had the following versions:

  • Microsoft.AspNetCore: 2.0.1
  • Microsoft.EntityFrameworkCore: 2.0.1
  • Abp.AspNetCore: 3.6.2
  • Swashbuckle.AspNetCore: 1.1.0

We had 385 APIs.

I added a new AppService, Commitment, with its Manager, Dtos, etc.

At that moment, when I start and I go in swagger, my browser crashes and displays a message asking me if I want to stop the script (IE, Edge, Firefox, Chrome, ...).

In debug mode, I have no information regarding a possible exception throwed.

Tried:

  1. Update Swashbuckle.AspNetCore NuGet package (all versions: 1.2, 2.X and 3.0.0)

    • In version 1.X, I've the same problem.
    • In version 2.5, UI doesn't displayed.
    • In other versions, UI is displayed, I can use all methods EXCEPT my new methods, Commitment. When I click hover him, I've only the spinner... Browser freezes and ask me if I want to stop the script or wait. Swagger UI freezes

On Chrome, Chrome raise an error : Chrome debugging catches an exception

  1. Remove overridden methods for Commitments.

In case my code is wrong inside of overridden methods.

[AbpAuthorize("Authorize.Commitments")]
public class CommitmentAppService : 
    AsyncCrudAppService<Commitment, CommitmentDto, Guid, CommitmentFilterInput, CreateCommitmentDto, UpdateCommitmentDto>,
    ICommitmentAppService
{
    private readonly ICommitmentManager _commitmentManager;
    private readonly IFundManager _fooManager;
    private readonly ILimitedPartnerManager _barManager;

    public CommitmentAppService(
        ICommitmentManager commitmentManager,
        IFooManager fooManager,
        IBarManager barManager,
        IOneRepository<Commitment, Guid> repository)
        : base(repository)
    {
        _commitmentManager = commitmentManager;
        _fooManager = fooManager;
        _barManager = barManager;
        _commitmentManager = commitmentManager;
    }
    // nothing here
}

Same result.

  1. Use only one DTO (CommitmentDto) instead of a set of DTOs CommitmentDto, CreateCommitmentDto, UpdateCommitmentDto, ...

    • AsyncCrudAppService<Commitment, CommitmentDto, Guid> where are defined the Entity, its DTO and PK type
    • AsyncCrudAppService<Commitment, CommitmentDto, Guid, CommitmentFilterInput> where are defined the Entity, its default DTO, PK type, and Filter Input DTO
    • AsyncCrudAppService<Commitment, CommitmentDto, Guid, CommitmentFilterInput, CommitmentDto> where are defined the Entity, its default DTO, PK type, Filter Input DTO and Creation Entity DTO
    • AsyncCrudAppService<Commitment, CommitmentDto, Guid, CommitmentFilterInput, CommitmentDto, CommitmentDto> where are defined the Entity, its default DTO, PK type, Filter Input DTO, Creation Entity DTO and Update Entity DTO

Same result.

  1. Use other AsyncCrudAppService implementations

    • AsyncCrudAppService<Commitment, CommitmentDto, Guid>where are defined the Entity, its DTO and PK type
    • AsyncCrudAppService<Commitment, CommitmentDto, Guid, CommitmentFilterInput> where are defined the Entity, its default DTO, PK type, and Filter Input DTO
    • AsyncCrudAppService<Commitment, CommitmentDto, Guid, CommitmentFilterInput, CreateCommitmentDto> where are defined the Entity, its default DTO, PK type, Filter Input DTO and Creation Entity DTO
    • AsyncCrudAppService<Commitment, CommitmentDto, Guid, CommitmentFilterInput, CreateCommitmentDto, UpdateCommitmentDto> where are defined the Entity, its default DTO, PK type, Filter Input DTO, Creation Entity DTO and Update Entity DTO

Same result.

  1. Use editor to validate

Swagger (OpenApi, I know...) provides an online editor at https://editor.swagger.io/

I've copied swagger.json and pasted it in editor. I've some errors about Semantic (I think this is caused by the conversion from Json to Yaml).

Semantic error at paths./api/services/app/Foo/GetAll.get.responses.200.schema.$ref $ref values must be RFC3986-compliant percent-encoded URIs Jump to line 234

Semantic error at paths./api/services/app/Foo/GetAll.get.security.0.0 Security scope definition Funds.BankAccounts could not be resolved Jump to line 240

I've no special error for CommitmentAppService. I can expand all items except Commitment methods... Browser crashes, blah blah blah

  1. Rename Commitment to Toto

  2. Remove a few methods to verify that the number of APIs was not too large for Swagger

  3. Import swagger.json in an Azure API Management I can expand all methods, even Commitment methods... But I don't know how to use my database (and isn't my objective, I wish to debug locally).

  4. Clean constructor... Maybe one of my injected items is wrong?

public CommitmentAppService(IRepository<Commitment, Guid> repository) 
: base(repository)
{ /**/ }

Nope...


If anyone has a solution...


Solution

  • It's all my fault!

    I need to add Commitment and its Dtos code to understand where I made my mistake...

    [Table("Commitment")]
    public class Commitment : FullAuditedEntity<Guid>, 
    {
        public string Property1 { get; set; }
        public Foo Foo { get; set; }
        public Guid FooId { get; set; }
    }
    
    [AutoMapFrom(typeof(Commitment))]
    [AutoMapTo(typeof(Commitment), MemberList = AutoMapper.MemberList.Source)]
    public class CommitmentDto : EntityDto<Guid>
    {
        public string Property1 { get; set; }
        public Foo Foo { get; set; }
        public Guid FooId { get; set; }
    }
    

    I've use entity objects in CommitmentDto instead of Dtos... Indeed, I need to use FooDto (instead of Foo) in CommitmentDto.