reactiveui / refit

The automatic type-safe REST library for .NET Core, Xamarin and .NET. Heavily inspired by Square's Retrofit library, Refit turns your REST API into a live interface.
https://reactiveui.github.io/refit/
MIT License
8.46k stars 745 forks source link

[Bug]: Refit.IRequestBuilder Dependency Injection Throws Exception #1583

Open HamidMusayev opened 11 months ago

HamidMusayev commented 11 months ago

Refit.IRequestBuilder dependency injection exception 🐞

Interface

public interface IPetStoreClient
{
    [Post("/store/order")]
    Task<Order> PlaceOrder([Body] Order body);

    [Get("/store/order/{orderId}")]
    Task<Order> GetOrderById(long orderId);

    [Delete("/store/order/{orderId}")]
    Task DeleteOrder(long orderId);
}

Exception An unhandled exception of type 'System.AggregateException' occurred in Microsoft.Extensions.DependencyInjection.dll: 'Some services are not able to be constructed' Inner exceptions found, see $exception in variables window for more details. Innermost exception System.InvalidOperationException : Unable to resolve service for type 'Refit.IRequestBuilder' while attempting to activate 'Refit.Implementation.Generated+BLLExternalClientsIPetStoreClient'.

Injection

builder.Services
            .AddRefitClient<IPetStoreClient>()
            .ConfigureHttpClient(c => c.BaseAddress = new Uri(config.PetStoreClientSettings.BaseUrl));

Usage

public class HelperController : Controller
{
    private readonly IPetStoreClient _petStoreClient;

    public HelperController(IPetStoreClient petStoreClient)
    {
        _petStoreClient = petStoreClient;
    }

    [HttpGet("test")]
    public async Task<IActionResult> Get()
    {
        var response = await _petStoreClient.GetOrderById(24);
        return Ok(response);
    }
}

Note 1 Same error when creating inside constructor

public class TestController : Controller
{
    private readonly IPetStoreClient _petStoreClient;

    public HelperController(ConfigSettings configSettings)
    {
        _petStoreClient = RestService.For<IPetStoreClient>(configSettings.PetStoreClientSettings.BaseUrl);
    }

Note 2 Same error when creating instance

[HttpGet("test")]
    public async Task<IActionResult> Get()
    {
        var client = RestService.For<IPetStoreClient>(_configSettings.PetStoreClientSettings.BaseUrl);
        var response = await client.GetOrderById(24);

        return Ok(response);
    }

Step to reproduce

Refit.HttpClientFactory v7.0.0 Refit v7.0.0

Reproduction repository

https://github.com/reactiveui/refit

Expected behavior

Dependency injection IRequestBuilder exception

Screenshots 🖼️

No response

IDE

Visual Studio 2022, Rider Windows, Visual Studio Code

Operating system

Windows

Version

No response

Device

No response

Refit Version

7.0.0

Additional information ℹ️

null

HamidMusayev commented 10 months ago

Update: Moving refit interfaces to another project inside solution fixes the bug

hansmbakker commented 1 month ago

Update: Moving refit interfaces to another project inside solution fixes the bug

@HamidMusayev could you please explain further what made it work? I have the same issue and wonder what the requirement is for the project that should contain the interfaces?

radupurdea commented 1 month ago

I had this issue when using Scrutor. If you are registering dependencies by automatically scanning the assembly, be sure to exclude your refit interface, in your case IPetStoreClient.

Potential cause: .net will validate the dependencies registered can be resolved on application start, meaning your refit interfaces (like IRequestBuilder) have no implementations registered, causing the above exception.

hansmbakker commented 1 month ago

I had this issue when using Scrutor.

Yes, we're using Scrutor too.