refit icon indicating copy to clipboard operation
refit copied to clipboard

[BUG] Refit does not recognize generated interface

Open PontusMagnusson opened this issue 2 years ago • 4 comments

Describe the bug

We've been playing around with generating Refit interfaces using the CodeAnalyzer and so far we've been able to generate an interface that, to us, looks like an interface that Refit would accept. However, we've been unable to register it with Refit since we only get the exception below.

Unhandled Exception: System.InvalidOperationException: ISetAPIClient doesn't look like a Refit interface. Make sure it has at least one method with a Refit HTTP method attribute and Refit is installed in the project.
   at Refit.RestService.GetGeneratedType(Type refitInterfaceType) in /_/Refit/RestService.cs:line 173
   at Refit.RestService.For(Type refitInterfaceType, HttpClient client, IRequestBuilder builder) in /_/Refit/RestService.cs:line 76
   at Refit.RestService.For[T](HttpClient client, IRequestBuilder`1 builder) in /_/Refit/RestService.cs:line 20
   at Customer.WebServices.API.Client.ClientBase.DoStuff() in C:\projects\customer\Customer.Webservices.Backend\generated\Customer.WebServices.API.Client\ClientBase.cs:line 19
   at Customer.WebServices.API.Client.ClientBase.Main() in C:\projects\customer\Customer.Webservices.Backend\generated\Customer.WebServices.API.Client\ClientBase.cs:line 12

The interface gets generated at build time and published as a NuGet package, and looks like the following:

Generated file

// This files was auto-generated. Do not modify this file

 namespace Customer.WebServices.API.Client
{
    public interface ISetAPIClient
    {
        [Refit.Get("/Sets")]
        System.Threading.Tasks.Task<System.Collections.Generic.IEnumerable<Customer.Webservices.Core.Models.Set>> GetSets();
        [Refit.Get("/Sets/{id}")]
        System.Threading.Tasks.Task<System.Collections.Generic.IEnumerable<Customer.Webservices.Core.Models.Set>> GetSets(int id);
    }
}

(Yes the case on Webservices/WebServices are different, this is going to be changed)

Inspected NuGet package in different project

using Customer.Webservices.Core.Interfaces;
using Customer.Webservices.Core.Models;
using Refit;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace Customer.WebServices.API.Client
{
    public interface ISetAPIClient
    {
        [Get("/Sets")]
        Task<IEnumerable<Set>> GetSets();

        [Get("/Sets/{id}")]
        Task<IEnumerable<Set>> GetSets(int id);
    }
}

I've tried consuming the interface the following ways with no success

RestService.For<ISetAPIClient>("http://localhost:12345");

services.AddRefitClient<ISetAPIClient>()
                .ConfigureHttpClient(options => options.BaseAddress = new Uri("https://localhost:44341"));

but neither times Refit recognized the Interface.

We've tried copying the generated interface into a different source file, and Refit seems to accept that interface. Why it does not accept the generated one or the NuGet interface is something we cannot figure out.

Environment

  • OS: Windows 10
  • Version: 5.2.4 and 6.3.2 (Both times all projects used the same packages)
  • Runtime: .NET 5

PontusMagnusson avatar Mar 18 '22 10:03 PontusMagnusson

I'm facing the same issue, as far as I looked up some of the previous ones there is no clear solution for this, I was using encryption so I thought it might be the case but I even removed the encryption, and still the same result "... doesn't look like a Refit interface".

D-Diyare avatar Mar 18 '22 21:03 D-Diyare

I have same issue. This occurs randomly when compiling the app in release mode. Sometimes, it is solved by adding a simple line break in the interface and recompiling. But then it happens again, especially when compiling through app center. I am using the latest version of Refit (6.3.2), but sometimes it also happens in applications with version 5.x. What can happen? Attached Stacktrace for Xamarin Android:

               ```
  E  android.runtime.JavaProxyThrowable: System.InvalidOperationException: IApiEndpointInterface doesn't look like a Refit interface. Make sure it has at least one method with a Refit HTTP 
                        method attribute and Refit is installed in the project.
                     E    at Refit.RestService.GetGeneratedType (System.Type refitInterfaceType) [0x00024] in <35270eda0328411cb9efadf1bfaeac9f>:0
                     E    at Refit.RestService.For (System.Type refitInterfaceType, System.Net.Http.HttpClient client, Refit.IRequestBuilder builder) [0x00000] in <35270eda0328411cb9efadf1bfaeac9f>:0
                     E    at Refit.RestService.For[T] (System.Net.Http.HttpClient client, Refit.IRequestBuilder`1[T] builder) [0x00000] in <35270eda0328411cb9efadf1bfaeac9f>:0
                     E    at Refit.HttpClientFactoryExtensions+<>c__2`1[T].<AddRefitClient>b__2_3 (System.Net.Http.HttpClient client, System.IServiceProvider serviceProvider) [0x00007] in <27045b5561f1439eb39
                        751889fd87d7b>:0
                     E    at Microsoft.Extensions.DependencyInjection.HttpClientBuilderExtensions+<>c__DisplayClass18_0`1[TClient].<AddTypedClientCore>b__0 (System.IServiceProvider s) [0x00019] in <dae2b93d46
                        0143a69fe93cb50ed6a7ed>:0
                     E    at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory (Microsoft.Extensions.DependencyInjection.ServiceLookup.FactoryCallSite factoryCallSite
                        , Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext context) [0x0000d] in <4cfecac43588472b828d32265d55bddc>:0
                     E    at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2[TArgument,TResult].VisitCallSiteMain (Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceCallSi
                        te callSite, TArgument argument) [0x00023] in <4cfecac43588472b828d32265d55bddc>:0
                     E    at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitDisposeCache (Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceCallSite transientC
                        allSite, Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext context) [0x00007] in <4cfecac43588472b828d32265d55bddc>:0
                     E    at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2[TArgument,TResult].VisitCallSite (Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceCallSite c
                        allSite, TArgument argument) [0x00060] in <4cfecac43588472b828d32265d55bddc>:0
                     E    at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve (Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceCallSite callSite, Microsoft.
                        Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope scope) [0x00026] in <4cfecac43588472b828d32265d55bddc>:0
                     E    at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine+<>c__DisplayClass2_0.<RealizeService>b__0 (Microsoft.Extensions.DependencyInjection.ServiceLook
                        up.ServiceProviderEngineScope scope) [0x00005] in <4cfecac43588472b828d32265d55bddc>:0
                     E    at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService (System.Type serviceType, Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope ser
                        viceProviderEngineScope) [0x00034] in <4cfecac43588472b828d32265d55bddc>:0
                     E    at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService (System.Type serviceType) [0x00008] in <4cfecac43588472b828d32265d55bddc>:0
                     E    at App.App.OnStart () [0x000ed] in <f387af337cbb4f49a6831dac5f9331f2>:0
                     E    at Xamarin.Forms.Application.SendStart () [0x00000] in <f366f2dcd9cb4bf3980d838b3b188da4>:0
                     E    at Xamarin.Forms.Platform.Android.FormsAppCompatActivity.OnStateChanged () [0x0001b] in <4da67e29198c41db9e82d94eef1969f0>:0
                     E    at Xamarin.Forms.Platform.Android.FormsAppCompatActivity.OnStart () [0x00046] in <4da67e29198c41db9e82d94eef1969f0>:0
                     E    at Android.App.Activity.n_OnStart (System.IntPtr jnienv, System.IntPtr native__this) [0x00008] in <6651ad3ab3a94c7fb62a1d3fe071e339>:0
                     E    at (wrapper dynamic-method) Android.Runtime.DynamicMethodNameCounter.39(intptr,intptr)
                     E      at crc643f46942d9dd1fff9.FormsAppCompatActivity.n_onStart(Native Method)
                     E      at crc643f46942d9dd1fff9.FormsAppCompatActivity.onStart(Unknown Source:0)
                     E      at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1447)
                     E      at android.app.Activity.performStart(Activity.java:8237)
                     E      at android.app.ActivityThread.handleStartActivity(ActivityThread.java:4084)
                     E      at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:235)
                     E      at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:215)
                     E      at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:187)
                     E      at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:105)
                     E      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2613)
                     E      at android.os.Handler.dispatchMessage(Handler.java:110)
                     E      at android.os.Looper.loop(Looper.java:219)
                     E      at android.app.ActivityThread.main(ActivityThread.java:8668)
                     E      at java.lang.reflect.Method.invoke(Native Method)
                     E      at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513)
                     E      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1109)

pablogupi avatar Aug 31 '22 15:08 pablogupi

Same. Can we trace the generator to diagnose this?

alrz avatar Oct 10 '22 21:10 alrz

Describe the bug

We've been playing around with generating Refit interfaces using the CodeAnalyzer and so far we've been able to generate an interface that, to us, looks like an interface that Refit would accept. However, we've been unable to register it with Refit since we only get the exception below. ...

@PontusMagnusson, hi, don't know if it is still actual, I got the same error, and in result the problem was in the package versions. Let me describe.

We have external nuget package with client interfaces and main project with reference to this package. When we migrated from Refit 5.4.2 to 6.3.2, we upgraded both package and main project dependencies, but made a mistake and package still referred to Refit 5.4.2. This was the main reason of the issue, since new Refit version uses different naming policy for generated client type. When new RestService looks for client implementation at runtime, it uses the new naming policy, however, the generated class type unique name is created using old policy.

For example if you have type MyNamespace.Clients.IFooClient which describes API, the unique name will be the following depending on Refit version:

5.4.2: "MyNamespace.Clients.IFooClient.AutoGeneratedIFooClient, MyNamespace, Version=1.0.0, Culture=neutral, PublicKeyToken=null" 6.3.2: "Refit.Implementation.Generated+MyNamespaceClientsIFooClient, MyNamespace, Version=1.0.0, Culture=neutral, PublicKeyToken=null"

When we ensured that our project dependencies refers to the same Refit version, the issue was resolved.

Perhaps you faced completely different issue, but I suppose anyway this is somehow related to the unique name of type the Refit uses.

Hope my comment is informative, since when I was googling it, I didn't find this details and I had to debug it and investigate on my own :).

romanstepanenkov avatar Feb 28 '23 21:02 romanstepanenkov