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.67k stars 745 forks source link

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

Open HamidMusayev opened 1 year ago

HamidMusayev commented 1 year 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 1 year ago

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

hansmbakker commented 4 months 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 3 months 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 3 months ago

I had this issue when using Scrutor.

Yes, we're using Scrutor too.