diff --git a/Directory.Build.props b/Directory.Build.props index 3c49ba8a4..58e479eda 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -13,7 +13,6 @@ en-US The automatic type-safe REST library for Xamarin and .NET true - $(MSBuildThisFileDirectory)Refit.ruleset preview true @@ -53,4 +52,4 @@ - \ No newline at end of file + diff --git a/README.md b/README.md index c43bf9867..9befb73b1 100644 --- a/README.md +++ b/README.md @@ -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> GetById(int id); -} -``` -To make the `MethodInfo` available you need to opt-in via the `RefitSettings` like so: - -```csharp -services.AddRefitClient(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 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. diff --git a/Refit.HttpClientFactory/HttpClientFactoryExtensions.cs b/Refit.HttpClientFactory/HttpClientFactoryExtensions.cs index 9e6949571..57e857cfa 100644 --- a/Refit.HttpClientFactory/HttpClientFactoryExtensions.cs +++ b/Refit.HttpClientFactory/HttpClientFactoryExtensions.cs @@ -6,8 +6,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Http; -using Refit.HttpClientFactory; - namespace Refit { public static class HttpClientFactoryExtensions @@ -42,25 +40,18 @@ public static IHttpClientBuilder AddRefitClient(this IServiceCollection services /// Type of the Refit interface /// container /// Optional. Action to configure refit settings. This method is called once and only once, avoid using any scoped dependencies that maybe be disposed automatically. + /// Optional. Allows users to change the HttpClient name as provided to IServiceCollection.AddHttpClient. Useful for logging scenarios. /// - public static IHttpClientBuilder AddRefitClient(this IServiceCollection services, Func? settingsAction) where T : class => AddRefitClient(services, null, settingsAction); - - /// - /// Adds a Refit client to the DI container - /// - /// Type of the Refit interface - /// container - /// Named http client - /// Optional. Action to configure refit settings. This method is called once and only once, avoid using any scoped dependencies that maybe be disposed automatically. - /// - public static IHttpClientBuilder AddRefitClient(this IServiceCollection services, string? name, Func? settingsAction) where T : class + public static IHttpClientBuilder AddRefitClient( + this IServiceCollection services, + Func? settingsAction, + string? httpClientName = null) where T : class { services.AddSingleton(provider => new SettingsFor(settingsAction?.Invoke(provider))); services.AddSingleton(provider => RequestBuilder.ForType(provider.GetRequiredService>().Settings)); - services.AddScoped(); return services - .AddHttpClient(name ?? UniqueName.ForType()) + .AddHttpClient(httpClientName ?? UniqueName.ForType()) .ConfigureHttpMessageHandlerBuilder(builder => { // check to see if user provided custom auth token @@ -69,7 +60,7 @@ public static IHttpClientBuilder AddRefitClient(this IServiceCollection servi builder.PrimaryHandler = innerHandler; } }) - .AddTypedClient((client, serviceProvider) => RestService.For(client, serviceProvider.GetService>()!)); + .AddTypedClient((client, serviceProvider) => RestService.For(client, serviceProvider.GetService>()!)); } /// @@ -78,8 +69,13 @@ public static IHttpClientBuilder AddRefitClient(this IServiceCollection servi /// container /// Type of the Refit interface /// Optional. Action to configure refit settings. This method is called once and only once, avoid using any scoped dependencies that maybe be disposed automatically. + /// Optional. Allows users to change the HttpClient name as provided to IServiceCollection.AddHttpClient. Useful for logging scenarios. /// - public static IHttpClientBuilder AddRefitClient(this IServiceCollection services, Type refitInterfaceType, Func? settingsAction) + public static IHttpClientBuilder AddRefitClient( + this IServiceCollection services, + Type refitInterfaceType, + Func? settingsAction, + string? httpClientName = null) { var settingsType = typeof(SettingsFor<>).MakeGenericType(refitInterfaceType); var requestBuilderType = typeof(IRequestBuilder<>).MakeGenericType(refitInterfaceType); @@ -87,7 +83,7 @@ public static IHttpClientBuilder AddRefitClient(this IServiceCollection services 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 diff --git a/Refit.HttpClientFactory/IRefitHttpClientFactory.cs b/Refit.HttpClientFactory/IRefitHttpClientFactory.cs deleted file mode 100644 index eee47e75c..000000000 --- a/Refit.HttpClientFactory/IRefitHttpClientFactory.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Refit.HttpClientFactory; - -public interface IRefitHttpClientFactory -{ - T CreateClient(string? name); -} diff --git a/Refit.HttpClientFactory/RefitHttpClientFactory.cs b/Refit.HttpClientFactory/RefitHttpClientFactory.cs deleted file mode 100644 index b77ab01f2..000000000 --- a/Refit.HttpClientFactory/RefitHttpClientFactory.cs +++ /dev/null @@ -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(string? name) - { - var client = HttpClientFactory.CreateClient(name ?? UniqueName.ForType()); - return RestService.For(client, ServiceProvider.GetRequiredService>()); - } -} diff --git a/Refit.Tests/MultipartTests.cs b/Refit.Tests/MultipartTests.cs index 9c155e10a..897672c50 100644 --- a/Refit.Tests/MultipartTests.cs +++ b/Refit.Tests/MultipartTests.cs @@ -159,7 +159,7 @@ public async Task MultipartUploadShouldWorkWithStreamAndCustomBoundary() } 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 @@ public async Task MultipartUploadShouldWorkWithHeaderAndRequestProperty() 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)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 }, diff --git a/Refit.Tests/RequestBuilder.cs b/Refit.Tests/RequestBuilder.cs index a61680d2f..e4737a342 100644 --- a/Refit.Tests/RequestBuilder.cs +++ b/Refit.Tests/RequestBuilder.cs @@ -288,7 +288,6 @@ public class ComplexQueryObject public class RestMethodInfoTests { - [Fact] public void TooManyComplexTypesThrows() { @@ -296,7 +295,7 @@ public void TooManyComplexTypesThrows() Assert.Throws(() => { - var fixture = new RestMethodInfo( + var fixture = new RestMethodInfoInternal( input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.TooManyComplexTypes))); }); @@ -307,7 +306,7 @@ public void TooManyComplexTypesThrows() 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 @@ public void ManyComplexTypes() 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 @@ public void DefaultBodyParameterDetected(string interfaceMethodName) 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 @@ public void DefaultBodyParameterNotDetectedForGet() 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 @@ public void PostWithDictionaryQueryParameter() 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 @@ public void ObjectQueryParameterWithInnerCollectionHasCorrectQuerystring() 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 @@ public void GarbagePathsShouldThrow() 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 @@ public void MissingParametersShouldBlowUp() 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 @@ public void MissingParametersShouldBlowUp() 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 @@ public void ParameterMappingWithTheSameIdInAFewPlaces() 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 @@ public void ParameterMappingWithTheSameIdInTheQueryParameter() 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 @@ public void ParameterMappingWithNonStringRoundTrippingShouldThrow() var input = typeof(IRestMethodInfoTests); Assert.Throws(() => { - var fixture = new RestMethodInfo( + var fixture = new RestMethodInfoInternal( input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithNonStringRoundTrippingParam)) ); @@ -568,7 +567,7 @@ public void ParameterMappingWithNonStringRoundTrippingShouldThrow() 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 @@ public void ParameterMappingWithQuerySmokeTest() 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 @@ public void ParameterMappingWithHardcodedQuerySmokeTest() 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 @@ public void AliasMappingShouldWork() 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 @@ public void MultipleParametersPerSegmentShouldWork() 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 @@ public void FindTheBodyParameter() 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 @@ public void FindTheAuthorizeParameter() 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 @@ public void AllowUrlEncodedContent() 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 @@ public void HardcodedHeadersShouldWork() 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 @@ public void DynamicHeadersShouldWork() 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 @@ public void DynamicHeaderCollectionShouldWork() 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 @@ public void DynamicHeaderCollectionShouldWorkWithBody(string interfaceMethodName 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 @@ public void DynamicHeaderCollectionShouldWorkWithoutBody(string interfaceMethodN 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 @@ public void DynamicHeaderCollectionShouldWorkWithInferredBody(string interfaceMe 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 @@ public void DynamicHeaderCollectionShouldWorkWithAuthorize(string interfaceMetho 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 @@ public void DynamicHeaderCollectionShouldWorkWithDynamicHeader(string interfaceM 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 @@ public void DynamicHeaderCollectionShouldWorkWithDynamicHeader(string interfaceM 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 @@ public void DynamicHeaderCollectionShouldWorkWithPathMemberDynamicHeader(string 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 @@ public void DynamicHeaderCollectionShouldOnlyAllowOne(string interfaceMethodName { var input = typeof(IRestMethodInfoTests); - Assert.Throws(() => new RestMethodInfo(input, input.GetMethods().First(x => x.Name == interfaceMethodName))); + Assert.Throws(() => new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == interfaceMethodName))); } [Theory] @@ -881,7 +880,7 @@ public void DynamicHeaderCollectionShouldOnlyAllowOne(string interfaceMethodName 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 @@ public void DynamicHeaderCollectionShouldWorkWithProperty(string interfaceMethod public void DynamicHeaderCollectionShouldOnlyWorkWithSupportedSemantics(string interfaceMethodName) { var input = typeof(IRestMethodInfoTests); - Assert.Throws(() => new RestMethodInfo(input, input.GetMethods().First(x => x.Name == interfaceMethodName))); + Assert.Throws(() => new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == interfaceMethodName))); } #endregion @@ -912,7 +911,7 @@ public void DynamicHeaderCollectionShouldOnlyWorkWithSupportedSemantics(string i 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 @@ public void DynamicRequestPropertiesShouldWork() 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 @@ public void DynamicRequestPropertyShouldWorkWithBody() 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 @@ public void DynamicRequestPropertiesShouldWorkWithBody() 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 @@ public void DynamicRequestPropertyShouldWorkWithoutBody(string interfaceMethodNa 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 @@ public void DynamicRequestPropertyShouldWorkWithInferredBody(string interfaceMet 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 @@ public void DynamicRequestPropertiesWithoutKeysShouldDefaultKeyToParameterName() 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 @@ public void DynamicRequestPropertiesWithDuplicateKeysDontBlowUp() 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 @@ public void ValueTypesDontBlowUpBuffered() 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 @@ public void ValueTypesDontBlowUpUnBuffered() 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 @@ public void StreamMethodPullWorks() 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 @@ public void SyncMethodsShouldThrow() 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 @@ public void SyncMethodsShouldThrow() 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 @@ public void UsingThePatchAttributeSetsTheCorrectMethod() 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 @@ public void UsingOptionsAttribute() 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 @@ public void ApiResponseShouldBeSet() 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 @@ public void ApiResponseShouldNotBeSet() 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 @@ public void ParameterMappingWithHeaderQueryParamAndQueryArrayParam() public void GenericReturnTypeIsNotTaskOrObservableShouldThrow() { var input = typeof(IRestMethodInfoTests); - Assert.Throws(() => new RestMethodInfo(input, + Assert.Throws(() => new RestMethodInfoInternal(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.InvalidGenericReturnType)))); } } @@ -2175,12 +2174,6 @@ public void InterfaceTypeShouldBeInProperties() var factory = fixture.BuildRequestFactoryForMethod(nameof(IContainAandB.Ping)); var output = factory(Array.Empty()); -#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]); @@ -2189,75 +2182,23 @@ public void InterfaceTypeShouldBeInProperties() } [Fact] - public void MethodInfoShouldBeInPropertiesIfInjectMethodInfoAsPropertyTrue() - { - var fixture = new RequestBuilderImplementation(new RefitSettings - { - InjectMethodInfoAsProperty = true - }); - var factory = fixture.BuildRequestFactoryForMethod(nameof(IContainAandB.Ping)); - var output = factory(Array.Empty()); - - 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() + public void RestMethodInfoShouldBeInProperties() { + var someProperty = new object(); var fixture = new RequestBuilderImplementation(); var factory = fixture.BuildRequestFactoryForMethod(nameof(IContainAandB.Ping)); - var output = factory(Array.Empty()); + var output = factory(new 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.True(output.Options.TryGetValue(new HttpRequestOptionsKey(HttpRequestMessageOptions.RestMethodInfo), out var restMethodInfo)); +#else 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(new() { InjectMethodInfoAsProperty = true }); - var factory = fixture.BuildRequestFactoryForMethod(nameof(IContainAandB.Ping)); - var output = factory(Array.Empty()); - 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); + Assert.True(output.Properties.TryGetValue(HttpRequestMessageOptions.RestMethodInfo, out var restMethodInfoObj)); + Assert.IsType(restMethodInfoObj); + var restMethodInfo = restMethodInfoObj as RestMethodInfo; #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] @@ -2293,12 +2234,12 @@ public void DynamicRequestPropertiesWithDuplicateKeyShouldOverwritePreviousPrope #if NET6_0_OR_GREATER - Assert.Equal(2, output.Options.Count()); + Assert.Equal(3, output.Options.Count()); Assert.Equal(someOtherProperty, ((IDictionary)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 } diff --git a/Refit.sln b/Refit.sln index 336190b3e..6edc2aa7b 100644 --- a/Refit.sln +++ b/Refit.sln @@ -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 diff --git a/Refit/HttpRequestMessageProperties.cs b/Refit/HttpRequestMessageProperties.cs index 0b7f84c75..0610c4be2 100644 --- a/Refit/HttpRequestMessageProperties.cs +++ b/Refit/HttpRequestMessageProperties.cs @@ -1,5 +1,3 @@ -using System.Reflection; - namespace Refit { /// @@ -12,24 +10,9 @@ public static class HttpRequestMessageOptions /// public static string InterfaceType { get; } = "Refit.InterfaceType"; -#if NET6_0_OR_GREATER - /// - /// A typed key to access the of the top-level interface where the method was called from - /// on the . - /// - public static System.Net.Http.HttpRequestOptionsKey InterfaceTypeKey { get; } = new(InterfaceType); -#endif - /// - /// Returns the of the method that was called + /// Returns the of the top-level interface /// public static string RestMethodInfo { get; } = "Refit.RestMethodInfo"; - -#if NET6_0_OR_GREATER - /// - /// A typed key to access the of the method that was called - /// - public static System.Net.Http.HttpRequestOptionsKey RestMethodInfoKey { get; } = new(RestMethodInfo); -#endif } } diff --git a/Refit/RefitSettings.cs b/Refit/RefitSettings.cs index b904b1e48..79372da47 100644 --- a/Refit/RefitSettings.cs +++ b/Refit/RefitSettings.cs @@ -27,35 +27,21 @@ public RefitSettings() ExceptionFactory = new DefaultApiExceptionFactory(this).CreateAsync; } - -#if NET6_0_OR_GREATER - /// - /// Creates a new instance with the specified parameters - /// - /// The instance to use - /// The instance to use (defaults to ) - /// The instance to use (defaults to ) - /// Controls injecting the of the method on the Refit client interface that was invoked into the HttpRequestMessage.Options (defaults to false) -#else /// /// Creates a new instance with the specified parameters /// /// The instance to use /// The instance to use (defaults to ) /// The instance to use (defaults to ) - /// Controls injecting the of the method on the Refit client interface that was invoked into the HttpRequestMessage.Properties (defaults to false) -#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; } /// @@ -103,17 +89,6 @@ public RefitSettings( /// Optional Key-Value pairs, which are displayed in the property or . /// public Dictionary HttpRequestMessageOptions { get; set; } - -#if NET6_0_OR_GREATER - /// - /// Controls injecting the of the method on the Refit client interface that was invoked into the HttpRequestMessage.Options (defaults to false) - /// -#else - /// - /// Controls injecting the of the method on the Refit client interface that was invoked into the HttpRequestMessage.Properties (defaults to false) - /// -#endif - public bool InjectMethodInfoAsProperty { get; set; } } /// diff --git a/Refit/RequestBuilderImplementation.cs b/Refit/RequestBuilderImplementation.cs index b71737c8c..eff3fc6a8 100644 --- a/Refit/RequestBuilderImplementation.cs +++ b/Refit/RequestBuilderImplementation.cs @@ -29,8 +29,8 @@ partial class RequestBuilderImplementation : IRequestBuilder HttpMethod.Get, HttpMethod.Head }; - readonly Dictionary> interfaceHttpMethods; - readonly ConcurrentDictionary interfaceGenericHttpMethods; + readonly Dictionary> interfaceHttpMethods; + readonly ConcurrentDictionary interfaceGenericHttpMethods; readonly IHttpContentSerializer serializer; readonly RefitSettings settings; public Type TargetType { get; } @@ -41,7 +41,7 @@ public RequestBuilderImplementation(Type refitInterfaceType, RefitSettings? refi settings = refitSettings ?? new RefitSettings(); serializer = settings.ContentSerializer; - interfaceGenericHttpMethods = new ConcurrentDictionary(); + interfaceGenericHttpMethods = new ConcurrentDictionary(); if (refitInterfaceType == null || !refitInterfaceType.GetTypeInfo().IsInterface) { @@ -50,7 +50,7 @@ public RequestBuilderImplementation(Type refitInterfaceType, RefitSettings? refi TargetType = refitInterfaceType; - var dict = new Dictionary>(); + var dict = new Dictionary>(); AddInterfaceHttpMethods(refitInterfaceType, dict); foreach (var inheritedInterface in targetInterfaceInheritedInterfaces) @@ -61,7 +61,7 @@ public RequestBuilderImplementation(Type refitInterfaceType, RefitSettings? refi interfaceHttpMethods = dict; } - void AddInterfaceHttpMethods(Type interfaceType, Dictionary> methods) + void AddInterfaceHttpMethods(Type interfaceType, Dictionary> methods) { // Consider public (the implicit visibility) and non-public abstract members of the interfaceType var methodInfos = interfaceType @@ -76,16 +76,16 @@ void AddInterfaceHttpMethods(Type interfaceType, Dictionary()); + methods.Add(methodInfo.Name, new List()); } - 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 @@ RestMethodInfo FindMatchingRestMethodInfo(string key, Type[]? parameterTypes, Ty } - 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 @@ void AddMultipartItem(MultipartFormDataContent multiPartContent, string fileName 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> BuildCancellableTaskFuncForMethod(RestMethodInfo restMethod) + Func> BuildCancellableTaskFuncForMethod(RestMethodInfoInternal restMethod) { return async (client, ct, paramList) => { @@ -466,7 +466,7 @@ void AddMultipartItem(MultipartFormDataContent multiPartContent, string fileName return kvps; } - Func BuildRequestFactoryForMethod(RestMethodInfo restMethod, string basePath, bool paramsContainsCancellationToken) + Func BuildRequestFactoryForMethod(RestMethodInfoInternal restMethod, string basePath, bool paramsContainsCancellationToken) { return paramList => { @@ -746,21 +746,14 @@ Func BuildRequestFactoryForMethod(RestMethodInfo r #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(HttpRequestMessageOptions.InterfaceType), TargetType); + ret.Options.Set(new HttpRequestOptionsKey(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 @@ Func BuildRequestFactoryForMethod(RestMethodInfo r } } - Func> BuildRxFuncForMethod(RestMethodInfo restMethod) + Func> BuildRxFuncForMethod(RestMethodInfoInternal restMethod) { var taskFunc = BuildCancellableTaskFuncForMethod(restMethod); @@ -862,7 +855,7 @@ Func BuildRequestFactoryForMethod(RestMethodInfo r }; } - Func> BuildTaskFuncForMethod(RestMethodInfo restMethod) + Func> BuildTaskFuncForMethod(RestMethodInfoInternal restMethod) { var ret = BuildCancellableTaskFuncForMethod(restMethod); @@ -877,7 +870,7 @@ Func BuildRequestFactoryForMethod(RestMethodInfo r }; } - Func BuildVoidTaskFuncForMethod(RestMethodInfo restMethod) + Func BuildVoidTaskFuncForMethod(RestMethodInfoInternal restMethod) { return async (client, paramList) => { @@ -909,7 +902,7 @@ Func BuildVoidTaskFuncForMethod(RestMethodInfo restM }; } - private static bool IsBodyBuffered(RestMethodInfo restMethod, HttpRequestMessage? request) + private static bool IsBodyBuffered(RestMethodInfoInternal restMethod, HttpRequestMessage? request) { return (restMethod.BodyParameterInfo?.Item2 ?? false) && (request?.Content != null); } diff --git a/Refit/RestMethodInfo.cs b/Refit/RestMethodInfo.cs index 04ec347a8..c79f693d6 100644 --- a/Refit/RestMethodInfo.cs +++ b/Refit/RestMethodInfo.cs @@ -9,10 +9,20 @@ 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 @@ public class RestMethodInfo 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 @@ public RestMethodInfo(Type targetInterface, MethodInfo methodInfo, RefitSettings IsApiResponse = ReturnResultType!.GetTypeInfo().IsGenericType && (ReturnResultType!.GetGenericTypeDefinition() == typeof(ApiResponse<>) - || ReturnResultType.GetGenericTypeDefinition() == typeof(IApiResponse<>)) + || ReturnResultType.GetGenericTypeDefinition() == typeof(IApiResponse<>)) || ReturnResultType == typeof(IApiResponse); } @@ -162,6 +172,8 @@ private ISet BuildHeaderCollectionParameterMap(List paramete return headerCollectionMap; } + public RestMethodInfo ToRestMethodInfo() => new RestMethodInfo(Name, Type, MethodInfo, RelativePath, ReturnType); + static Dictionary BuildRequestPropertyMap(List parameterList) { var propertyMap = new Dictionary();