aspnetcore icon indicating copy to clipboard operation
aspnetcore copied to clipboard

Exception when multiple OpenAPI services refrences is added in Visual Studio 2019 (swagger endpoints)

Open vsfeedback opened this issue 5 years ago • 13 comments

This issue has been moved from a ticket on Developer Community.


I try to use the service reference OpenAPI in Visual Studio 2019, to generate clients based on existing swagger endpoints. It works fine when one endpoint is added, but multiple endpoints in different namespaces does not work. The reason is that the autogenerated APIException class is only generated in in the first "OpenApiReference". I tried to set the option "generateExceptionClasses" but it didn't have any effect. Also tried to give the exception different names with the option "exceptionClass", but the exception class was only created in the first client.

This is the code that fails:

  <ItemGroup>
    <OpenApiReference Include="OpenAPIs\api1Swagger.json" CodeGenerator="NSwagCSharp" Namespace="API1">
      <SourceUri>https://api1/swagger/v1/swagger.json</SourceUri>
      <ClassName>{controller}Client</ClassName>
      <OutputPath>API1Client.cs</OutputPath>
    </OpenApiReference>
    <OpenApiReference Include="OpenAPIs\api2Swagger.json" CodeGenerator="NSwagCSharp" Namespace="API2">
      <SourceUri>https://api2/swagger/v1/swagger.json</SourceUri>
      <ClassName>{controller}Client</ClassName>
      <OutputPath>API2Client.cs</OutputPath>
    </OpenApiReference>
  </ItemGroup>

It's possible to solve the problem with the following code, but I don't like to reference to API1 in API2:

  <ItemGroup>
    <OpenApiReference Include="OpenAPIs\api1Swagger.json" CodeGenerator="NSwagCSharp" Namespace="API1">
      <SourceUri>https://api1/swagger/v1/swagger.json</SourceUri>
      <ClassName>{controller}Client</ClassName>
      <OutputPath>API1Client.cs</OutputPath>
    </OpenApiReference>
    <OpenApiReference Include="OpenAPIs\api2Swagger.json" CodeGenerator="NSwagCSharp" Namespace="API2">
      <SourceUri>https://api2/swagger/v1/swagger.json</SourceUri>
      <ClassName>{controller}Client</ClassName>
      <OutputPath>API2Client.cs</OutputPath>
      <Options>/ExceptionClass:"API1. ApiException"</Options>
    </OpenApiReference>
  </ItemGroup>

Any way to slove this?


Original Comments

Visual Studio Feedback System on 12/5/2019, 00:01 AM:

We have directed your feedback to the appropriate engineering team for further evaluation. The team will review the feedback and notify you about the next steps.

Visual Studio Feedback System on 12/6/2019, 01:28 AM:

Thank you for sharing your feedback! Our teams prioritize action on product issues with broad customer impact. See details at: https://docs.microsoft.com/en-us/visualstudio/ide/report-a-problem?view=vs-2017#faq. In case you need answers to common questions or need assisted support, be sure to use https://visualstudio.microsoft.com/vs/support/. We’ll keep you posted on any updates to this feedback.


Original Solutions

(no solutions)

vsfeedback avatar Jan 08 '20 19:01 vsfeedback

Move ApiException and ApiException<TResult> to their own namespace

namespace Company.Api.Exceptions
{
  public partial class ApiException : System.Exception
  {
    ...
  }
  public partial class ApiException<TResult> : ApiException
  {
    ...
  }
}

Modify your csproj file OpenApiReference elements to include <Options>/AdditionalNamespaceUsages:Ent.Api.Exceptions /GenerateExceptionClasses:false</Options>

<ItemGroup>
    <OpenApiReference Include="OpenAPIs\api1Swagger.json" CodeGenerator="NSwagCSharp" Namespace="API1">
      <SourceUri>https://api1/swagger/v1/swagger.json</SourceUri>
      <ClassName>{controller}Client</ClassName>
      <OutputPath>API1Client.cs</OutputPath>
      <Options>/AdditionalNamespaceUsages:Ent.Api.Exceptions /GenerateExceptionClasses:false</Options>
    </OpenApiReference>
    <OpenApiReference Include="OpenAPIs\api2Swagger.json" CodeGenerator="NSwagCSharp" Namespace="API2">
      <SourceUri>https://api2/swagger/v1/swagger.json</SourceUri>
      <ClassName>{controller}Client</ClassName>
      <OutputPath>API2Client.cs</OutputPath>
      <Options>/AdditionalNamespaceUsages:Ent.Api.Exceptions /GenerateExceptionClasses:false</Options>
    </OpenApiReference>
  </ItemGroup>

