Revert #1418, #1367, introduce public version of RestMethodInfo (#1496)

* Revert "feature: Add named httpclient support (#1418)"

This reverts commit b78bbc79dd.

* Revert "Feature: allow developers to inject the MethodInfo as a Property (#1367)"

This reverts commit b06ef7c37d.

* no

* Make RestMethodInfo internal

* Implement a public RestMethodInfo

* Reenable RestMethodInfo, but our public one instead

amend

* Allow configuring the HttpClient name

* Fix typo
This commit is contained in:
Ani Betts 2023-05-14 14:18:55 +02:00 коммит произвёл GitHub
Родитель ef46395693
Коммит e4a3565c85
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
12 изменённых файлов: 123 добавлений и 304 удалений

Просмотреть файл

@ -13,7 +13,6 @@
<DefaultLanguage>en-US</DefaultLanguage>
<Description>The automatic type-safe REST library for Xamarin and .NET</Description>
<NoPackageAnalysis>true</NoPackageAnalysis>
<CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)Refit.ruleset</CodeAnalysisRuleSet>
<LangVersion>preview</LangVersion>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<!-- Net Analyzers config taken from : https://docs.microsoft.com/en-gb/visualstudio/code-quality/migrate-from-fxcop-analyzers-to-net-analyzers?view=vs-2019 -->
@ -53,4 +52,4 @@
</AssemblyAttribute>
</ItemGroup>
</Target>
</Project>
</Project>

Просмотреть файл

