Open Trokkin opened 2 years ago
+1 same issue. Using an api with a templated path generates illegal method names for C#
Example https://docs.oracle.com/en/cloud/saas/marketing/responsys-rest-api/swagger.json
Same here, especially the OData $count is a problem for me. I'm trying to fix it using a custom IOperationNameGenerator-decorator and I'll let you know if that works.
I ran into this issue while trying to generate a C# client from an API with OData endpoints. I believe this issue is related to #4002 and #4027, which has a proposed solution in #4041. I took that solution and tried to look for a way to inject this behavior instead of recompiling my own patch. If you are able to supply your own custom IOperationNameGenerator
implementation, you can supply the logic needed for legal method names:
public class CustomSingleClientFromOperationIdOperationNameGenerator : IOperationNameGenerator
{
public bool SupportsMultipleClients { get; } = true;
public virtual string GetClientName(OpenApiDocument document, string path, string httpMethod,
OpenApiOperation operation)
{
return string.Empty;
}
public virtual string GetOperationName(OpenApiDocument document, string path, string httpMethod,
OpenApiOperation operation)
{
// remove unwanted symbols
var operationName = Regex.Replace(operation.OperationId, @"(?:[^\w\.-]+(\w?))",
match => match.Groups[1].ToString().ToUpperInvariant(), RegexOptions.None);
// capitalize all caps verbs (ie. PATCH, DELETE)
operationName = Regex.Replace(operationName, @"[A-Z]{2,}", match => Capitalize(match.ToString().ToLowerInvariant()), RegexOptions.None);
// capitalize first letter
return Capitalize(operationName);
}
private static string Capitalize(string input)
{
if (string.IsNullOrEmpty(input))
{
return string.Empty;
}
return $"{input[0].ToString().ToUpper()}{input.Substring(1)}";
}
}
I have not yet found a way to inject this using the .NET Tool or specifying in an nswag.json
config. However, I was able to create a simple console app and use NSwag.Commands
where I can inject my custom operation name generator:
var nSwagDocument = await NSwagDocument.LoadWithTransformationsAsync(path, variables);
nSwagDocument.CodeGenerators.OpenApiToCSharpClientCommand.Settings.OperationNameGenerator =
new CustomSingleClientFromOperationIdOperationNameGenerator();
var result = await nSwagDocument.ExecuteAsync();
It's not the prettiest, but gets the job done without patching anything. I think a long term solution would be to make the OperationNameGenerator extensible from the nswag.json config so that the user can supply their own criteria for name generation, rather than trying to find a hardcoded pattern that serves all needs.
Ran into the same problem with an operationId looking like that:
"/api/4.0/users/me": {
"get": {
"tags": [
"users"
],
"operationId": "Users: Me",
Resulting in
public virtual async System.Threading.Tasks.Task<UserDto_4_0> Users:_MeAsync(System.Collections.Generic.IEnumerable<string> fields, System.Threading.CancellationToken cancellationToken)
When swagger generates reference with templated paths, NSwag would not recognize the templates in the path and paste them in method names as is, like such:
->
Which would never be recognized by C# as a correct statement.
Also, in my case OData add end points like
$count
-- it's possible to filter them out of Swagger, but that won't not solve the general problem:->
Steps to reproduce:
With VS2022:
Startup.cs
, addusing Microsoft.OpenApi.Models;
and replaceservices.AddSwaggerGen();
withservices.AddSwaggerGen(c => c.SwaggerDoc("v1", new OpenApiInfo { Title = "OData 8.x OpenAPI", Version = "v1" }));
localhost:5000/swagger/v1/swagger.json
. (Both native VS variant and Unchase produce the same results)swaggerClient.cs