jeremysimmons avatar Mar 30 '20 22:03 jeremysimmons

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

mkArtakMSFT avatar Jun 16 '20 20:06 mkArtakMSFT

The ApiException error exists when generating two schemas: The type or namespace name 'ApiException<>' could not be found (are you missing a using directive or an assembly reference?)

When will it be fixed?

cloud-devlpr avatar Aug 05 '21 19:08 cloud-devlpr

Un-assigning myself as I'm no longer on that team. @mkArtakMSFT to triage this.

ryanbrandenburg avatar Aug 12 '21 21:08 ryanbrandenburg

It would definitely be nice if this was fixed in a foreseeable future

jabak avatar Sep 27 '21 14:09 jabak

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

ghost avatar Oct 22 '21 00:10 ghost

Move ApiException and ApiException<TResult> to their own namespace

namespace Company.Api.Exceptions
{
  public partial class ApiException : System.Exception
  {
    ...
  }
  public partial class ApiException<TResult> : ApiException
  {
    ...
  }
}

Modify your csproj file OpenApiReference elements to include <Options>/AdditionalNamespaceUsages:Ent.Api.Exceptions /GenerateExceptionClasses:false</Options>

<ItemGroup>
    <OpenApiReference Include="OpenAPIs\api1Swagger.json" CodeGenerator="NSwagCSharp" Namespace="API1">
      <SourceUri>https://api1/swagger/v1/swagger.json</SourceUri>
      <ClassName>{controller}Client</ClassName>
      <OutputPath>API1Client.cs</OutputPath>
      <Options>/AdditionalNamespaceUsages:Ent.Api.Exceptions /GenerateExceptionClasses:false</Options>
    </OpenApiReference>
    <OpenApiReference Include="OpenAPIs\api2Swagger.json" CodeGenerator="NSwagCSharp" Namespace="API2">
      <SourceUri>https://api2/swagger/v1/swagger.json</SourceUri>
      <ClassName>{controller}Client</ClassName>
      <OutputPath>API2Client.cs</OutputPath>
      <Options>/AdditionalNamespaceUsages:Ent.Api.Exceptions /GenerateExceptionClasses:false</Options>
    </OpenApiReference>
  </ItemGroup>

I am running into this problem also when having greater than 2 OpenAPI specs in a single Project. I have them configured to use different Namespaces and different client names same

The above work around does work which gets me by for now but I would hope this gets resolved at some point.

mwolford avatar Nov 17 '21 19:11 mwolford

Modify your csproj file OpenApiReference elements to include <Options>/AdditionalNamespaceUsages:Ent.Api.Exceptions /GenerateExceptionClasses:false</Options>

Apparently the order is also important, it has to be at the beginning of the options element, e.g:

<Options>/AdditionalNamespaceUsages:Buddy.App.Services.OpenAPIs /GenerateExceptionClasses:false /UseBaseUrl:false /GenerateClientInterfaces:true /DateType:System.DateTime /DateTimeType:System.DateTime</Options>

I wasted a lot of time trying to understand why it doesn't add additional namespace

nZeus avatar Feb 09 '22 21:02 nZeus

Move ApiException and ApiException<TResult> to their own namespace

namespace Company.Api.Exceptions
{
  public partial class ApiException : System.Exception
  {
    ...
  }
  public partial class ApiException<TResult> : ApiException
  {
    ...
  }
}

Modify your csproj file OpenApiReference elements to include <Options>/AdditionalNamespaceUsages:Ent.Api.Exceptions /GenerateExceptionClasses:false</Options>

<ItemGroup>
    <OpenApiReference Include="OpenAPIs\api1Swagger.json" CodeGenerator="NSwagCSharp" Namespace="API1">
      <SourceUri>https://api1/swagger/v1/swagger.json</SourceUri>
      <ClassName>{controller}Client</ClassName>
      <OutputPath>API1Client.cs</OutputPath>
      <Options>/AdditionalNamespaceUsages:Ent.Api.Exceptions /GenerateExceptionClasses:false</Options>
    </OpenApiReference>
    <OpenApiReference Include="OpenAPIs\api2Swagger.json" CodeGenerator="NSwagCSharp" Namespace="API2">
      <SourceUri>https://api2/swagger/v1/swagger.json</SourceUri>
      <ClassName>{controller}Client</ClassName>
      <OutputPath>API2Client.cs</OutputPath>
      <Options>/AdditionalNamespaceUsages:Ent.Api.Exceptions /GenerateExceptionClasses:false</Options>
    </OpenApiReference>
  </ItemGroup>

That fixed it for me as well but I also think that this can't be the solution... It should be fixed properly since this issues persists since more than two years now...

