Skip to content

Commit

Permalink
Added non generic methods for create rest service
Browse files Browse the repository at this point in the history
  • Loading branch information
yuri-voloshyn committed Apr 2, 2019
1 parent 5d9fe6c commit d6570f9
Show file tree
Hide file tree
Showing 10 changed files with 126 additions and 33 deletions.
7 changes: 1 addition & 6 deletions InterfaceStubGenerator.Core/InterfaceStubGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ public class ClassTemplateInfo
public string TypeParameters => TypeParametersInfo != null ? string.Join(", ", TypeParametersInfo) : null;
}

public class TypeInfo : ICloneable
public class TypeInfo
{
public string Name { get; set; }
public List<TypeInfo> Children { get; set; }
Expand All @@ -388,11 +388,6 @@ public TypeInfo Clone()
return CloneImpl() as TypeInfo;
}

object ICloneable.Clone()
{
throw new NotImplementedException();
}

protected virtual object CloneImpl()
{
return new TypeInfo
Expand Down
16 changes: 15 additions & 1 deletion Refit.HttpClientFactory/HttpClientFactoryExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.Extensions.DependencyInjection;
using System;
using Microsoft.Extensions.DependencyInjection;

namespace Refit
{
Expand All @@ -18,5 +19,18 @@ public static IHttpClientBuilder AddRefitClient<T>(this IServiceCollection servi
return services.AddHttpClient(UniqueName.ForType<T>())
.AddTypedClient((client, serviceProvider) => RestService.For<T>(client, serviceProvider.GetService<IRequestBuilder<T>>()));
}

/// <summary>
/// Adds a Refit client to the DI container
/// </summary>
/// <param name="services">container</param>
/// <param name="refitInterfaceType">Type of the Refit interface</typeparam>
/// <param name="settings">Optional. Settings to configure the instance with</param>
/// <returns></returns>
public static IHttpClientBuilder AddRefitClient(this IServiceCollection services, Type refitInterfaceType, RefitSettings settings = null)
{
return services.AddHttpClient(UniqueName.ForType(refitInterfaceType))
.AddTypedClient((client, serviceProvider) => RestService.For(refitInterfaceType, client, settings));
}
}
}
11 changes: 11 additions & 0 deletions Refit.Tests/RestService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1290,5 +1290,16 @@ public void ShouldThrowArgumentExceptionIfHostUrlIsWhitespace()

Assert.False(true, "Exception not thrown.");
}

[Fact]
public void NonGenericCreate()
{
var expectedBaseAddress = "http://example.com/api";
var inputBaseAddress = "http://example.com/api/";

var fixture = RestService.For(typeof(ITrimTrailingForwardSlashApi), inputBaseAddress) as ITrimTrailingForwardSlashApi;

Assert.Equal(fixture.Client.BaseAddress.AbsoluteUri, expectedBaseAddress);
}
}
}
13 changes: 10 additions & 3 deletions Refit/CachedRequestBuilderImplementation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,21 @@

namespace Refit
{
class CachedRequestBuilderImplementation<T> : IRequestBuilder<T>
class CachedRequestBuilderImplementation<T> : CachedRequestBuilderImplementation, IRequestBuilder<T>
{
public CachedRequestBuilderImplementation(IRequestBuilder<T> innerBuilder)
public CachedRequestBuilderImplementation(IRequestBuilder<T> innerBuilder) : base(innerBuilder)
{
}
}

class CachedRequestBuilderImplementation : IRequestBuilder
{
public CachedRequestBuilderImplementation(IRequestBuilder innerBuilder)
{
this.innerBuilder = innerBuilder;
}

readonly IRequestBuilder<T> innerBuilder;
readonly IRequestBuilder innerBuilder;
readonly ConcurrentDictionary<string, Func<HttpClient, object[], object>> methodDictionary = new ConcurrentDictionary<string, Func<HttpClient, object[], object>>();

public Func<HttpClient, object[], object> BuildRestResultFuncForMethod(string methodName, Type[] parameterTypes = null, Type[] genericArgumentTypes = null)
Expand Down
10 changes: 10 additions & 0 deletions Refit/RequestBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,15 @@ public static IRequestBuilder<T> ForType<T>()
{
return PlatformRequestBuilderFactory.Create<T>(null);
}

public static IRequestBuilder ForType(Type refitInterfaceType, RefitSettings settings)
{
return PlatformRequestBuilderFactory.Create(refitInterfaceType, settings);
}

public static IRequestBuilder ForType(Type refitInterfaceType)
{
return PlatformRequestBuilderFactory.Create(refitInterfaceType, null);
}
}
}
6 changes: 6 additions & 0 deletions Refit/RequestBuilderFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ namespace Refit
interface IRequestBuilderFactory
{
IRequestBuilder<T> Create<T>(RefitSettings settings);
IRequestBuilder Create(Type refitInterfaceType, RefitSettings settings);
}

