12

I am investigating the refit library and evaluating if I is worth integrating in my project.

Let's say I have this Controller that accepts a POST message with a specific contract:

[Route("api/[controller]")]
[ApiController]
public class KeepAliveController : ControllerBase
{
    [HttpPost]
    public IActionResult Post(KeepAliveContract keepAliveContract)
    {
        // 
    }
}

From what I understand from the refit documentation, I have to create an interface. Let's call it IKeepAliveService. It would look like this:

public interface IKeepAliveService
{
    [Post("api/keepalive")]
    Task SendKeepAliveAsync(KeepAliveContract keepAliveContract);
}

This way of doing things lead to potential runtime errors, if I mess up the route in the PostAttribute or in the signature itself.

Question

Is there a way to automatically generate this interface out of the existing controllers and, as such reduce the risk of bugs?

Kzryzstof
  • 7,688
  • 10
  • 61
  • 108
  • I am not aware of any officai way to do this. You could make a an application which reads the output assembly of your web application and generate the interfaces based on the controllers you find in the assembly. You could use Roslyn, T4 or whatever you like to generate the interfaces. – Georgi Georgiev Dec 04 '18 at 06:43
  • 3
    I usually make a T4 template to generate API's with the specific contracts that are usually different for each project that I work on. Then I make a test that will fail if there are any mismatches, and then I have an end2end test that goes through all my controllers for verification before release. – Archlight Dec 04 '18 at 11:27
  • On addition to what @Archlight stated see https://stackoverflow.com/questions/14134016/design-time-reflection/14402269#14402269 that shows a way to use Reflection in design time so you can scan your assembly, get the controller classes extract the attributes of the class and methods and build the refit interfaces – fmaccaroni Dec 05 '18 at 13:54

4 Answers4

2

You can certainly do this either by using C# 9 Source Generators or Fody IL Weaving.

but another solution would be to use a live Roslyn analyzer with a code fix on top of the Refit library and let it handle the generation of type safe clients. because instead of reinventing the wheel, why not just save time and effort and build on top of something that already exists, documented, stable and maintained like Refit rather then rolling your own implementation.

in order for the analyzer to work you have to enable routing by action name in your web api config, and also each controller has to implement its corresponding Refit interface.

// routing by action name
config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "{controller}/{action}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

what the analyzer will do is check if the route string specified in the route attribute match the method signature. if invalid routes are detected, the compiler will report compilation errors and will also provide a fix.

this way you will never have mistakes in your route string, and even if you do the compiler will instantly notify you!!

here is the code for a simple Refit route analyzer that I made so you don't have to, it does exactly what I described, I already tried it and it works great so feel free to customize it any way you want!

PS: The first rule of programming is Don't Reinvent The Wheel.

Joseph
  • 1,458
  • 15
  • 20
1

There is tool (win only) where you install it and then you could generate refit interface via cmd. https://github.com/Dreamescaper/GenerateAspNetCoreClient

valentasm
  • 2,137
  • 23
  • 24
0

I needed the same thing so I built a tool called Refitter that generates the interface and contracts from an OpenAPI specifications file.

The OpenAPI specifications file can be generated by enabling Swagger and SwaggerUI on the ASP.NET Core project

Because I'm too lazy to leave Visual Studio to generate code, I also built a Visual Studio extension called REST API Client Code Generator that allows me to just right click on the OpenAPI spec file from client systems that call the API

-3

You can simply right-click on the class name, choose custom actions from the context menu and then click on extract interface

RSadocchi
  • 72
  • 6
  • No it is not acceptable because it does not take into account the `Route` attributes of the `Controller` and transform them into the appropriate `refit` attribute (`Post`, `GET` etc). – Kzryzstof Dec 04 '18 at 18:24