@ -56,7 +56,7 @@ services
* [Removing headers](#removing-headers)
* [Passing state into DelegatingHandlers](#passing-state-into-delegatinghandlers)
* [Support for Polly and Polly.Context](#support-for-polly-and-pollycontext)
* [Target Interface type and method info](#target-interface-type-and-method-info)
* [Target Interface type](#target-interface-type)
* [MethodInfo of the method on the Refit client interface that was invoked](#methodinfo-of-the-method-on-the-refit-client-interface-that-was-invoked)
* [Multipart uploads](#multipart-uploads)
* [Retrieving the response](#retrieving-the-response)
@ -882,54 +882,6 @@ class RequestPropertyHandler : DelegatingHandler
Note: in .NET 5 `HttpRequestMessage.Properties` has been marked `Obsolete` and Refit will instead populate the value into the new `HttpRequestMessage.Options`. Refit provides `HttpRequestMessageOptions.InterfaceTypeKey` and `HttpRequestMessageOptions.RestMethodInfoKey` to respectively access the interface type and REST method info from the options.
#### MethodInfo of the method on the Refit client interface that was invoked
There may be times when you want access to the `MethodInfo` of the method on the Refit client interface that was invoked. An example is where you
want to decorate the method with a custom attribute in order to control some aspect of behavior in a `DelegatingHandler`:
```csharp
public interface ISomeAPI
{
[SomeCustomAttribute("SomeValue")]
[Get("/{id}")]
Task<ApiResponse<SomeClass>> GetById(int id);
}
```
To make the `MethodInfo` available you need to opt-in via the `RefitSettings` like so:
```csharp
services.AddRefitClient<ISomeAPI>(provider => new RefitSettings
{
InjectMethodInfoAsProperty = true
})
.ConfigureHttpClient(c => c.BaseAddress = new Uri("https://api.example.com"));
```
You can access the `MethodInfo` for use in a handler and then get the custom attributes:
```csharp
class RequestPropertyHandler : DelegatingHandler
{
public RequestPropertyHandler(HttpMessageHandler innerHandler = null) : base(innerHandler ?? new HttpClientHandler()) {}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
// Get the MethodInfo
MethodInfo methodInfo;
request.Options.TryGetValue(HttpRequestMessageOptions.MethodInfoKey, out methodInfo);
//get the custom attributes
var customAttributes = methodInfo.CustomAttributes;
//insert your logic here
return await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
}
}
```
Note: for .NET Core 3.1 and lower this will be available via `HttpRequestMessage.Properties[HttpRequestMessageOptions.MethodInfo]`.
### Multipart uploads
Methods decorated with `Multipart` attribute will be submitted with multipart content type.

Просмотреть файл

@ -6,8 +6,6 @@ using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Http;
using Refit.HttpClientFactory;
namespace Refit
{
public static class HttpClientFactoryExtensions
@ -42,25 +40,18 @@ namespace Refit
/// <typeparam name="T">Type of the Refit interface</typeparam>
/// <param name="services">container</param>
/// <param name="settingsAction">Optional. Action to configure refit settings. This method is called once and only once, avoid using any scoped dependencies that maybe be disposed automatically.</param>
/// <param name="httpClientName">Optional. Allows users to change the HttpClient name as provided to IServiceCollection.AddHttpClient. Useful for logging scenarios.</param>
/// <returns></returns>
public static IHttpClientBuilder AddRefitClient<T>(this IServiceCollection services, Func<IServiceProvider, RefitSettings?>? settingsAction) where T : class => AddRefitClient<T>(services, null, settingsAction);
/// <summary>
/// Adds a Refit client to the DI container
/// </summary>
/// <typeparam name="T">Type of the Refit interface</typeparam>
/// <param name="services">container</param>
/// <param name="name">Named http client</param>
/// <param name="settingsAction">Optional. Action to configure refit settings. This method is called once and only once, avoid using any scoped dependencies that maybe be disposed automatically.</param>
/// <returns></returns>
public static IHttpClientBuilder AddRefitClient<T>(this IServiceCollection services, string? name, Func<IServiceProvider, RefitSettings?>? settingsAction) where T : class
public static IHttpClientBuilder AddRefitClient<T>(
this IServiceCollection services,
Func<IServiceProvider, RefitSettings?>? settingsAction,
string? httpClientName = null) where T : class
{
services.AddSingleton(provider => new SettingsFor<T>(settingsAction?.Invoke(provider)));
services.AddSingleton(provider => RequestBuilder.ForType<T>(provider.GetRequiredService<SettingsFor<T>>().Settings));
services.AddScoped<IRefitHttpClientFactory, RefitHttpClientFactory>();
return services
.AddHttpClient(name ?? UniqueName.ForType<T>())
.AddHttpClient(httpClientName ?? UniqueName.ForType<T>())
.ConfigureHttpMessageHandlerBuilder(builder =>
{
// check to see if user provided custom auth token
@ -69,7 +60,7 @@ namespace Refit
builder.PrimaryHandler = innerHandler;
}
})
.AddTypedClient((client, serviceProvider) => RestService.For(client, serviceProvider.GetService<IRequestBuilder<T>>()!));
.AddTypedClient((client, serviceProvider) => RestService.For<T>(client, serviceProvider.GetService<IRequestBuilder<T>>()!));
}
/// <summary>
@ -78,8 +69,13 @@ namespace Refit
/// <param name="services">container</param>
/// <param name="refitInterfaceType">Type of the Refit interface</param>
/// <param name="settingsAction">Optional. Action to configure refit settings. This method is called once and only once, avoid using any scoped dependencies that maybe be disposed automatically.</param>
/// <param name="httpClientName">Optional. Allows users to change the HttpClient name as provided to IServiceCollection.AddHttpClient. Useful for logging scenarios.</param>
/// <returns></returns>
public static IHttpClientBuilder AddRefitClient(this IServiceCollection services, Type refitInterfaceType, Func<IServiceProvider, RefitSettings?>? settingsAction)
public static IHttpClientBuilder AddRefitClient(
this IServiceCollection services,
Type refitInterfaceType,
Func<IServiceProvider, RefitSettings?>? settingsAction,
string? httpClientName = null)
{
var settingsType = typeof(SettingsFor<>).MakeGenericType(refitInterfaceType);
var requestBuilderType = typeof(IRequestBuilder<>).MakeGenericType(refitInterfaceType);
@ -87,7 +83,7 @@ namespace Refit
services.AddSingleton(requestBuilderType, provider => RequestBuilderGenericForTypeMethod.MakeGenericMethod(refitInterfaceType).Invoke(null, new object?[] { ((ISettingsFor)provider.GetRequiredService(settingsType)).Settings })!);
return services
.AddHttpClient(UniqueName.ForType(refitInterfaceType))
.AddHttpClient(httpClientName ?? UniqueName.ForType(refitInterfaceType))
.ConfigureHttpMessageHandlerBuilder(builder =>
{
// check to see if user provided custom auth token

Просмотреть файл

@ -1,6 +0,0 @@
namespace Refit.HttpClientFactory;
public interface IRefitHttpClientFactory
{
T CreateClient<T>(string? name);
}

Просмотреть файл

@ -1,25 +0,0 @@
using System;
using System.Net.Http;
using Microsoft.Extensions.DependencyInjection;
namespace Refit.HttpClientFactory;
internal class RefitHttpClientFactory : IRefitHttpClientFactory
{
public RefitHttpClientFactory(IHttpClientFactory httpClientFactory, IServiceProvider serviceProvider)
{
HttpClientFactory = httpClientFactory;
ServiceProvider = serviceProvider;
}
private IHttpClientFactory HttpClientFactory { get; }
private IServiceProvider ServiceProvider { get; }
public T CreateClient<T>(string? name)
{
var client = HttpClientFactory.CreateClient(name ?? UniqueName.ForType<T>());
return RestService.For(client, ServiceProvider.GetRequiredService<IRequestBuilder<T>>());
}
}

Просмотреть файл

@ -159,7 +159,7 @@ namespace Refit.Tests
}
var input = typeof(IRunscopeApi);
var methodFixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == "UploadStreamWithCustomBoundary"));
var methodFixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == "UploadStreamWithCustomBoundary"));
Assert.Equal("-----SomeCustomBoundary", methodFixture.MultipartBoundary);
}
@ -308,12 +308,12 @@ namespace Refit.Tests
Assert.Equal(someHeader, message.Headers.Authorization.ToString());
#if NET6_0_OR_GREATER
Assert.Equal(2, message.Options.Count());
Assert.Equal(3, message.Options.Count());
Assert.Equal(someProperty, ((IDictionary<string, object>)message.Options)["SomeProperty"]);
#endif
#pragma warning disable CS0618 // Type or member is obsolete
Assert.Equal(2, message.Properties.Count);
Assert.Equal(3, message.Properties.Count);
Assert.Equal(someProperty, message.Properties["SomeProperty"]);
#pragma warning restore CS0618 // Type or member is obsolete
},

Просмотреть файл

@ -288,7 +288,6 @@ namespace Refit.Tests
public class RestMethodInfoTests
{
[Fact]
public void TooManyComplexTypesThrows()
{
@ -296,7 +295,7 @@ namespace Refit.Tests
Assert.Throws<ArgumentException>(() =>
{
var fixture = new RestMethodInfo(
var fixture = new RestMethodInfoInternal(
input,
input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.TooManyComplexTypes)));
});
@ -307,7 +306,7 @@ namespace Refit.Tests
public void ManyComplexTypes()
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.ManyComplexTypes)));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.ManyComplexTypes)));
Assert.Single(fixture.QueryParameterMap);
Assert.NotNull(fixture.BodyParameterInfo);
@ -321,7 +320,7 @@ namespace Refit.Tests
public void DefaultBodyParameterDetected(string interfaceMethodName)
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == interfaceMethodName));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == interfaceMethodName));
Assert.Empty(fixture.QueryParameterMap);
Assert.NotNull(fixture.BodyParameterInfo);
@ -331,7 +330,7 @@ namespace Refit.Tests
public void DefaultBodyParameterNotDetectedForGet()
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.GetWithBodyDetected)));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.GetWithBodyDetected)));
Assert.Single(fixture.QueryParameterMap);
Assert.Null(fixture.BodyParameterInfo);
@ -341,7 +340,7 @@ namespace Refit.Tests
public void PostWithDictionaryQueryParameter()
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.PostWithDictionaryQuery)));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.PostWithDictionaryQuery)));
Assert.Single(fixture.QueryParameterMap);
Assert.Null(fixture.BodyParameterInfo);
@ -351,7 +350,7 @@ namespace Refit.Tests
public void PostWithObjectQueryParameterHasSingleQueryParameterValue()
{
var input = typeof(IRestMethodInfoTests);
var fixtureParams = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.PostWithComplexTypeQuery)));
var fixtureParams = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.PostWithComplexTypeQuery)));
Assert.Single(fixtureParams.QueryParameterMap);
Assert.Equal("queryParams", fixtureParams.QueryParameterMap[0]);
@ -463,7 +462,7 @@ namespace Refit.Tests
public void MultipleQueryAttributesWithNulls()
{
var input = typeof(IRestMethodInfoTests);
var fixtureParams = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.MultipleQueryAttributes)));
var fixtureParams = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.MultipleQueryAttributes)));
Assert.Equal(3, fixtureParams.QueryParameterMap.Count);
}
@ -476,7 +475,7 @@ namespace Refit.Tests
try
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.GarbagePath)));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.GarbagePath)));
}
catch (ArgumentException)
{
@ -494,7 +493,7 @@ namespace Refit.Tests
try
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffMissingParameters)));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffMissingParameters)));
}
catch (ArgumentException)
{
@ -508,18 +507,18 @@ namespace Refit.Tests
public void ParameterMappingSmokeTest()
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuff)));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuff)));
Assert.Equal("id", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type);
Assert.Empty(fixture.QueryParameterMap);
Assert.Null(fixture.BodyParameterInfo);
}
[Fact]
public void ParameterMappingWithTheSameIdInAFewPlaces()
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithTheSameId)));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithTheSameId)));
Assert.Equal("id", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type);
Assert.Empty(fixture.QueryParameterMap);
@ -530,7 +529,7 @@ namespace Refit.Tests
public void ParameterMappingWithTheSameIdInTheQueryParameter()
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithTheIdInAParameterMultipleTimes)));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithTheIdInAParameterMultipleTimes)));
Assert.Equal("id", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type);
Assert.Empty(fixture.QueryParameterMap);
@ -542,7 +541,7 @@ namespace Refit.Tests
public void ParameterMappingWithRoundTrippingSmokeTest()
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithRoundTrippingParam)));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithRoundTrippingParam)));
Assert.Equal("path", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.RoundTripping, fixture.ParameterMap[0].Type);
Assert.Equal("id", fixture.ParameterMap[1].Name);
@ -557,7 +556,7 @@ namespace Refit.Tests
var input = typeof(IRestMethodInfoTests);
Assert.Throws<ArgumentException>(() =>
{
var fixture = new RestMethodInfo(
var fixture = new RestMethodInfoInternal(
input,
input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithNonStringRoundTrippingParam))
);
@ -568,7 +567,7 @@ namespace Refit.Tests
public void ParameterMappingWithQuerySmokeTest()
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithQueryParam)));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithQueryParam)));
Assert.Equal("id", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type);
Assert.Equal("search", fixture.QueryParameterMap[1]);
@ -579,7 +578,7 @@ namespace Refit.Tests
public void ParameterMappingWithHardcodedQuerySmokeTest()
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithHardcodedQueryParam)));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithHardcodedQueryParam)));
Assert.Equal("id", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type);
Assert.Empty(fixture.QueryParameterMap);
@ -590,7 +589,7 @@ namespace Refit.Tests
public void AliasMappingShouldWork()
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithAlias)));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithAlias)));
Assert.Equal("id", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type);
Assert.Empty(fixture.QueryParameterMap);
@ -601,7 +600,7 @@ namespace Refit.Tests
public void MultipleParametersPerSegmentShouldWork()
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchAnImage)));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchAnImage)));
Assert.Equal("width", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type);
Assert.Equal("height", fixture.ParameterMap[1].Name);
@ -614,7 +613,7 @@ namespace Refit.Tests
public void FindTheBodyParameter()
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithBody)));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithBody)));
Assert.Equal("id", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type);
@ -627,7 +626,7 @@ namespace Refit.Tests
public void FindTheAuthorizeParameter()
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithAuthorizationSchemeSpecified)));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithAuthorizationSchemeSpecified)));
Assert.Equal("id", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type);
@ -640,7 +639,7 @@ namespace Refit.Tests
public void AllowUrlEncodedContent()
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.PostSomeUrlEncodedStuff)));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.PostSomeUrlEncodedStuff)));
Assert.Equal("id", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type);
@ -653,7 +652,7 @@ namespace Refit.Tests
public void HardcodedHeadersShouldWork()
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithHardcodedHeaders)));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithHardcodedHeaders)));
Assert.Equal("id", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type);
Assert.Empty(fixture.QueryParameterMap);
@ -672,7 +671,7 @@ namespace Refit.Tests
public void DynamicHeadersShouldWork()
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithDynamicHeader)));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithDynamicHeader)));
Assert.Equal("id", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type);
Assert.Empty(fixture.QueryParameterMap);
@ -691,7 +690,7 @@ namespace Refit.Tests
public void DynamicHeaderCollectionShouldWork()
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithDynamicHeaderCollection)));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithDynamicHeaderCollection)));
Assert.Equal("id", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type);
Assert.Empty(fixture.QueryParameterMap);
@ -720,7 +719,7 @@ namespace Refit.Tests
public void DynamicHeaderCollectionShouldWorkWithBody(string interfaceMethodName)
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == interfaceMethodName));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == interfaceMethodName));
Assert.Equal("id", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type);
Assert.Empty(fixture.QueryParameterMap);
@ -740,7 +739,7 @@ namespace Refit.Tests
public void DynamicHeaderCollectionShouldWorkWithoutBody(string interfaceMethodName)
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == interfaceMethodName));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == interfaceMethodName));
Assert.Equal("id", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type);
Assert.Empty(fixture.QueryParameterMap);
@ -760,7 +759,7 @@ namespace Refit.Tests
public void DynamicHeaderCollectionShouldWorkWithInferredBody(string interfaceMethodName)
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == interfaceMethodName));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == interfaceMethodName));
Assert.Equal("id", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type);
Assert.Empty(fixture.QueryParameterMap);
@ -780,7 +779,7 @@ namespace Refit.Tests
public void DynamicHeaderCollectionShouldWorkWithAuthorize(string interfaceMethodName)
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == interfaceMethodName));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == interfaceMethodName));
Assert.Equal("id", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type);
Assert.Empty(fixture.QueryParameterMap);
@ -799,7 +798,7 @@ namespace Refit.Tests
public void DynamicHeaderCollectionShouldWorkWithDynamicHeader(string interfaceMethodName)
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == interfaceMethodName));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == interfaceMethodName));
Assert.Equal("id", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type);
Assert.Empty(fixture.QueryParameterMap);
@ -813,7 +812,7 @@ namespace Refit.Tests
Assert.True(fixture.HeaderCollectionParameterMap.Contains(2));
input = typeof(IRestMethodInfoTests);
fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithDynamicHeaderCollectionAndDynamicHeaderOrderFlipped)));
fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithDynamicHeaderCollectionAndDynamicHeaderOrderFlipped)));
Assert.Equal("id", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type);
Assert.Empty(fixture.QueryParameterMap);
@ -833,7 +832,7 @@ namespace Refit.Tests
public void DynamicHeaderCollectionShouldWorkWithPathMemberDynamicHeader(string interfaceMethodName)
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == interfaceMethodName));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == interfaceMethodName));
Assert.Equal("id", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type);
Assert.Empty(fixture.QueryParameterMap);
@ -853,7 +852,7 @@ namespace Refit.Tests
public void DynamicHeaderCollectionInMiddleOfParamsShouldWork(string interfaceMethodName)
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == interfaceMethodName));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == interfaceMethodName));
Assert.Equal("id", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type);
Assert.Null(fixture.AuthorizeParameterInfo);
@ -872,7 +871,7 @@ namespace Refit.Tests
{
var input = typeof(IRestMethodInfoTests);
Assert.Throws<ArgumentException>(() => new RestMethodInfo(input, input.GetMethods().First(x => x.Name == interfaceMethodName)));
Assert.Throws<ArgumentException>(() => new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == interfaceMethodName)));
}
[Theory]
@ -881,7 +880,7 @@ namespace Refit.Tests
public void DynamicHeaderCollectionShouldWorkWithProperty(string interfaceMethodName)
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == interfaceMethodName));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == interfaceMethodName));
Assert.Null(fixture.BodyParameterInfo);
Assert.Null(fixture.AuthorizeParameterInfo);
@ -901,7 +900,7 @@ namespace Refit.Tests
public void DynamicHeaderCollectionShouldOnlyWorkWithSupportedSemantics(string interfaceMethodName)
{
var input = typeof(IRestMethodInfoTests);
Assert.Throws<ArgumentException>(() => new RestMethodInfo(input, input.GetMethods().First(x => x.Name == interfaceMethodName)));
Assert.Throws<ArgumentException>(() => new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == interfaceMethodName)));
}
#endregion
@ -912,7 +911,7 @@ namespace Refit.Tests
public void DynamicRequestPropertiesShouldWork()
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithDynamicRequestProperty)));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithDynamicRequestProperty)));
Assert.Equal("id", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type);
Assert.Empty(fixture.QueryParameterMap);
@ -926,7 +925,7 @@ namespace Refit.Tests
public void DynamicRequestPropertyShouldWorkWithBody()
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.PostSomeStuffWithDynamicRequestProperty)));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.PostSomeStuffWithDynamicRequestProperty)));
Assert.Equal("id", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type);
Assert.Empty(fixture.QueryParameterMap);
@ -942,7 +941,7 @@ namespace Refit.Tests
public void DynamicRequestPropertiesShouldWorkWithBody()
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.PostSomeStuffWithDynamicRequestProperties)));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.PostSomeStuffWithDynamicRequestProperties)));
Assert.Equal("id", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type);
Assert.Empty(fixture.QueryParameterMap);
@ -963,7 +962,7 @@ namespace Refit.Tests
public void DynamicRequestPropertyShouldWorkWithoutBody(string interfaceMethodName)
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == interfaceMethodName));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == interfaceMethodName));
Assert.Equal("id", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type);
Assert.Empty(fixture.QueryParameterMap);
@ -982,7 +981,7 @@ namespace Refit.Tests
public void DynamicRequestPropertyShouldWorkWithInferredBody(string interfaceMethodName)
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == interfaceMethodName));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == interfaceMethodName));
Assert.Equal("id", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type);
Assert.Empty(fixture.QueryParameterMap);
@ -999,7 +998,7 @@ namespace Refit.Tests
public void DynamicRequestPropertiesWithoutKeysShouldDefaultKeyToParameterName()
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithDynamicRequestPropertyWithoutKey)));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithDynamicRequestPropertyWithoutKey)));
Assert.Equal("id", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type);
Assert.Empty(fixture.QueryParameterMap);
@ -1014,7 +1013,7 @@ namespace Refit.Tests
public void DynamicRequestPropertiesWithDuplicateKeysDontBlowUp()
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithDynamicRequestPropertyWithDuplicateKey)));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithDynamicRequestPropertyWithDuplicateKey)));
Assert.Equal("id", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type);
Assert.Empty(fixture.QueryParameterMap);
@ -1031,7 +1030,7 @@ namespace Refit.Tests
public void ValueTypesDontBlowUpBuffered()
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.OhYeahValueTypes)));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.OhYeahValueTypes)));
Assert.Equal("id", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type);
Assert.Empty(fixture.QueryParameterMap);
@ -1046,7 +1045,7 @@ namespace Refit.Tests
public void ValueTypesDontBlowUpUnBuffered()
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.OhYeahValueTypesUnbuffered)));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.OhYeahValueTypesUnbuffered)));
Assert.Equal("id", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type);
Assert.Empty(fixture.QueryParameterMap);
@ -1061,7 +1060,7 @@ namespace Refit.Tests
public void StreamMethodPullWorks()
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.PullStreamMethod)));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.PullStreamMethod)));
Assert.Equal("id", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type);
Assert.Empty(fixture.QueryParameterMap);
@ -1076,7 +1075,7 @@ namespace Refit.Tests
public void ReturningTaskShouldWork()
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.VoidPost)));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.VoidPost)));
Assert.Equal("id", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type);
@ -1092,7 +1091,7 @@ namespace Refit.Tests
try
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.AsyncOnlyBuddy)));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.AsyncOnlyBuddy)));
}
catch (ArgumentException)
{
@ -1106,7 +1105,7 @@ namespace Refit.Tests
public void UsingThePatchAttributeSetsTheCorrectMethod()
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.PatchSomething)));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.PatchSomething)));
Assert.Equal("PATCH", fixture.HttpMethod.Method);
}
@ -1115,7 +1114,7 @@ namespace Refit.Tests
public void UsingOptionsAttribute()
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IDummyHttpApi.SendOptions)));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IDummyHttpApi.SendOptions)));
Assert.Equal("OPTIONS", fixture.HttpMethod.Method);
}
@ -1124,7 +1123,7 @@ namespace Refit.Tests
public void ApiResponseShouldBeSet()
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.PostReturnsApiResponse)));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.PostReturnsApiResponse)));
Assert.True(fixture.IsApiResponse);
}
@ -1133,7 +1132,7 @@ namespace Refit.Tests
public void ApiResponseShouldNotBeSet()
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.PostReturnsNonApiResponse)));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.PostReturnsNonApiResponse)));
Assert.False(fixture.IsApiResponse);
}
@ -1142,7 +1141,7 @@ namespace Refit.Tests
public void ParameterMappingWithHeaderQueryParamAndQueryArrayParam()
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithDynamicHeaderQueryParamAndArrayQueryParam)));
var fixture = new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithDynamicHeaderQueryParamAndArrayQueryParam)));
Assert.Equal("GET", fixture.HttpMethod.Method);
Assert.Equal(2, fixture.QueryParameterMap.Count);
@ -1154,7 +1153,7 @@ namespace Refit.Tests
public void GenericReturnTypeIsNotTaskOrObservableShouldThrow()
{
var input = typeof(IRestMethodInfoTests);
Assert.Throws<ArgumentException>(() => new RestMethodInfo(input,
Assert.Throws<ArgumentException>(() => new RestMethodInfoInternal(input,
input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.InvalidGenericReturnType))));
}
}
@ -2175,12 +2174,6 @@ namespace Refit.Tests
var factory = fixture.BuildRequestFactoryForMethod(nameof(IContainAandB.Ping));
var output = factory(Array.Empty<object>());
#if NET6_0_OR_GREATER
Assert.NotEmpty(output.Options);
output.Options.TryGetValue(HttpRequestMessageOptions.InterfaceTypeKey, out var interfaceType);
Assert.Equal(typeof(IContainAandB), interfaceType);
#endif
#pragma warning disable CS0618 // Type or member is obsolete
Assert.NotEmpty(output.Properties);
Assert.Equal(typeof(IContainAandB), output.Properties[HttpRequestMessageOptions.InterfaceType]);
@ -2188,76 +2181,24 @@ namespace Refit.Tests
}
[Fact]
public void MethodInfoShouldBeInPropertiesIfInjectMethodInfoAsPropertyTrue()
{
var fixture = new RequestBuilderImplementation<IContainAandB>(new RefitSettings
{
InjectMethodInfoAsProperty = true
});
var factory = fixture.BuildRequestFactoryForMethod(nameof(IContainAandB.Ping));
var output = factory(Array.Empty<object>());
RestMethodInfo restMethodInfo;
#if NET6_0_OR_GREATER
Assert.NotEmpty(output.Options);
output.Options.TryGetValue(HttpRequestMessageOptions.RestMethodInfoKey, out restMethodInfo);
Assert.NotNull(restMethodInfo);
Assert.Equal(nameof(IContainAandB.Ping), restMethodInfo.Name);
Assert.Equal(typeof(IAmInterfaceA), restMethodInfo.MethodInfo.DeclaringType);
#endif
#pragma warning disable CS0618 // Type or member is obsolete
Assert.NotEmpty(output.Properties);
restMethodInfo = (RestMethodInfo)(output.Properties[HttpRequestMessageOptions.RestMethodInfo]);
Assert.NotNull(restMethodInfo);
Assert.Equal(nameof(IContainAandB.Ping), restMethodInfo.Name);
Assert.Equal(typeof(IAmInterfaceA), restMethodInfo.MethodInfo.DeclaringType);
#pragma warning restore CS0618 // Type or member is obsolete
}
[Fact]
public void MethodInfoShouldNotBeInPropertiesIfInjectMethodInfoAsPropertyFalse()
{
var fixture = new RequestBuilderImplementation<IContainAandB>();
var factory = fixture.BuildRequestFactoryForMethod(nameof(IContainAandB.Ping));
var output = factory(Array.Empty<object>());
RestMethodInfo restMethodInfo;
#if NET6_0_OR_GREATER
Assert.NotEmpty(output.Options);
output.Options.TryGetValue(HttpRequestMessageOptions.RestMethodInfoKey, out restMethodInfo);
Assert.Null(restMethodInfo);
#endif
#pragma warning disable CS0618 // Type or member is obsolete
Assert.NotEmpty(output.Properties);
Assert.False(output.Properties.ContainsKey(HttpRequestMessageOptions.RestMethodInfo));
#pragma warning restore CS0618 // Type or member is obsolete
}
[Fact]
public void RestMethodInfoShouldBeInProperties()
{
var fixture = new RequestBuilderImplementation<IContainAandB>(new() { InjectMethodInfoAsProperty = true });
var someProperty = new object();
var fixture = new RequestBuilderImplementation<IContainAandB>();
var factory = fixture.BuildRequestFactoryForMethod(nameof(IContainAandB.Ping));
var output = factory(Array.Empty<object>());
RestMethodInfo restMethodInfo;
var output = factory(new object[] { });
#if NET6_0_OR_GREATER
Assert.NotEmpty(output.Options);
output.Options.TryGetValue(HttpRequestMessageOptions.RestMethodInfoKey, out restMethodInfo);
Assert.NotNull(restMethodInfo);
Assert.Equal(nameof(IContainAandB.Ping), restMethodInfo.Name);
Assert.Equal(typeof(IAmInterfaceA), restMethodInfo.MethodInfo.DeclaringType);
#endif
#pragma warning disable CS0618 // Type or member is obsolete
Assert.True(output.Options.TryGetValue(new HttpRequestOptionsKey<RestMethodInfo>(HttpRequestMessageOptions.RestMethodInfo), out var restMethodInfo));
#else
Assert.NotEmpty(output.Properties);
restMethodInfo = (RestMethodInfo)(output.Properties[HttpRequestMessageOptions.RestMethodInfo]);
Assert.NotNull(restMethodInfo);
Assert.True(output.Properties.TryGetValue(HttpRequestMessageOptions.RestMethodInfo, out var restMethodInfoObj));
Assert.IsType<RestMethodInfo>(restMethodInfoObj);
var restMethodInfo = restMethodInfoObj as RestMethodInfo;
#endif
Assert.Equal(nameof(IContainAandB.Ping), restMethodInfo.Name);
Assert.Equal(typeof(IAmInterfaceA), restMethodInfo.MethodInfo.DeclaringType);
#pragma warning restore CS0618 // Type or member is obsolete
}
[Fact]
@ -2293,12 +2234,12 @@ namespace Refit.Tests
#if NET6_0_OR_GREATER
Assert.Equal(2, output.Options.Count());
Assert.Equal(3, output.Options.Count());
Assert.Equal(someOtherProperty, ((IDictionary<string, object>)output.Options)["SomeProperty"]);
#endif
#pragma warning disable CS0618 // Type or member is obsolete
Assert.Equal(2, output.Properties.Count);
Assert.Equal(3, output.Properties.Count);
Assert.Equal(someOtherProperty, output.Properties["SomeProperty"]);
#pragma warning restore CS0618 // Type or member is obsolete
}

