Skip to content

Instantly share code, notes, and snippets.

@bennor
Last active October 24, 2023 15:31
Show Gist options
  • Save bennor/c73870e810f8245b2b1d to your computer and use it in GitHub Desktop.
Save bennor/c73870e810f8245b2b1d to your computer and use it in GitHub Desktop.
A polyfill for Refit 2.0+ in scripting environments (e.g. LINQPad). Warning: This won't work on all platforms Refit 2.0+ supports (e.g. iOS, maybe WinRT?).
using System.Net.Http;
using Castle.DynamicProxy; // From Castle.Core
using Refit;
public class ProxyRestService
{
static readonly ProxyGenerator Generator = new ProxyGenerator();
public static T For<T>(HttpClient client)
where T : class
{
if(!typeof(T).IsInterface) {
throw new InvalidOperationException("T must be an interface.");
}
var interceptor = new RestMethodInterceptor<T>(client);
return Generator.CreateInterfaceProxyWithoutTarget<T>(interceptor);
}
public static T For<T>(string hostUrl)
where T : class
{
var client = new HttpClient() { BaseAddress = new Uri(hostUrl) };
return For<T>(client);
}
class RestMethodInterceptor<T> : IInterceptor
{
static readonly Dictionary<string, Func<HttpClient, object[], object>> methodImpls
= RequestBuilder.ForType<T>().InterfaceHttpMethods
.ToDictionary(k => k, v => RequestBuilder.ForType<T>().BuildRestResultFuncForMethod(v));
readonly HttpClient client;
public RestMethodInterceptor(HttpClient client)
{
this.client = client;
}
public void Intercept(IInvocation invocation)
{
if (!methodImpls.ContainsKey(invocation.Method.Name)) {
throw new NotImplementedException();
}
invocation.ReturnValue = methodImpls[invocation.Method.Name](client, invocation.Arguments);
}
}
}
@bennor
Copy link
Author

bennor commented Nov 17, 2014

This class is a shim for Refit 2.0+ to fix the fact that the new InterfaceStubGenerator approach isn't compatible with all environments/NuGet consumers (e.g. LINQPad, Paket, etc).

Just drop this class in your project, reference Castle.Core and call ProxyRestService.For<ISomeApi>(...) instead of RestService.For<ISomeApi>().

@jrotello
Copy link

Thanks for this gist. I use LinqPad all the time and have been wanting to play around with Refit. I was thinking about making a Nuget package out of this gist for folks with LinqPad Developer or Premium. Are you okay with this?

@samneirinck
Copy link

@jrotello that would be very handy, did you end up doing this?

@andylech
Copy link

andylech commented Mar 5, 2018

@bennor Do you have a more current version of this gist for Refit 4.X?
@jrotello Did you make a NuGet package?

I get the error below on InterfaceHttpMethods here and I can't figure it out:

static readonly Dictionary<string, Func<HttpClient, object[], object>> methodImpls
      = RequestBuilder.ForType<T>().InterfaceHttpMethods
				.ToDictionary(k => k, v => RequestBuilder.ForType<T>().BuildRestResultFuncForMethod(v));
CS1061 'IRequestBuilder' does not contain a definition for 'InterfaceHttpMethods' and no extension method 'InterfaceHttpMethods' accepting a first argument of type 'IRequestBuilder' could be found (press F4 to add a using directive or assembly reference)

@bennor
Copy link
Author

bennor commented Jul 5, 2018

@jrotello 100% okay with it (only just saw your comment). But as has been mentioned -- the above code isn't compatible with Refit 4+.

@gsoulavy
Copy link

gsoulavy commented Nov 14, 2019

just use the following to create the dictionary:

	static readonly Dictionary<string, Func<HttpClient, object[], object>> methodImpls
		= typeof(T).GetMethods().Select(m => m.Name)
			.ToDictionary(k => k, v => RequestBuilder.ForType<T>().BuildRestResultFuncForMethod(v));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment