Search code examples
c#asp.net-web-api

Server 500 error when Dto class name exists in two separate DtoModels folders


I have an odd error. I'm testing a C# Web API application. The structure for the controllers is the following:

-US (FOLDER) -> UsersController.cs
-EU (FOLDER) -> UsersController.cs

Then I have a DtoModels folder for both separate regions. Like this - DtoModels:

   -US (FOLDER) -> Users (FOLDER) -> UserDto.cs
   -EU (FOLDER) -> Users (FOLDER) -> UserDto.cs

Then I have simple endpoint in both controllers like this:

[HttpPost("AddUser")]
public async Task<IActionResult> AddUser(UserDto data)
{
        try
        {
            if (data is not null)
            {
                await _usersService.CreateUser(new Models.EU.User() { Name = data.Name, Email = data.Email });

                return Ok();
            }
            else
            {
                return BadRequest();
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);

            return BadRequest();
        }
}

I include the namespace to each controller.

Controllers -> US -> UsersController.cs

using WebApplication1.DtoModels.US.Users;


Controllers -> EU -> UsersController.cs

using WebApplication1.DtoModels.EU.Users;

Even the namespace is clearly set, my application is crashing, to be specific is throwing error 500.

However, if I use the namespace of US to EU controller like:

using WebApplication1.DtoModels.US.Users;

Then the application is working, which is kind of odd. I tried directly to include the namespace as:

  public async Task<IActionResult> AddUser(DtoModels.EU.Users.UserDto data)

but it didn't help.

Note: I would like to keep those dto's separate.

Any hint how can I solve this?


Solution

  • It is because Swagger registers models with SchemaId set to class name by default.

    To work around that, you need to specify custom generation of SchemaIds.

    In your case the simpliest solution would be to call:

    builder.Services.AddSwaggerGen(options => 
        options.CustomSchemaIds(type => type.FullName));
    

    This would remove ambiguity by using fullname of a type (so namespace included).

    UPDATE

    Minimal example using minimal APIs:

    var builder = WebApplication.CreateBuilder(args);
    
    builder.Services.AddEndpointsApiExplorer();
    builder.Services.AddSwaggerGen(options => options.CustomSchemaIds(type => type.FullName));
    
    var app = builder.Build();
    
    if (app.Environment.IsDevelopment())
    {
        app.UseSwagger();
        app.UseSwaggerUI();
    }
    
    app.UseHttpsRedirection();
    
    // Note different namespaces of the User type.
    app.MapGet("/get-us-user", () => new testprojects.US.User()).WithOpenApi();
    app.MapGet("/get-eu-user", () => new testprojects.EU.User()).WithOpenApi();
    
    app.Run();
    

    UPDATE

    Removing Swagger altogether is also an option. The error will go away together with it.