Просмотреть файл

@ -10,7 +10,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
Directory.build.props = Directory.build.props
LICENSE = LICENSE
README.md = README.md
Refit.ruleset = Refit.ruleset
.github\workflows\release.yml = .github\workflows\release.yml
version.json = version.json
EndProjectSection

Просмотреть файл

@ -1,5 +1,3 @@
using System.Reflection;
namespace Refit
{
/// <summary>
@ -12,24 +10,9 @@ namespace Refit
/// </summary>
public static string InterfaceType { get; } = "Refit.InterfaceType";
#if NET6_0_OR_GREATER
/// <summary>
/// A typed key to access the <see cref="System.Type"/> of the top-level interface where the method was called from
/// on the <see cref="System.Net.Http.HttpRequestMessage.Options"/>.
/// </summary>
public static System.Net.Http.HttpRequestOptionsKey<System.Type> InterfaceTypeKey { get; } = new(InterfaceType);
#endif
/// <summary>
/// Returns the <see cref="Refit.RestMethodInfo"/> of the method that was called
/// Returns the <see cref="Refit.RestMethodInfo"/> of the top-level interface
/// </summary>
public static string RestMethodInfo { get; } = "Refit.RestMethodInfo";
#if NET6_0_OR_GREATER
/// <summary>
/// A typed key to access the <see cref="Refit.RestMethodInfo"/> of the method that was called
/// </summary>
public static System.Net.Http.HttpRequestOptionsKey<RestMethodInfo> RestMethodInfoKey { get; } = new(RestMethodInfo);
#endif
}
}

