Refit: [BUG] AddRefitClient non-generic version does not register service

Created on 12 Sep 2019  路  6Comments  路  Source: reactiveui/refit

Describe the bug

When registering the refit client with the HttpClientFactoryExtensions using the method overload that takes in a runtime type (i.e. services.AddRefitClient(myInterfaceType, settings)), the service is not registered as it is with the generic version. This is due to it missing the line services.AddSingleton(provider => RequestBuilder.ForType(refitInterfaceType, settings)); similar to the way it does it in the first line of the generic method, located here.

Steps To Reproduce

  1. Create standard Refit interface, i.e. IMyApi
  2. Create a .net core web API
  3. In Startup.ConfigureServices, get a Type for your interface type and call the broken AddRefitClient method:
var refitInterfaceType = typeof(IMyApi);
services.AddRefitClient(refitInterfaceType);
  1. In a controller, inject the IMyApi and attempt to use it in an endpoint:
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
  private readonly IMyApi _api;
  public ValuesController(IMyApi api)
  {
    _api = api;
  }

  // GET api/values
  [HttpGet]
  public ActionResult<IEnumerable<string>> Get()
  {
    _api.GetThing();
    return new string[] { "value1", "value2" };
  }
}
  1. Navigate to route and receive error like InvalidOperationException: Unable to resolve service for type 'IMyApi' while attempting to activate 'test_api.Controllers.ValuesController'.
  2. Note: follow steps 1-4 and use the generic version to register the API and it will work:
    services.AddRefitClient<IMyApi>();

Expected behavior

It is expected that adding the refit client with the runtime type will act the same as adding it with the generic type.

Environment

  • OS: Windows 10
  • Version: 4.7.9
  • Device: Desktop
bug

Most helpful comment

We had a similar problem, refit tried to register all the typeclient under the same name, so the DI container was throwing exception (this type is already registred...). We created this workaround :

public static class IServiceCollectionExtension
    {
        public static IServiceCollection AddRestServiceClient(this IServiceCollection services, Type type, Action<IServiceProvider, HttpClient> clientFactory)
        {
            services.AddHttpClient(type.FullName, clientFactory)
                .Services.AddTransient(type, services =>
                {
                    var httpClientFactory = services.GetRequiredService<IHttpClientFactory>();
                    var httpClient = httpClientFactory.CreateClient(type.FullName);
                    return Refit.RestService.For(type, httpClient);
                });

            return services;
        }

        public static IServiceCollection AddRestServiceClient(this IServiceCollection services, Type type, Action<HttpClient> clientFactory)
        {
            return AddRestServiceClient(services, type, (serviceProvider, client) => clientFactory(client));
        }
    }

I think the problem seem to be around the UniqueName.ForType

All 6 comments

It looks like a bug.
https://github.com/reactiveui/refit/blob/master/Refit.HttpClientFactory/HttpClientFactoryExtensions.cs

You can do PR with tests.

GitHub
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. - reactiveui/refit

I also got this problem.here is my solution.

  1. Because of the IHttpClientBuilder don't have a matched method.

```c#
public static IHttpClientBuilder AddTypedClient(this IHttpClientBuilder builder, Type type, Func factory)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}

        if (factory == null)
        {
            throw new ArgumentNullException(nameof(factory));
        }

        builder.Services.AddTransient(type, s =>
        {
            var httpClientFactory = s.GetRequiredService<IHttpClientFactory>();
            var httpClient = httpClientFactory.CreateClient(builder.Name);

            return factory(httpClient, s);
        });

        return builder;
    }

2. Add a new AddRefitClient method
```c# 
public static IHttpClientBuilder AddRefitClient(this IServiceCollection services, Type refitInterfaceType, RefitSettings settings = null)
        {
            return services.AddHttpClient(UniqueName.ForType(refitInterfaceType))
                           .AddTypedClient(refitInterfaceType, (client, serviceProvider) => RestService.For(refitInterfaceType, client, settings));
        }

We had a similar problem, refit tried to register all the typeclient under the same name, so the DI container was throwing exception (this type is already registred...). We created this workaround :

public static class IServiceCollectionExtension
    {
        public static IServiceCollection AddRestServiceClient(this IServiceCollection services, Type type, Action<IServiceProvider, HttpClient> clientFactory)
        {
            services.AddHttpClient(type.FullName, clientFactory)
                .Services.AddTransient(type, services =>
                {
                    var httpClientFactory = services.GetRequiredService<IHttpClientFactory>();
                    var httpClient = httpClientFactory.CreateClient(type.FullName);
                    return Refit.RestService.For(type, httpClient);
                });

            return services;
        }

        public static IServiceCollection AddRestServiceClient(this IServiceCollection services, Type type, Action<HttpClient> clientFactory)
        {
            return AddRestServiceClient(services, type, (serviceProvider, client) => clientFactory(client));
        }
    }

I think the problem seem to be around the UniqueName.ForType

+1 me too.

is it released?

Closing due to age. Please try Refit v6 and reopen if still an issue.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

AnjaliSahu51 picture AnjaliSahu51  路  4Comments

jstafford5380 picture jstafford5380  路  4Comments

ahmedalejo picture ahmedalejo  路  6Comments

omares picture omares  路  6Comments

sahinyyurt picture sahinyyurt  路  5Comments