class RequestBuilderFactory : IRequestBuilderFactory
Expand All @@ -16,5 +17,10 @@ public IRequestBuilder<T> Create<T>(RefitSettings settings = null)
{
return new CachedRequestBuilderImplementation<T>(new RequestBuilderImplementation<T>(settings));
}

public IRequestBuilder Create(Type refitInterfaceType, RefitSettings settings = null)
{
return new CachedRequestBuilderImplementation(new RequestBuilderImplementation(refitInterfaceType, settings));
}
}
}
2 changes: 1 addition & 1 deletion Refit/RequestBuilderImplementation.TaskToObservable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace Refit
{
partial class RequestBuilderImplementation<TApi>
partial class RequestBuilderImplementation
{
sealed class TaskToObservable<T> : IObservable<T>
{
Expand Down
20 changes: 13 additions & 7 deletions Refit/RequestBuilderImplementation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,14 @@

namespace Refit
{
partial class RequestBuilderImplementation<TApi> : IRequestBuilder<TApi>
class RequestBuilderImplementation<TApi> : RequestBuilderImplementation, IRequestBuilder<TApi>
{
public RequestBuilderImplementation(RefitSettings refitSettings = null) : base(typeof(TApi), refitSettings)
{
}
}

partial class RequestBuilderImplementation : IRequestBuilder
{
static readonly ISet<HttpMethod> BodylessMethods = new HashSet<HttpMethod>
{
Expand All @@ -28,25 +35,24 @@ partial class RequestBuilderImplementation<TApi> : IRequestBuilder<TApi>
readonly RefitSettings settings;
public Type TargetType { get; }

public RequestBuilderImplementation(RefitSettings refitSettings = null)
public RequestBuilderImplementation(Type refitInterfaceType, RefitSettings refitSettings = null)
{
Type targetInterface = typeof(TApi);
Type[] targetInterfaceInheritedInterfaces = targetInterface.GetInterfaces();
Type[] targetInterfaceInheritedInterfaces = refitInterfaceType.GetInterfaces();

settings = refitSettings ?? new RefitSettings();
serializer = settings.ContentSerializer;
interfaceGenericHttpMethods = new ConcurrentDictionary<CloseGenericMethodKey, RestMethodInfo>();

if (targetInterface == null || !targetInterface.GetTypeInfo().IsInterface)
if (refitInterfaceType == null || !refitInterfaceType.GetTypeInfo().IsInterface)
{
throw new ArgumentException("targetInterface must be an Interface");
}

TargetType = targetInterface;
TargetType = refitInterfaceType;

var dict = new Dictionary<string, List<RestMethodInfo>>();

AddInterfaceHttpMethods(targetInterface, dict);
AddInterfaceHttpMethods(refitInterfaceType, dict);
foreach (var inheritedInterface in targetInterfaceInheritedInterfaces)
{
AddInterfaceHttpMethods(inheritedInterface, dict);
Expand Down
53 changes: 45 additions & 8 deletions Refit/RestService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,49 @@ public static T For<T>(HttpClient client, IRequestBuilder<T> builder)

public static T For<T>(HttpClient client, RefitSettings settings)
{
IRequestBuilder<T> requestBuilder = RequestBuilder.ForType<T>(settings);
var requestBuilder = RequestBuilder.ForType<T>(settings);

return For<T>(client, requestBuilder);
return For(client, requestBuilder);
}

public static T For<T>(HttpClient client) => For<T>(client, (RefitSettings)null);

public static T For<T>(string hostUrl, RefitSettings settings)
{
var client = CreateHttpClient(hostUrl, settings);

return For<T>(client, settings);
}

public static T For<T>(string hostUrl) => For<T>(hostUrl, null);

public static object For(Type refitInterfaceType, HttpClient client, IRequestBuilder builder)
{
var generatedType = TypeMapping.GetOrAdd(refitInterfaceType, GetGeneratedType(refitInterfaceType));

return Activator.CreateInstance(generatedType, client, builder);
}

public static object For(Type refitInterfaceType, HttpClient client, RefitSettings settings)
{
var requestBuilder = RequestBuilder.ForType(refitInterfaceType, settings);

return For(refitInterfaceType, client, requestBuilder);
}

public static object For(Type refitInterfaceType, HttpClient client) => For(refitInterfaceType, client, (RefitSettings)null);

public static object For(Type refitInterfaceType, string hostUrl, RefitSettings settings)
{
var client = CreateHttpClient(hostUrl, settings);

return For(refitInterfaceType, client, settings);
}

public static object For(Type refitInterfaceType, string hostUrl) => For(refitInterfaceType, hostUrl, null);


public static HttpClient CreateHttpClient(string hostUrl, RefitSettings settings)
{
if (string.IsNullOrWhiteSpace(hostUrl))
{
Expand All @@ -56,21 +91,23 @@ public static T For<T>(string hostUrl, RefitSettings settings)
}
}

var client = new HttpClient(innerHandler ?? new HttpClientHandler()) { BaseAddress = new Uri(hostUrl.TrimEnd('/')) };
return For<T>(client, settings);
return new HttpClient(innerHandler ?? new HttpClientHandler()) { BaseAddress = new Uri(hostUrl.TrimEnd('/')) };
}

public static T For<T>(string hostUrl) => For<T>(hostUrl, null);

static Type GetGeneratedType<T>()
{
string typeName = UniqueName.ForType<T>();
return GetGeneratedType(typeof(T));
}

static Type GetGeneratedType(Type refitInterfaceType)
{
string typeName = UniqueName.ForType(refitInterfaceType);

var generatedType = Type.GetType(typeName);

if (generatedType == null)
{
var message = typeof(T).Name + " 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.";
var message = refitInterfaceType.Name + " 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.";

throw new InvalidOperationException(message);
}
Expand Down
21 changes: 14 additions & 7 deletions Refit/UniqueName.cs
Original file line number Diff line number Diff line change
@@ -1,26 +1,33 @@
namespace Refit
using System;

namespace Refit
{
internal class UniqueName
{
public static string ForType<T>()
{
return ForType(typeof(T));
}

public static string ForType(Type refitInterfaceType)
{
string typeName;

if (typeof(T).IsNested)
if (refitInterfaceType.IsNested)
{
var className = "AutoGenerated" + typeof(T).DeclaringType.Name + typeof(T).Name;
typeName = typeof(T).AssemblyQualifiedName.Replace(typeof(T).DeclaringType.FullName + "+" + typeof(T).Name, typeof(T).Namespace + "." + className);
var className = "AutoGenerated" + refitInterfaceType.DeclaringType.Name + refitInterfaceType.Name;
typeName = refitInterfaceType.AssemblyQualifiedName.Replace(refitInterfaceType.DeclaringType.FullName + "+" + refitInterfaceType.Name, refitInterfaceType.Namespace + "." + className);
}
else
{
var className = "AutoGenerated" + typeof(T).Name;
var className = "AutoGenerated" + refitInterfaceType.Name;

if (typeof(T).Namespace == null)
if (refitInterfaceType.Namespace == null)
{
className = $"{className}.{className}";
}

typeName = typeof(T).AssemblyQualifiedName.Replace(typeof(T).Name, className);
typeName = refitInterfaceType.AssemblyQualifiedName.Replace(refitInterfaceType.Name, className);
}

return typeName;
Expand Down

0 comments on commit d6570f9

Please sign in to comment.