Просмотреть файл

@ -27,35 +27,21 @@ namespace Refit
ExceptionFactory = new DefaultApiExceptionFactory(this).CreateAsync;
}
#if NET6_0_OR_GREATER
/// <summary>
/// Creates a new <see cref="RefitSettings"/> instance with the specified parameters
/// </summary>
/// <param name="contentSerializer">The <see cref="IHttpContentSerializer"/> instance to use</param>
/// <param name="urlParameterFormatter">The <see cref="IUrlParameterFormatter"/> instance to use (defaults to <see cref="DefaultUrlParameterFormatter"/>)</param>
/// <param name="formUrlEncodedParameterFormatter">The <see cref="IFormUrlEncodedParameterFormatter"/> instance to use (defaults to <see cref="DefaultFormUrlEncodedParameterFormatter"/>)</param>
/// <param name="injectMethodInfoAsProperty">Controls injecting the <see cref="MethodInfo"/> of the method on the Refit client interface that was invoked into the HttpRequestMessage.Options (defaults to false)</param>
#else
/// <summary>
/// Creates a new <see cref="RefitSettings"/> instance with the specified parameters
/// </summary>
/// <param name="contentSerializer">The <see cref="IHttpContentSerializer"/> instance to use</param>
/// <param name="urlParameterFormatter">The <see cref="IUrlParameterFormatter"/> instance to use (defaults to <see cref="DefaultUrlParameterFormatter"/>)</param>
/// <param name="formUrlEncodedParameterFormatter">The <see cref="IFormUrlEncodedParameterFormatter"/> instance to use (defaults to <see cref="DefaultFormUrlEncodedParameterFormatter"/>)</param>
/// <param name="injectMethodInfoAsProperty">Controls injecting the <see cref="MethodInfo"/> of the method on the Refit client interface that was invoked into the HttpRequestMessage.Properties (defaults to false)</param>
#endif
public RefitSettings(
IHttpContentSerializer contentSerializer,
IUrlParameterFormatter? urlParameterFormatter = null,
IFormUrlEncodedParameterFormatter? formUrlEncodedParameterFormatter = null,
bool injectMethodInfoAsProperty = false)
IFormUrlEncodedParameterFormatter? formUrlEncodedParameterFormatter = null)
{
ContentSerializer = contentSerializer ?? throw new ArgumentNullException(nameof(contentSerializer), "The content serializer can't be null");
UrlParameterFormatter = urlParameterFormatter ?? new DefaultUrlParameterFormatter();
FormUrlEncodedParameterFormatter = formUrlEncodedParameterFormatter ?? new DefaultFormUrlEncodedParameterFormatter();
ExceptionFactory = new DefaultApiExceptionFactory(this).CreateAsync;
InjectMethodInfoAsProperty = injectMethodInfoAsProperty;
}
/// <summary>
@ -103,17 +89,6 @@ namespace Refit
/// Optional Key-Value pairs, which are displayed in the property <see cref="HttpRequestMessage.Options"/> or <see cref="HttpRequestMessage.Properties"/>.
/// </summary>
public Dictionary<string, object> HttpRequestMessageOptions { get; set; }
#if NET6_0_OR_GREATER
/// <summary>
/// Controls injecting the <see cref="MethodInfo"/> of the method on the Refit client interface that was invoked into the HttpRequestMessage.Options (defaults to false)
/// </summary>
#else
/// <summary>
/// Controls injecting the <see cref="MethodInfo"/> of the method on the Refit client interface that was invoked into the HttpRequestMessage.Properties (defaults to false)
/// </summary>
#endif
public bool InjectMethodInfoAsProperty { get; set; }
}
/// <summary>

