Consume OpenApi client .NET Core with Interface
Asked Answered
P

1

6

Someone out there must have run into this already...

I created a WebApi solution with swagger implemented, full documentation, the whole 9 yards!

  • When I run my web api solution, see the swagger output (and I've tested the endpoints, all working fine)
  • I can see the swagger definition: https://localhost:5001/swagger/v1/swagger.json

Now, I want to consume this Api as a connected service on my web app. So following every single tutorial online:

  • I go to my webapp
  • right click on Connected Services
  • Add Connected Service
  • Add Service Reference > OpenApi > add Url, namespace & class name enter image description here

That generates a partial class in my solution (MyTestApiClient)

public parial class MyTestApiClient
{
   // auto generated code
}

Next step, inject the service in Startup.cs

services.AddTransient(x =>
{
   var client = new MyTestApiClient("https://localhost:5001", new HttpClient());
   return client;
});

Then, inject the class into some class where it's consumed and this all works

public class TestService
{
    private readonly MyTestApiClient _client; // this is class, not an interface -> my problem
    public TestService(MyTestApiClient client)
    {
        _client = client;
    }

    public async Task<int> GetCountAsync()
    {
        return _client.GetCountAsync();
    }
}

So everything up to here works. BUT, this generated OpenApi client doesn't have an interface which sucks for the purposes of DI and Unit Testing.

I got around this by creating a local interface IMyTestApiClient, added to the generated class (MyTestApiClient). I only have 1 endpoint in my WebApi so have to declare that on my interface.

public parial class MyTestApiClient : IMyTestApiClient
{
   // auto generated code
}
public interface IMyTestApiClient
{
   // implemented in generated MyTestApiClient class
   Task<int> GetCountAsync();
}
services.AddTransient<IMyTestApiClient, MyTestApiClient>(x =>
{
   IMyTestApiClient client = new MyTestApiClient("https://localhost:5001", new HttpClient());
   return client;
});
public class TestService
{
    private readonly IMyTestApiClient _client; // now injecting local interface instead of the generated class - great success
    public TestService(IMyTestApiClient client)
    {
        _client = client;
    }

    public async Task<int> GetCountAsync()
    {
        return _client.GetCountAsync();
    }
}

But this is a bad approach because it makes me manually create an interface and explicitly declare the methods I want to consume. Furthermore, every time my Api gets updated, I will have to tweak my local interface.

So question time: How can I add an OpenApi Service Reference that automagically also generates an interface as well? Thanks in advance for any help getting to a viable solution.

Pressman answered 23/4, 2021 at 18:18 Comment(0)
C
8

You may have already found the answer but I had the same issue and managed to resolve it by adding /GenerateClientInterfaces:true in the Options section for the OpenAPI reference in my .csproj:

<OpenApiReference Include="api.json" CodeGenerator="NSwagCSharp" Namespace="MyNamespace" ClassName="MyClassName">
    <SourceUri>https://localhost:7040/swagger/v1/swagger.json</SourceUri>
    <OutputPath>MyClient.cs</OutputPath>
    <Options>/GenerateClientInterfaces:true</Options>
</OpenApiReference>
Comanche answered 1/12, 2021 at 13:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.