atc-net / atc-rest-api-generator

A REST API code generator from OpenAPI Specification in YAML or Json file format
https://atc-net.github.io/repository/atc-rest-api-generator
MIT License
19 stars 4 forks source link

Use qualified namespace for reserved type names as "Task" #102

Closed kimlundjohansen closed 3 years ago

kimlundjohansen commented 3 years ago

Describe the bug When using reserved names for contract types we need to specify the fully qualified namespace to avoid build errors.

Version 1.1.87.0

egil commented 3 years ago

More problem details:

This YAML:

openapi: 3.0.0
paths:
  '/tasks':
    get:
      summary: Get
      description: Get
      operationId: get
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Task'
components:
  schemas:
    Task:
      title: Task
      description: Task.
      type: object
      properties:
        id:
          type: string

will currently generate this controller class:

using System;
using System.CodeDom.Compiler;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using TestProject.AtcTest.Contracts.Tasks;

//------------------------------------------------------------------------------
// This code was auto-generated by ApiGenerator x.x.x.x.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
//------------------------------------------------------------------------------
namespace TestProject.AtcTest.Endpoints
{
    /// <summary>
    /// Endpoint definitions.
    /// Area: Tasks.
    /// </summary>
    [ApiController]
    [Route("/api/v1/tasks")]
    [GeneratedCode("ApiGenerator", "x.x.x.x")]
    public class TasksController : ControllerBase
    {
        /// <summary>
        /// Description: Get.
        /// Operation: Get.
        /// Area: Tasks.
        /// </summary>
        [HttpGet]
        [ProducesResponseType(typeof(Task), StatusCodes.Status200OK)]
        public Task<ActionResult> GetAsync([FromServices] IGetHandler handler, CancellationToken cancellationToken)
        {
            if (handler is null)
            {
                throw new ArgumentNullException(nameof(handler));
            }

            return InvokeGetAsync(handler, cancellationToken);
        }

        private static async Task<ActionResult> InvokeGetAsync([FromServices] IGetHandler handler, CancellationToken cancellationToken)
        {
            return await handler.ExecuteAsync(cancellationToken);
        }
    }
}

This results in a compiler error because the type Task is both in System.Threading.Tasks and in TestProject.AtcTest.Contracts.Tasks.

My proposal is to move any project specific using statements inside the namespace, making those take priority when the compiler is resolving the ambiguity.

using System;
using System.CodeDom.Compiler;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
-using TestProject.AtcTest.Contracts.Tasks;

//------------------------------------------------------------------------------
// This code was auto-generated by ApiGenerator x.x.x.x.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
//------------------------------------------------------------------------------
namespace TestProject.AtcTest.Endpoints
{
+    using TestProject.AtcTest.Contracts.Tasks;

    /// <summary>
    /// Endpoint definitions.
    /// Area: Tasks.
    /// </summary>
    [ApiController]
    [Route("/api/v1/tasks")]
    [GeneratedCode("ApiGenerator", "x.x.x.x")]
    public class TasksController : ControllerBase
    {
        /// <summary>
        /// Description: Get.
        /// Operation: Get.
        /// Area: Tasks.
        /// </summary>
        [HttpGet]
        [ProducesResponseType(typeof(Task), StatusCodes.Status200OK)]
        public Task<ActionResult> GetAsync([FromServices] IGetHandler handler, CancellationToken cancellationToken)
        {
            if (handler is null)
            {
                throw new ArgumentNullException(nameof(handler));
            }

            return InvokeGetAsync(handler, cancellationToken);
        }

        private static async Task<ActionResult> InvokeGetAsync([FromServices] IGetHandler handler, CancellationToken cancellationToken)
        {
            return await handler.ExecuteAsync(cancellationToken);
        }
    }
}