Просмотреть файл

@ -29,8 +29,8 @@ namespace Refit
HttpMethod.Get,
HttpMethod.Head
};
readonly Dictionary<string, List<RestMethodInfo>> interfaceHttpMethods;
readonly ConcurrentDictionary<CloseGenericMethodKey, RestMethodInfo> interfaceGenericHttpMethods;
readonly Dictionary<string, List<RestMethodInfoInternal>> interfaceHttpMethods;
readonly ConcurrentDictionary<CloseGenericMethodKey, RestMethodInfoInternal> interfaceGenericHttpMethods;
readonly IHttpContentSerializer serializer;
readonly RefitSettings settings;
public Type TargetType { get; }
@ -41,7 +41,7 @@ namespace Refit
settings = refitSettings ?? new RefitSettings();
serializer = settings.ContentSerializer;
interfaceGenericHttpMethods = new ConcurrentDictionary<CloseGenericMethodKey, RestMethodInfo>();
interfaceGenericHttpMethods = new ConcurrentDictionary<CloseGenericMethodKey, RestMethodInfoInternal>();
if (refitInterfaceType == null || !refitInterfaceType.GetTypeInfo().IsInterface)
{
@ -50,7 +50,7 @@ namespace Refit
TargetType = refitInterfaceType;
var dict = new Dictionary<string, List<RestMethodInfo>>();
var dict = new Dictionary<string, List<RestMethodInfoInternal>>();
AddInterfaceHttpMethods(refitInterfaceType, dict);
foreach (var inheritedInterface in targetInterfaceInheritedInterfaces)
@ -61,7 +61,7 @@ namespace Refit
interfaceHttpMethods = dict;
}
void AddInterfaceHttpMethods(Type interfaceType, Dictionary<string, List<RestMethodInfo>> methods)
void AddInterfaceHttpMethods(Type interfaceType, Dictionary<string, List<RestMethodInfoInternal>> methods)
{
// Consider public (the implicit visibility) and non-public abstract members of the interfaceType
var methodInfos = interfaceType
@ -76,16 +76,16 @@ namespace Refit
{
if (!methods.ContainsKey(methodInfo.Name))
{
methods.Add(methodInfo.Name, new List<RestMethodInfo>());
methods.Add(methodInfo.Name, new List<RestMethodInfoInternal>());
}
var restinfo = new RestMethodInfo(interfaceType, methodInfo, settings);
var restinfo = new RestMethodInfoInternal(interfaceType, methodInfo, settings);
methods[methodInfo.Name].Add(restinfo);
}
}
}
RestMethodInfo FindMatchingRestMethodInfo(string key, Type[]? parameterTypes, Type[]? genericArgumentTypes)
RestMethodInfoInternal FindMatchingRestMethodInfo(string key, Type[]? parameterTypes, Type[]? genericArgumentTypes)
{
if (interfaceHttpMethods.TryGetValue(key, out var httpMethods))
{
@ -134,12 +134,12 @@ namespace Refit
}
RestMethodInfo CloseGenericMethodIfNeeded(RestMethodInfo restMethodInfo, Type[]? genericArgumentTypes)
RestMethodInfoInternal CloseGenericMethodIfNeeded(RestMethodInfoInternal restMethodInfo, Type[]? genericArgumentTypes)
{
if (genericArgumentTypes != null)
{
return interfaceGenericHttpMethods.GetOrAdd(new CloseGenericMethodKey(restMethodInfo.MethodInfo, genericArgumentTypes),
_ => new RestMethodInfo(restMethodInfo.Type, restMethodInfo.MethodInfo.MakeGenericMethod(genericArgumentTypes), restMethodInfo.RefitSettings));
_ => new RestMethodInfoInternal(restMethodInfo.Type, restMethodInfo.MethodInfo.MakeGenericMethod(genericArgumentTypes), restMethodInfo.RefitSettings));
}
return restMethodInfo;
}
@ -234,7 +234,7 @@ namespace Refit
throw new ArgumentException($"Unexpected parameter type in a Multipart request. Parameter {fileName} is of type {itemValue.GetType().Name}, whereas allowed types are String, Stream, FileInfo, Byte array and anything that's JSON serializable", nameof(itemValue), e);
}
Func<HttpClient, CancellationToken, object[], Task<T?>> BuildCancellableTaskFuncForMethod<T, TBody>(RestMethodInfo restMethod)
Func<HttpClient, CancellationToken, object[], Task<T?>> BuildCancellableTaskFuncForMethod<T, TBody>(RestMethodInfoInternal restMethod)
{
return async (client, ct, paramList) =>
{
@ -466,7 +466,7 @@ namespace Refit
return kvps;
}
Func<object[], HttpRequestMessage> BuildRequestFactoryForMethod(RestMethodInfo restMethod, string basePath, bool paramsContainsCancellationToken)
Func<object[], HttpRequestMessage> BuildRequestFactoryForMethod(RestMethodInfoInternal restMethod, string basePath, bool paramsContainsCancellationToken)
{
return paramList =>
{
@ -746,21 +746,14 @@ namespace Refit
#endif
}
// Always add the top-level type of the interface to the options/properties and include the MethodInfo if the developer has opted-in to that behavior
// Always add the top-level type of the interface to the properties
#if NET6_0_OR_GREATER
ret.Options.Set(HttpRequestMessageOptions.InterfaceTypeKey, TargetType);
if (settings.InjectMethodInfoAsProperty)
{
ret.Options.Set(HttpRequestMessageOptions.RestMethodInfoKey, restMethod);
}
ret.Options.Set(new HttpRequestOptionsKey<Type>(HttpRequestMessageOptions.InterfaceType), TargetType);
ret.Options.Set(new HttpRequestOptionsKey<RestMethodInfo>(HttpRequestMessageOptions.RestMethodInfo), restMethod.ToRestMethodInfo());
#else
ret.Properties[HttpRequestMessageOptions.InterfaceType] = TargetType;
if (settings.InjectMethodInfoAsProperty)
{
ret.Properties[HttpRequestMessageOptions.RestMethodInfo] = restMethod;
}
#endif
ret.Properties[HttpRequestMessageOptions.RestMethodInfo] = restMethod.ToRestMethodInfo();
#endif
// NB: The URI methods in .NET are dumb. Also, we do this
// UriBuilder business so that we preserve any hardcoded query
@ -840,7 +833,7 @@ namespace Refit
}
}
Func<HttpClient, object[], IObservable<T?>> BuildRxFuncForMethod<T, TBody>(RestMethodInfo restMethod)
Func<HttpClient, object[], IObservable<T?>> BuildRxFuncForMethod<T, TBody>(RestMethodInfoInternal restMethod)
{
var taskFunc = BuildCancellableTaskFuncForMethod<T, TBody>(restMethod);
@ -862,7 +855,7 @@ namespace Refit
};
}
Func<HttpClient, object[], Task<T?>> BuildTaskFuncForMethod<T, TBody>(RestMethodInfo restMethod)
Func<HttpClient, object[], Task<T?>> BuildTaskFuncForMethod<T, TBody>(RestMethodInfoInternal restMethod)
{
var ret = BuildCancellableTaskFuncForMethod<T, TBody>(restMethod);
@ -877,7 +870,7 @@ namespace Refit
};
}
Func<HttpClient, object[], Task> BuildVoidTaskFuncForMethod(RestMethodInfo restMethod)
Func<HttpClient, object[], Task> BuildVoidTaskFuncForMethod(RestMethodInfoInternal restMethod)
{
return async (client, paramList) =>
{
@ -909,7 +902,7 @@ namespace Refit
};
}
private static bool IsBodyBuffered(RestMethodInfo restMethod, HttpRequestMessage? request)
private static bool IsBodyBuffered(RestMethodInfoInternal restMethod, HttpRequestMessage? request)
{
return (restMethod.BodyParameterInfo?.Item2 ?? false) && (request?.Content != null);
}

