diff --git a/README.md b/README.md index 6816fe6e0..2ba6e0c40 100644 --- a/README.md +++ b/README.md @@ -787,7 +787,7 @@ Because Refit supports `HttpClientFactory` it is possible to configure Polly pol If your policy makes use of `Polly.Context` this can be passed via Refit by adding `[Property("PollyExecutionContext")] Polly.Context context` as behind the scenes `Polly.Context` is simply stored in `HttpRequestMessage.Properties` under the key `PollyExecutionContext` and is of type `Polly.Context` -#### Target Interface Type +#### Target Interface Type and MethodInfo There may be times when you want to know what the target interface type is of the Refit instance. An example is where you have a derived interface that implements a common base like this: @@ -807,8 +807,9 @@ public interface IOrdersAPI : IGetAPI { } ``` - -You can access the concrete type of the interface for use in a handler, such as to alter the URL of the request: +You may want to know the information of the current method as well. Then you can add path or tag for metrics and telemetry. +Even more that you may want to set custom attributes to the method. +You can access the concrete type of the interface and the current method for use in a handler, such as to alter the URL of the request: [//]: # ({% raw %}) ```csharp @@ -819,7 +820,12 @@ class RequestPropertyHandler : DelegatingHandler protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { // Get the type of the target interface - Type interfaceType = (Type)request.Properties[HttpMessageRequestOptions.InterfaceType]; + var interfaceType = (Type)request.Properties[HttpMessageRequestOptions.InterfaceType]; + + // Get the methodInfo of the current method + var methodInfo = (MethodInfo)request.Properties[HttpMessageRequestOptions.MethodInfo]; + + // do something with methodInfo with method name, custom attributes and etc. var builder = new UriBuilder(request.RequestUri); // Alter the Path in some way based on the interface or an attribute on it diff --git a/Refit.Tests/MultipartTests.cs b/Refit.Tests/MultipartTests.cs index 94b6fcf2d..91abbc99e 100644 --- a/Refit.Tests/MultipartTests.cs +++ b/Refit.Tests/MultipartTests.cs @@ -308,12 +308,12 @@ public async Task MultipartUploadShouldWorkWithHeaderAndRequestProperty() Assert.Equal(someHeader, message.Headers.Authorization.ToString()); #if NET5_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 b0cc116d8..4db548d5d 100644 --- a/Refit.Tests/RequestBuilder.cs +++ b/Refit.Tests/RequestBuilder.cs @@ -2141,6 +2141,26 @@ public void InterfaceTypeShouldBeInProperties() } + [Fact] + public void MethodInfoShouldBeInProperties() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod(nameof(IContainAandB.Ping)); + var output = factory(new object[] { }); + +#if NET5_0_OR_GREATER + Assert.NotEmpty(output.Options); + Assert.Equal(typeof(IAmInterfaceA).GetMethod(nameof(IAmInterfaceA.Ping)), + ((IDictionary)output.Options)[HttpRequestMessageOptions.MethodInfo]); +#endif + +#pragma warning disable CS0618 // Type or member is obsolete + Assert.NotEmpty(output.Properties); + Assert.Equal(typeof(IAmInterfaceA).GetMethod(nameof(IAmInterfaceA.Ping)), + output.Properties[HttpRequestMessageOptions.MethodInfo]); +#pragma warning restore CS0618 // Type or member is obsolete + } + [Fact] public void DynamicRequestPropertiesWithDefaultKeysShouldBeInProperties() { @@ -2174,12 +2194,12 @@ public void DynamicRequestPropertiesWithDuplicateKeyShouldOverwritePreviousPrope #if NET5_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/HttpRequestMessageProperties.cs b/Refit/HttpRequestMessageProperties.cs index 801f990bb..0f7143b33 100644 --- a/Refit/HttpRequestMessageProperties.cs +++ b/Refit/HttpRequestMessageProperties.cs @@ -1,8 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Refit { @@ -12,8 +8,13 @@ namespace Refit public static class HttpRequestMessageOptions { /// - /// Returns the of the top-level interface where the method was called from + /// Returns the of the top-level interface where the method was called from. /// - public static string InterfaceType { get; } = "Refit.InterfaceType"; + public static string InterfaceType => "Refit.InterfaceType"; + + /// + /// Returns the of the executing method. + /// + public static string MethodInfo => "Refit.MethodInfo"; } } diff --git a/Refit/RequestBuilderImplementation.cs b/Refit/RequestBuilderImplementation.cs index d173a9141..55fe69412 100644 --- a/Refit/RequestBuilderImplementation.cs +++ b/Refit/RequestBuilderImplementation.cs @@ -733,15 +733,15 @@ Func BuildRequestFactoryForMethod(RestMethodInfo r #endif } - // Always add the top-level type of the interface to the properties + // Always add the top-level type of the interface and the current method to the properties #if NET5_0_OR_GREATER ret.Options.Set(new HttpRequestOptionsKey(HttpRequestMessageOptions.InterfaceType), TargetType); + ret.Options.Set(new HttpRequestOptionsKey(HttpRequestMessageOptions.MethodInfo), restMethod.MethodInfo); #else ret.Properties[HttpRequestMessageOptions.InterfaceType] = TargetType; + ret.Properties[HttpRequestMessageOptions.MethodInfo] = restMethod.MethodInfo; #endif - ; - // NB: The URI methods in .NET are dumb. Also, we do this // UriBuilder business so that we preserve any hardcoded query // parameters as well as add the parameterized ones.