Search code examples
c#genericsswagger-uiswashbuckleswashbuckle.aspnetcore

How to resolve Swashbuckle/Swagger -UI model naming issue for generics?


I want to clean the names of the models in the swagger ui for my webapi.

The issue is that when I define a response type on my endpoint, and that type is a generic, it gets named in such a way that if one were to use a swagger-gen tool like NSwag, the models gets the worst names, (as they're based on the swagger, I'd like to define how the model is named).

This is the response attribute:

[ProducesResponseType(typeof(BulkUpsertResponse<AccountingCode>), StatusCodes.Status200OK)]

This is the resultant name: Company.IntegrationApi.Api.Models.Responses.BulkUpsertResponse1[[Company.IntegrationApi.Api.Models.AccountingParameters.AccountingCode, Company.IntegrationApi.Api, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]

What NSwag makes it to be: BulkUpsertResponse_1OfOfAccountingCodeAndApiAnd_0AndCulture_neutralAndPublicKeyToken_null

What i'd like the name to be is: BulkUpsertResponse<AccountingCode>

I've tried to find an attribute or tag to define the name, and it's not feasable to make the generics into "hard types" as it's hundreads of uses.

How can I specify the name exactly, or what work-arounds can I use to solve my issue?


Solution

  • This worked for me as the FriendlyId method doesn't seem to exist anymore in current Swagger:

    c.CustomSchemaIds(i => i.FriendlyId(true)); (same as daveBM's answer)

    Then this:

    public static string FriendlyId(this Type type, bool fullyQualified = false)
        {
            var typeName = fullyQualified
                ? type.FullNameSansTypeArguments().Replace("+", ".")
                : type.Name;
    
            if (!type.GetTypeInfo().IsGenericType)
            {
                return typeName;
            }
    
            var genericArgumentIds = type.GetGenericArguments()
                .Select(t => t.FriendlyId(fullyQualified))
                .ToArray();
    
            return new StringBuilder(typeName)
                .Replace(string.Format("`{0}", genericArgumentIds.Count()), string.Empty)
                .Append(string.Format("[{0}]", string.Join(",", genericArgumentIds).TrimEnd(',')))
                .ToString();
        }
    
    
    private static string FullNameSansTypeArguments(this Type type)
    {
        if (string.IsNullOrEmpty(type.FullName))
        {
            return string.Empty;
        }
    
        var fullName = type.FullName;
        var chopIndex = fullName.IndexOf("[[");
        return chopIndex == -1 ? fullName : fullName.Substring(0, chopIndex);
    }