NSwag namespace in model names

Viewed 4764

It's possible to generate client code so that model's class names have full namespaces as prefix?

That should avoid same class name conflicts.

Example

com.foo.MyClass 

and

it.foo.MyClass

Up to now what I got is MyClass and MyClass2 that's not so much meaningful.

Should be better to have, in case of name collision, ComFooMyClass and ItFooMyClass.

5 Answers

Let me update shadowsheep's answer for a more recent version of NSwag:

services.AddSwaggerDocument(cfg => { cfg.SchemaNameGenerator = new CustomSchemaNameGenerator(); });

With:

internal class CustomSchemaNameGenerator : ISchemaNameGenerator
{
    public string Generate(Type type)
    {
        return type.FullName.Replace(".", "_");
    }
}

Updated for NSwag.AspNetCore as of v13.15.10 based on @shadowsheep answer.

The extension method UseSwaggerUi has been deprecated and we should now use UseSwaggerUi3. This method does not provides you with a way to set your custom instance of ISchemaNameGenerator, instead you set this at service registration time as follows:

services.AddOpenApiDocument(configure => {
    configure.SchemaNameGenerator = new CustomSchemaNameGenerator();
});

For completeness I'm leaving CustomSchemaNameGenerator below:

class CustomSchemaNameGenerator : NJsonSchema.Generation.ISchemaNameGenerator
{
    public string Generate(Type type) => type.FullName.Replace(".", "_");
}

To generate full namespace. You need to setup API to return swagger with full namespace

services.AddSwaggerGen(c =>
{
    ...  //any lines you aready have 
    c.CustomSchemaIds((type) => type.FullName); //show full namespace
}

You can't generate a client via NSwagStudio, you need to do via code with this solution https://stackoverflow.com/a/45311657/1818723

And here is ready code to generate client via own code

using NJsonSchema;
using NSwag;
using NSwag.CodeGeneration.CSharp;
using NSwag.CodeGeneration.OperationNameGenerators;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Threading.Tasks;

...

public async Task<string> GetClientCode(string swaggerUrl, CSharpClientGeneratorSettings settings)
{
    settings.OperationNameGenerator = new SingleClientFromOperationIdOperationNameGenerator();
    settings.CSharpGeneratorSettings.TypeNameGenerator = new MyTypeNameGenerator();
    var swagger = await GetAsync(swaggerUrl);
    var document = await OpenApiDocument.FromJsonAsync(swagger);
    var codeGen = new CSharpClientGenerator(document, settings);

    var code = codeGen.GenerateFile();
    return code;
}

public class MyTypeNameGenerator : ITypeNameGenerator
{
    public string Generate(JsonSchema schema, string typeNameHint, IEnumerable<string> reservedTypeNames)
    {
        if (typeNameHint == null && schema.IsEnumeration && schema.Title != null)
                return schema.Title; //for method argument when expected type is IEnumerable<Enum> (swagger definition must contain title - see last link) 

        return typeNameHint;   //this contains full namespace (assuming returned in swagger definition)
    }
}

private async Task<string> GetAsync(string uri)
{
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
    request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;

    using (HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync())
    using (Stream stream = response.GetResponseStream())
    using (StreamReader reader = new StreamReader(stream))
    {
        return await reader.ReadToEndAsync();
    }
}

here about enum title

https://github.com/RicoSuter/NSwag/issues/2103#issuecomment-853965927

Related