Modify your csproj file OpenApiReference elements to include <Options>/AdditionalNamespaceUsages:Ent.Api.Exceptions /GenerateExceptionClasses:false</Options>

Apparently the order is also important, it has to be at the beginning of the options element, e.g:

<Options>/AdditionalNamespaceUsages:Buddy.App.Services.OpenAPIs /GenerateExceptionClasses:false /UseBaseUrl:false /GenerateClientInterfaces:true /DateType:System.DateTime /DateTimeType:System.DateTime</Options>

I wasted a lot of time trying to understand why it doesn't add additional namespace

For me the order didn't matter. I placed it at the end and it also worked.

jbTim avatar Mar 04 '22 12:03 jbTim

Hi Team.

This really is quite a big issue for users.

The case for a microservice referencing more than one other microservice is very common, so a lot of people will encounter this (myself included).

Please can you re-triage it with this in mind?

JsAndDotNet avatar Aug 18 '22 06:08 JsAndDotNet

Move ApiException and ApiException<TResult> to their own namespace

namespace Company.Api.Exceptions
{
  public partial class ApiException : System.Exception
  {
    ...
  }
  public partial class ApiException<TResult> : ApiException
  {
    ...
  }
}

Modify your csproj file OpenApiReference elements to include <Options>/AdditionalNamespaceUsages:Ent.Api.Exceptions /GenerateExceptionClasses:false</Options>

<ItemGroup>
    <OpenApiReference Include="OpenAPIs\api1Swagger.json" CodeGenerator="NSwagCSharp" Namespace="API1">
      <SourceUri>https://api1/swagger/v1/swagger.json</SourceUri>
      <ClassName>{controller}Client</ClassName>
      <OutputPath>API1Client.cs</OutputPath>
      <Options>/AdditionalNamespaceUsages:Ent.Api.Exceptions /GenerateExceptionClasses:false</Options>
    </OpenApiReference>
    <OpenApiReference Include="OpenAPIs\api2Swagger.json" CodeGenerator="NSwagCSharp" Namespace="API2">
      <SourceUri>https://api2/swagger/v1/swagger.json</SourceUri>
      <ClassName>{controller}Client</ClassName>
      <OutputPath>API2Client.cs</OutputPath>
      <Options>/AdditionalNamespaceUsages:Ent.Api.Exceptions /GenerateExceptionClasses:false</Options>
    </OpenApiReference>
  </ItemGroup>

I had to create a different Exception class to get this to work:

namespace MyApp.OpenApi.Exceptions
{
    /// <summary>
    /// This is a fudge to get by for now
    /// https://github.com/dotnet/aspnetcore/issues/18204
    /// </summary>
    public partial class ApiException : System.Exception
    {
        public ApiException(string message, int statusCode, string? responseText, IReadOnlyDictionary<string, IEnumerable<string>> headers, Newtonsoft.Json.JsonException exception)
        {

        }
    }
    public partial class ApiException<TResult> : ApiException
    {
        public ApiException(string message, int statusCode, string? responseText, IReadOnlyDictionary<string, IEnumerable<string>> headers, Newtonsoft.Json.JsonException exception)
            : base(message, statusCode, responseText, headers, exception)
        {

        }
    }
}

Also note that /AdditionalNamespaceUsages:Ent.Api.Exceptions, the Ent.Api.Exceptions is not a copy and paster - you need to use your own namspace for the class you've created e.g. MyApp.OpenApi.Exceptions.

JsAndDotNet avatar Aug 18 '22 07:08 JsAndDotNet

IM baffled, this should be prioritized???

filipreft avatar Dec 24 '23 00:12 filipreft

2024 and this is still an issue.

Kingcuber avatar Mar 14 '24 11:03 Kingcuber

I saw this today

werebear73-tritelph avatar Mar 26 '24 15:03 werebear73-tritelph

I am amazed how this is possible, that it is ignored and nobody solves it. Multiple connected OpenApiReferences are refferencing the namespace of the first one; if it is swagger 2.0. Which is a horrible solution. And when it is openapi 3.0 it breaks completely between each other.

I had to also have those options in the first place of the OpenApiReference Options, it was not working otherwise. I am shocked.

krtek2k avatar Jul 08 '24 04:07 krtek2k

There is a good write-up here on how to make this work (assuming you have an up-to-date NSwag): https://github.com/RicoSuter/NSwag/issues/4938#issuecomment-2236419139

mus65 avatar Jul 18 '24 13:07 mus65

cool, so basically "Example 3: Every client gets its own generated ApiException class (in different namespaces)." should be the case. And this is a MUST when you are using a different namespaces.

krtek2k avatar Jul 18 '24 21:07 krtek2k