Просмотреть файл

@ -9,10 +9,20 @@ using System.Threading.Tasks;
using System.Text.RegularExpressions;
using System.Threading;
// Enable support for C# 9 record types
#if NETSTANDARD2_1 || !NET6_0_OR_GREATER
namespace System.Runtime.CompilerServices
{
internal static class IsExternalInit { }
}
#endif
namespace Refit
{
public record RestMethodInfo(string Name, Type HostingType, MethodInfo MethodInfo, string RelativePath, Type ReturnType);
[DebuggerDisplay("{MethodInfo}")]
public class RestMethodInfo
internal class RestMethodInfoInternal
{
public string Name { get; set; }
public Type Type { get; set; }
@ -43,7 +53,7 @@ namespace Refit
static readonly HttpMethod PatchMethod = new("PATCH");
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
public RestMethodInfo(Type targetInterface, MethodInfo methodInfo, RefitSettings? refitSettings = null)
public RestMethodInfoInternal(Type targetInterface, MethodInfo methodInfo, RefitSettings? refitSettings = null)
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
{
RefitSettings = refitSettings ?? new RefitSettings();
@ -127,7 +137,7 @@ namespace Refit
IsApiResponse = ReturnResultType!.GetTypeInfo().IsGenericType &&
(ReturnResultType!.GetGenericTypeDefinition() == typeof(ApiResponse<>)
|| ReturnResultType.GetGenericTypeDefinition() == typeof(IApiResponse<>))
|| ReturnResultType.GetGenericTypeDefinition() == typeof(IApiResponse<>))
|| ReturnResultType == typeof(IApiResponse);
}
@ -162,6 +172,8 @@ namespace Refit
return headerCollectionMap;
}
public RestMethodInfo ToRestMethodInfo() => new RestMethodInfo(Name, Type, MethodInfo, RelativePath, ReturnType);
static Dictionary<int, string> BuildRequestPropertyMap(List<ParameterInfo> parameterList)
{
var propertyMap = new Dictionary<int, string>();