diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0a5457e3b..b072e9f85 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,6 +13,7 @@ jobs: with: configuration: Release productNamespacePrefix: "Refit" + dotNetBuild: true useVisualStudioPreview: false useMauiCheckDotNetTool: false srcFolder: "./" diff --git a/InterfaceStubGenerator.Shared/InterfaceStubGenerator.cs b/InterfaceStubGenerator.Shared/InterfaceStubGenerator.cs index 0e45cbacc..7af867752 100644 --- a/InterfaceStubGenerator.Shared/InterfaceStubGenerator.cs +++ b/InterfaceStubGenerator.Shared/InterfaceStubGenerator.cs @@ -16,6 +16,9 @@ namespace Refit.Generator // * Generate the data we need for the template based on interface method // defn's + /// + /// InterfaceStubGeneratorV2. + /// [Generator] #if ROSLYN_4 public class InterfaceStubGeneratorV2 : IIncrementalGenerator @@ -49,6 +52,10 @@ public class InterfaceStubGenerator : ISourceGenerator #if !ROSLYN_4 + /// + /// Executes the specified context. + /// + /// The context. public void Execute(GeneratorExecutionContext context) { if (context.SyntaxReceiver is not SyntaxReceiver receiver) @@ -71,6 +78,18 @@ out var refitInternalNamespace } #endif + /// + /// Generates the interface stubs. + /// + /// The type of the context. + /// The context. + /// The report diagnostic. + /// The add source. + /// The compilation. + /// The refit internal namespace. + /// The candidate methods. + /// The candidate interfaces. + /// public void GenerateInterfaceStubs( TContext context, Action reportDiagnostic, @@ -160,7 +179,7 @@ ImmutableArray candidateInterfaces { // Add the interface to the generation list with an empty set of methods // The logic already looks for base refit methods - interfaces.Add(ifaceSymbol, new List()); + interfaces.Add(ifaceSymbol, []); var isAnnotated = model.GetNullableContext(iface.SpanStart) == NullableContext.Enabled; @@ -170,7 +189,7 @@ ImmutableArray candidateInterfaces } // Bail out if there aren't any interfaces to generate code for. This may be the case with transitives - if (!interfaces.Any()) + if (interfaces.Count == 0) return; var supportsNullable = options.LanguageVersion >= LanguageVersion.CSharp8; @@ -275,7 +294,7 @@ internal static partial class Generated } } - string ProcessInterface( + static string ProcessInterface( TContext context, Action reportDiagnostic, INamedTypeSymbol interfaceSymbol, @@ -450,7 +469,7 @@ partial class {ns}{classDeclaration} /// /// True if directly from the type we're generating for, false for methods found on base interfaces /// Contains the unique member names in the interface scope. - void ProcessRefitMethod( + static void ProcessRefitMethod( StringBuilder source, IMethodSymbol methodSymbol, bool isTopLevel, @@ -519,7 +538,7 @@ HashSet memberNames WriteMethodClosing(source); } - void ProcessDisposableMethod(StringBuilder source, IMethodSymbol methodSymbol) + static void ProcessDisposableMethod(StringBuilder source, IMethodSymbol methodSymbol) { WriteMethodOpening(source, methodSymbol, true); @@ -532,7 +551,7 @@ void ProcessDisposableMethod(StringBuilder source, IMethodSymbol methodSymbol) WriteMethodClosing(source); } - string GenerateConstraints( + static string GenerateConstraints( ImmutableArray typeParameters, bool isOverrideOrExplicitImplementation ) @@ -551,7 +570,7 @@ bool isOverrideOrExplicitImplementation return source.ToString(); } - void WriteConstraitsForTypeParameter( + static void WriteConstraitsForTypeParameter( StringBuilder source, ITypeParameterSymbol typeParameter, bool isOverrideOrExplicitImplementation @@ -601,7 +620,7 @@ bool isOverrideOrExplicitImplementation } } - void ProcessNonRefitMethod( + static void ProcessNonRefitMethod( TContext context, Action reportDiagnostic, StringBuilder source, @@ -687,7 +706,7 @@ static bool ContainsTypeParameter(ITypeSymbol symbol) } } - void WriteMethodOpening( + static void WriteMethodOpening( StringBuilder source, IMethodSymbol methodSymbol, bool isExplicitInterface, @@ -737,7 +756,7 @@ void WriteMethodOpening( ); } - void WriteMethodClosing(StringBuilder source) => source.Append(@" }"); + static void WriteMethodClosing(StringBuilder source) => source.Append(@" }"); static string UniqueName(string name, HashSet methodNames) { @@ -753,7 +772,7 @@ static string UniqueName(string name, HashSet methodNames) return candidateName; } - bool IsRefitMethod(IMethodSymbol? methodSymbol, INamedTypeSymbol httpMethodAttibute) + static bool IsRefitMethod(IMethodSymbol? methodSymbol, INamedTypeSymbol httpMethodAttibute) { return methodSymbol ?.GetAttributes() @@ -763,6 +782,11 @@ bool IsRefitMethod(IMethodSymbol? methodSymbol, INamedTypeSymbol httpMethodAttib #if ROSLYN_4 + /// + /// Initializes the specified context. + /// + /// The context. + /// public void Initialize(IncrementalGeneratorInitializationContext context) { // We're looking for methods with an attribute that are in an interface @@ -772,7 +796,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) is MethodDeclarationSyntax { Parent: InterfaceDeclarationSyntax, - AttributeLists: { Count: > 0 } + AttributeLists.Count: > 0 }, (context, cancellationToken) => (MethodDeclarationSyntax)context.Node ); @@ -834,6 +858,11 @@ out var refitInternalNamespace #else + /// + /// Initializes the specified context. + /// + /// The context. + /// public void Initialize(GeneratorInitializationContext context) { context.RegisterForSyntaxNotifications(() => new SyntaxReceiver()); diff --git a/Refit.Benchmarks/Refit.Benchmarks.csproj b/Refit.Benchmarks/Refit.Benchmarks.csproj index 9c49c4437..ab5e7133a 100644 --- a/Refit.Benchmarks/Refit.Benchmarks.csproj +++ b/Refit.Benchmarks/Refit.Benchmarks.csproj @@ -6,6 +6,7 @@ Exe net6.0 false + $(NoWarn);CS1591 diff --git a/Refit.HttpClientFactory/HttpClientFactoryExtensions.cs b/Refit.HttpClientFactory/HttpClientFactoryExtensions.cs index b4920df5e..27f5a0f72 100644 --- a/Refit.HttpClientFactory/HttpClientFactoryExtensions.cs +++ b/Refit.HttpClientFactory/HttpClientFactoryExtensions.cs @@ -8,6 +8,9 @@ namespace Refit { + /// + /// HttpClientFactoryExtensions. + /// public static class HttpClientFactoryExtensions { /// diff --git a/Refit.HttpClientFactory/SettingsFor.cs b/Refit.HttpClientFactory/SettingsFor.cs index a6f8a948d..eb656b127 100644 --- a/Refit.HttpClientFactory/SettingsFor.cs +++ b/Refit.HttpClientFactory/SettingsFor.cs @@ -1,14 +1,36 @@ namespace Refit { + /// + /// ISettingsFor + /// public interface ISettingsFor { + /// + /// Gets the settings. + /// + /// + /// The settings. + /// RefitSettings? Settings { get; } } - public class SettingsFor : ISettingsFor + /// + /// SettingsFor. + /// + /// + /// + /// + /// Initializes a new instance of the class. + /// + /// The settings. + public class SettingsFor(RefitSettings? settings) : ISettingsFor { - public SettingsFor(RefitSettings? settings) => Settings = settings; - - public RefitSettings? Settings { get; } + /// + /// Gets the settings. + /// + /// + /// The settings. + /// + public RefitSettings? Settings { get; } = settings; } } diff --git a/Refit.Newtonsoft.Json/NewtonsoftJsonContentSerializer.cs b/Refit.Newtonsoft.Json/NewtonsoftJsonContentSerializer.cs index f881e15e1..05d9b7ff7 100644 --- a/Refit.Newtonsoft.Json/NewtonsoftJsonContentSerializer.cs +++ b/Refit.Newtonsoft.Json/NewtonsoftJsonContentSerializer.cs @@ -1,11 +1,7 @@ -using System; -using System.IO; -using System.Linq; -using System.Net.Http; +using System.Net.Http; using System.Reflection; using System.Text; -using System.Threading; -using System.Threading.Tasks; + using Newtonsoft.Json; namespace Refit @@ -13,12 +9,21 @@ namespace Refit /// /// A implementing using the Newtonsoft.Json APIs /// - public sealed class NewtonsoftJsonContentSerializer : IHttpContentSerializer + /// + /// Creates a new instance with the specified parameters + /// + /// The serialization settings to use for the current instance + public sealed class NewtonsoftJsonContentSerializer(JsonSerializerSettings? jsonSerializerSettings) : IHttpContentSerializer { /// /// The instance providing the JSON serialization settings to use /// - readonly Lazy jsonSerializerSettings; + readonly Lazy jsonSerializerSettings = new( + () => + jsonSerializerSettings + ?? JsonConvert.DefaultSettings?.Invoke() + ?? new JsonSerializerSettings() + ); /// /// Creates a new instance @@ -26,20 +31,6 @@ public sealed class NewtonsoftJsonContentSerializer : IHttpContentSerializer public NewtonsoftJsonContentSerializer() : this(null) { } - /// - /// Creates a new instance with the specified parameters - /// - /// The serialization settings to use for the current instance - public NewtonsoftJsonContentSerializer(JsonSerializerSettings? jsonSerializerSettings) - { - this.jsonSerializerSettings = new Lazy( - () => - jsonSerializerSettings - ?? JsonConvert.DefaultSettings?.Invoke() - ?? new JsonSerializerSettings() - ); - } - /// public HttpContent ToHttpContent(T item) { @@ -58,6 +49,11 @@ public HttpContent ToHttpContent(T item) CancellationToken cancellationToken = default ) { + if (content == null) + { + return default; + } + var serializer = JsonSerializer.Create(jsonSerializerSettings.Value); using var stream = await content @@ -69,15 +65,24 @@ public HttpContent ToHttpContent(T item) return serializer.Deserialize(jsonTextReader); } + /// + /// Calculates what the field name should be for the given property. This may be affected by custom attributes the serializer understands + /// + /// A PropertyInfo object. + /// + /// The calculated field name. + /// + /// propertyInfo public string? GetFieldNameForProperty(PropertyInfo propertyInfo) { - if (propertyInfo is null) - throw new ArgumentNullException(nameof(propertyInfo)); - - return propertyInfo + return propertyInfo switch + { + null => throw new ArgumentNullException(nameof(propertyInfo)), + _ => propertyInfo .GetCustomAttributes(true) .Select(a => a.PropertyName) - .FirstOrDefault(); + .FirstOrDefault() + }; } } } diff --git a/Refit.Tests/InterfaceStubGenerator.cs b/Refit.Tests/InterfaceStubGenerator.cs index 0708a3ddd..ff7dedbf8 100644 --- a/Refit.Tests/InterfaceStubGenerator.cs +++ b/Refit.Tests/InterfaceStubGenerator.cs @@ -1292,5 +1292,5 @@ Task PostMessage([Body] T message, U param1, V param2) where U : T; } - public interface IMessage { } + public interface IMessage; } diff --git a/Refit.Tests/Refit.Tests.csproj b/Refit.Tests/Refit.Tests.csproj index 074250ac6..752e54f57 100644 --- a/Refit.Tests/Refit.Tests.csproj +++ b/Refit.Tests/Refit.Tests.csproj @@ -6,6 +6,7 @@ net462;net6.0;net7.0;net8.0 false https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json + $(NoWarn);CS1591;CA1819;CA2000;CA2007;CA1056;CA1707;CA1861;xUnit1031 diff --git a/Refit.Tests/RequestBuilder.cs b/Refit.Tests/RequestBuilder.cs index 88305fce5..48ca590e2 100644 --- a/Refit.Tests/RequestBuilder.cs +++ b/Refit.Tests/RequestBuilder.cs @@ -1064,7 +1064,7 @@ public void DynamicHeaderCollectionShouldWork() Assert.Equal("1", fixture.Headers["Api-Version"]); Assert.Equal(4, fixture.Headers.Count); - Assert.Equal(1, fixture.HeaderCollectionParameterMap.Count); + Assert.Single(fixture.HeaderCollectionParameterMap); Assert.True(fixture.HeaderCollectionParameterMap.Contains(1)); } @@ -1087,7 +1087,7 @@ public void DynamicHeaderCollectionShouldWorkWithBody(string interfaceMethodName Assert.NotNull(fixture.BodyParameterInfo); Assert.Null(fixture.AuthorizeParameterInfo); - Assert.Equal(1, fixture.HeaderCollectionParameterMap.Count); + Assert.Single(fixture.HeaderCollectionParameterMap); Assert.True(fixture.HeaderCollectionParameterMap.Contains(2)); } @@ -1112,7 +1112,7 @@ public void DynamicHeaderCollectionShouldWorkWithoutBody(string interfaceMethodN Assert.Null(fixture.BodyParameterInfo); Assert.Null(fixture.AuthorizeParameterInfo); - Assert.Equal(1, fixture.HeaderCollectionParameterMap.Count); + Assert.Single(fixture.HeaderCollectionParameterMap); Assert.True(fixture.HeaderCollectionParameterMap.Contains(1)); } @@ -1143,7 +1143,7 @@ public void DynamicHeaderCollectionShouldWorkWithInferredBody(string interfaceMe Assert.NotNull(fixture.BodyParameterInfo); Assert.Null(fixture.AuthorizeParameterInfo); - Assert.Equal(1, fixture.HeaderCollectionParameterMap.Count); + Assert.Single(fixture.HeaderCollectionParameterMap); Assert.True(fixture.HeaderCollectionParameterMap.Contains(1)); Assert.Equal(2, fixture.BodyParameterInfo.Item3); } @@ -1170,7 +1170,7 @@ public void DynamicHeaderCollectionShouldWorkWithAuthorize(string interfaceMetho Assert.Null(fixture.BodyParameterInfo); Assert.NotNull(fixture.AuthorizeParameterInfo); - Assert.Equal(1, fixture.HeaderCollectionParameterMap.Count); + Assert.Single(fixture.HeaderCollectionParameterMap); Assert.True(fixture.HeaderCollectionParameterMap.Contains(2)); } @@ -1197,7 +1197,7 @@ public void DynamicHeaderCollectionShouldWorkWithDynamicHeader(string interfaceM Assert.Single(fixture.HeaderParameterMap); Assert.Equal("Authorization", fixture.HeaderParameterMap[1]); - Assert.Equal(1, fixture.HeaderCollectionParameterMap.Count); + Assert.Single(fixture.HeaderCollectionParameterMap); Assert.True(fixture.HeaderCollectionParameterMap.Contains(2)); input = typeof(IRestMethodInfoTests); @@ -1222,7 +1222,7 @@ public void DynamicHeaderCollectionShouldWorkWithDynamicHeader(string interfaceM Assert.Single(fixture.HeaderParameterMap); Assert.Equal("Authorization", fixture.HeaderParameterMap[2]); - Assert.Equal(1, fixture.HeaderCollectionParameterMap.Count); + Assert.Single(fixture.HeaderCollectionParameterMap); Assert.True(fixture.HeaderCollectionParameterMap.Contains(1)); } @@ -1255,7 +1255,7 @@ string interfaceMethodName Assert.Single(fixture.HeaderParameterMap); Assert.Equal("X-PathMember", fixture.HeaderParameterMap[0]); - Assert.Equal(1, fixture.HeaderCollectionParameterMap.Count); + Assert.Single(fixture.HeaderCollectionParameterMap); Assert.True(fixture.HeaderCollectionParameterMap.Contains(1)); } @@ -1276,7 +1276,7 @@ public void DynamicHeaderCollectionInMiddleOfParamsShouldWork(string interfaceMe Assert.Null(fixture.BodyParameterInfo); Assert.Equal("baz", fixture.QueryParameterMap[2]); - Assert.Equal(1, fixture.HeaderCollectionParameterMap.Count); + Assert.Single(fixture.HeaderCollectionParameterMap); Assert.True(fixture.HeaderCollectionParameterMap.Contains(1)); } @@ -1323,7 +1323,7 @@ public void DynamicHeaderCollectionShouldWorkWithProperty(string interfaceMethod Assert.Single(fixture.PropertyParameterMap); - Assert.Equal(1, fixture.HeaderCollectionParameterMap.Count); + Assert.Single(fixture.HeaderCollectionParameterMap); Assert.True(fixture.HeaderCollectionParameterMap.Contains(0)); } @@ -2162,6 +2162,11 @@ protected override async Task SendAsync( CancellationToken cancellationToken ) { + if (request == null) + { + throw new ArgumentNullException(nameof(request)); + } + RequestMessage = request; if (request.Content != null) { @@ -2177,19 +2182,9 @@ CancellationToken cancellationToken } } - public class TestUrlParameterFormatter : IUrlParameterFormatter + public class TestUrlParameterFormatter(string constantOutput) : IUrlParameterFormatter { - readonly string constantParameterOutput; - - public TestUrlParameterFormatter(string constantOutput) - { - constantParameterOutput = constantOutput; - } - - public string Format(object value, ICustomAttributeProvider attributeProvider, Type type) - { - return constantParameterOutput; - } + public string Format(object value, ICustomAttributeProvider attributeProvider, Type type) => constantOutput; } // Converts enums to ints and adds a suffix to strings to test that both dictionary keys and values are formatted. diff --git a/Refit.Tests/RestService.cs b/Refit.Tests/RestService.cs index ec7090165..5f4d76523 100644 --- a/Refit.Tests/RestService.cs +++ b/Refit.Tests/RestService.cs @@ -1726,7 +1726,7 @@ public async Task ValueTypesArentValidButTheyWorkAnyway() } [Fact] - public async void MissingBaseUrlThrowsArgumentException() + public async Task MissingBaseUrlThrowsArgumentException() { var client = new HttpClient(); // No BaseUrl specified @@ -2151,7 +2151,7 @@ public void ShouldThrowArgumentExceptionIfHostUrlIsNull() return; } - Assert.False(true, "Exception not thrown."); + Assert.Fail("Exception not thrown."); } [Fact] @@ -2167,7 +2167,7 @@ public void ShouldThrowArgumentExceptionIfHostUrlIsEmpty() return; } - Assert.False(true, "Exception not thrown."); + Assert.Fail("Exception not thrown."); } [Fact] @@ -2183,7 +2183,7 @@ public void ShouldThrowArgumentExceptionIfHostUrlIsWhitespace() return; } - Assert.False(true, "Exception not thrown."); + Assert.Fail("Exception not thrown."); } [Fact] diff --git a/Refit/ApiException.cs b/Refit/ApiException.cs index 51f9d5dfb..5330232f8 100644 --- a/Refit/ApiException.cs +++ b/Refit/ApiException.cs @@ -60,6 +60,17 @@ public class ApiException : Exception /// public RefitSettings RefitSettings { get; } + /// + /// Initializes a new instance of the class. + /// + /// The message. + /// The HTTP method. + /// The content. + /// The status code. + /// The reason phrase. + /// The headers. + /// The refit settings. + /// The inner exception. protected ApiException( HttpRequestMessage message, HttpMethod httpMethod, @@ -82,6 +93,18 @@ protected ApiException( innerException ) { } + /// + /// Initializes a new instance of the class. + /// + /// The exception message. + /// The message. + /// The HTTP method. + /// The content. + /// The status code. + /// The reason phrase. + /// The headers. + /// The refit settings. + /// The inner exception. protected ApiException( string exceptionMessage, HttpRequestMessage message, diff --git a/Refit/ApiResponse.cs b/Refit/ApiResponse.cs index cf1ff9d46..119720c40 100644 --- a/Refit/ApiResponse.cs +++ b/Refit/ApiResponse.cs @@ -65,10 +65,19 @@ public ApiResponse( /// public RefitSettings Settings { get; } + /// + /// HTTP response headers. + /// public HttpResponseHeaders Headers => response.Headers; + /// + /// HTTP response content headers as defined in RFC 2616. + /// public HttpContentHeaders? ContentHeaders => response.Content?.Headers; + /// + /// Indicates whether the request was successful. + /// #if NET6_0_OR_GREATER [MemberNotNullWhen(true, nameof(Content))] [MemberNotNullWhen(true, nameof(ContentHeaders))] @@ -76,16 +85,34 @@ public ApiResponse( #endif public bool IsSuccessStatusCode => response.IsSuccessStatusCode; + /// + /// The reason phrase which typically is sent by the server together with the status code. + /// public string? ReasonPhrase => response.ReasonPhrase; + /// + /// The HTTP Request message which led to this response. + /// public HttpRequestMessage? RequestMessage => response.RequestMessage; + /// + /// HTTP response status code. + /// public HttpStatusCode StatusCode => response.StatusCode; + /// + /// HTTP Message version. + /// public Version Version => response.Version; + /// + /// The object in case of unsuccessful response. + /// public ApiException? Error { get; private set; } + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// public void Dispose() { Dispose(true); diff --git a/Refit/Attributes.cs b/Refit/Attributes.cs index 7e6e0b995..b092ff20d 100644 --- a/Refit/Attributes.cs +++ b/Refit/Attributes.cs @@ -2,121 +2,164 @@ namespace Refit { - public abstract class HttpMethodAttribute : Attribute + /// + /// HttpMethodAttribute. + /// + /// + /// + /// Initializes a new instance of the class. + /// + /// The path. + public abstract class HttpMethodAttribute(string path) : Attribute { - public HttpMethodAttribute(string path) - { - Path = path; - } - + /// + /// Gets the method. + /// + /// + /// The method. + /// public abstract HttpMethod Method { get; } - public virtual string Path { get; protected set; } + /// + /// Gets or sets the path. + /// + /// + /// The path. + /// + public virtual string Path { get; protected set; } = path; } /// /// Send the request with HTTP method 'GET'. /// + /// + /// Initializes a new instance of the class. + /// + /// The path. [AttributeUsage(AttributeTargets.Method)] - public class GetAttribute : HttpMethodAttribute + public sealed class GetAttribute(string path) : HttpMethodAttribute(path) { - public GetAttribute(string path) - : base(path) { } - - public override HttpMethod Method - { - get { return HttpMethod.Get; } - } + /// + /// Gets the method. + /// + /// + /// The method. + /// + public override HttpMethod Method => HttpMethod.Get; } /// /// Send the request with HTTP method 'POST'. /// + /// + /// Initializes a new instance of the class. + /// + /// The path. [AttributeUsage(AttributeTargets.Method)] - public class PostAttribute : HttpMethodAttribute + public sealed class PostAttribute(string path) : HttpMethodAttribute(path) { - public PostAttribute(string path) - : base(path) { } - - public override HttpMethod Method - { - get { return HttpMethod.Post; } - } + /// + /// Gets the method. + /// + /// + /// The method. + /// + public override HttpMethod Method => HttpMethod.Post; } /// /// Send the request with HTTP method 'PUT'. /// + /// + /// Initializes a new instance of the class. + /// + /// The path. [AttributeUsage(AttributeTargets.Method)] - public class PutAttribute : HttpMethodAttribute + public sealed class PutAttribute(string path) : HttpMethodAttribute(path) { - public PutAttribute(string path) - : base(path) { } - - public override HttpMethod Method - { - get { return HttpMethod.Put; } - } + /// + /// Gets the method. + /// + /// + /// The method. + /// + public override HttpMethod Method => HttpMethod.Put; } /// /// Send the request with HTTP method 'DELETE'. /// + /// + /// Initializes a new instance of the class. + /// + /// The path. [AttributeUsage(AttributeTargets.Method)] - public class DeleteAttribute : HttpMethodAttribute + public sealed class DeleteAttribute(string path) : HttpMethodAttribute(path) { - public DeleteAttribute(string path) - : base(path) { } - - public override HttpMethod Method - { - get { return HttpMethod.Delete; } - } + /// + /// Gets the method. + /// + /// + /// The method. + /// + public override HttpMethod Method => HttpMethod.Delete; } /// /// Send the request with HTTP method 'PATCH'. /// + /// + /// Initializes a new instance of the class. + /// + /// The path. [AttributeUsage(AttributeTargets.Method)] - public class PatchAttribute : HttpMethodAttribute + public sealed class PatchAttribute(string path) : HttpMethodAttribute(path) { - public PatchAttribute(string path) - : base(path) { } - - public override HttpMethod Method - { - get { return new HttpMethod("PATCH"); } - } + /// + /// Gets the method. + /// + /// + /// The method. + /// + public override HttpMethod Method => new HttpMethod("PATCH"); } /// /// Send the request with HTTP method 'OPTION'. /// + /// + /// Initializes a new instance of the class. + /// + /// The path. [AttributeUsage(AttributeTargets.Method)] - public class OptionsAttribute : HttpMethodAttribute + public sealed class OptionsAttribute(string path) : HttpMethodAttribute(path) { - public OptionsAttribute(string path) - : base(path) { } - - public override HttpMethod Method - { - get { return new HttpMethod("OPTIONS"); } - } + /// + /// Gets the method. + /// + /// + /// The method. + /// + public override HttpMethod Method => new HttpMethod("OPTIONS"); } /// /// Send the request with HTTP method 'HEAD'. /// + /// + /// Initializes a new instance of the class. + /// + /// The path. [AttributeUsage(AttributeTargets.Method)] - public class HeadAttribute : HttpMethodAttribute + public sealed class HeadAttribute(string path) : HttpMethodAttribute(path) { - public HeadAttribute(string path) - : base(path) { } - - public override HttpMethod Method - { - get { return HttpMethod.Head; } - } + /// + /// Gets the method. + /// + /// + /// The method. + /// + public override HttpMethod Method => HttpMethod.Head; } /// @@ -125,15 +168,20 @@ public override HttpMethod Method /// /// Currently, multipart methods only support the following parameter types: , array, , . /// + /// + /// Initializes a new instance of the class. + /// + /// The boundary text. [AttributeUsage(AttributeTargets.Method)] - public class MultipartAttribute : Attribute + public sealed class MultipartAttribute(string boundaryText = "----MyGreatBoundary") : Attribute { - public string BoundaryText { get; private set; } - - public MultipartAttribute(string boundaryText = "----MyGreatBoundary") - { - BoundaryText = boundaryText; - } + /// + /// Gets the boundary text. + /// + /// + /// The boundary text. + /// + public string BoundaryText { get; private set; } = boundaryText; } /// @@ -175,21 +223,34 @@ public enum BodySerializationMethod /// - For all other types, the object will be serialized using the content serializer specified in the request's . /// [AttributeUsage(AttributeTargets.Parameter)] - public class BodyAttribute : Attribute + public sealed class BodyAttribute : Attribute { + /// + /// Initializes a new instance of the class. + /// public BodyAttribute() { } - public BodyAttribute(bool buffered) - { - Buffered = buffered; - } + /// + /// Initializes a new instance of the class. + /// + /// if set to true [buffered]. + public BodyAttribute(bool buffered) => Buffered = buffered; + /// + /// Initializes a new instance of the class. + /// + /// The serialization method. + /// if set to true [buffered]. public BodyAttribute(BodySerializationMethod serializationMethod, bool buffered) { SerializationMethod = serializationMethod; Buffered = buffered; } + /// + /// Initializes a new instance of the class. + /// + /// The serialization method. public BodyAttribute( BodySerializationMethod serializationMethod = BodySerializationMethod.Default ) @@ -197,72 +258,106 @@ public BodyAttribute( SerializationMethod = serializationMethod; } - public bool? Buffered { get; set; } - public BodySerializationMethod SerializationMethod { get; protected set; } = + /// + /// Gets or sets the buffered. + /// + /// + /// The buffered. + /// + public bool? Buffered { get; } + + /// + /// Gets or sets the serialization method. + /// + /// + /// The serialization method. + /// + public BodySerializationMethod SerializationMethod { get; } = BodySerializationMethod.Default; } /// /// Override the key that will be sent in the query string. /// + /// + /// Initializes a new instance of the class. + /// + /// The name. [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property)] - public class AliasAsAttribute : Attribute + public sealed class AliasAsAttribute(string name) : Attribute { - public AliasAsAttribute(string name) - { - Name = name; - } - - public string Name { get; protected set; } + /// + /// Gets or sets the name. + /// + /// + /// The name. + /// + public string Name { get; protected set; } = name; } + /// + /// Initializes a new instance of the class. + /// + /// The name. [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property)] [Obsolete( "Use Refit.StreamPart, Refit.ByteArrayPart, Refit.FileInfoPart or if necessary, inherit from Refit.MultipartItem", false )] - public class AttachmentNameAttribute : Attribute + public sealed class AttachmentNameAttribute(string name) : Attribute { - public AttachmentNameAttribute(string name) - { - Name = name; - } - - public string Name { get; protected set; } + /// + /// Gets or sets the name. + /// + /// + /// The name. + /// + public string Name { get; protected set; } = name; } /// /// Allows you to provide a Dictionary of headers to be added to the request. /// [AttributeUsage(AttributeTargets.Parameter)] - public class HeaderCollectionAttribute : Attribute { } + public sealed class HeaderCollectionAttribute : Attribute { } /// /// Add multiple headers to the request. /// + /// + /// Initializes a new instance of the class. + /// + /// The headers. [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Method)] - public class HeadersAttribute : Attribute + public sealed class HeadersAttribute(params string[] headers) : Attribute { - public HeadersAttribute(params string[] headers) - { - Headers = headers ?? Array.Empty(); - } - - public string[] Headers { get; } + /// + /// Gets the headers. + /// + /// + /// The headers. + /// + public string[] Headers { get; } = headers ?? Array.Empty(); } /// /// Add a header to the request. /// + /// + /// Initializes a new instance of the class. + /// + /// The header. [AttributeUsage(AttributeTargets.Parameter)] - public class HeaderAttribute : Attribute + public sealed class HeaderAttribute(string header) : Attribute { - public HeaderAttribute(string header) - { - Header = header; - } - public string Header { get; } + /// + /// Gets the header. + /// + /// + /// The header. + /// + public string Header { get; } = header; } /// @@ -271,10 +366,17 @@ public HeaderAttribute(string header) /// If no key is specified then the key will be defaulted to the name of the parameter. /// [AttributeUsage(AttributeTargets.Parameter)] - public class PropertyAttribute : Attribute + public sealed class PropertyAttribute : Attribute { + /// + /// Initializes a new instance of the class. + /// public PropertyAttribute() { } + /// + /// Initializes a new instance of the class. + /// + /// The key. public PropertyAttribute(string key) { Key = key; @@ -292,38 +394,61 @@ public PropertyAttribute(string key) /// /// Default authorization scheme: Bearer /// + /// + /// Initializes a new instance of the class. + /// + /// The scheme. [AttributeUsage(AttributeTargets.Parameter)] - public class AuthorizeAttribute : Attribute + public sealed class AuthorizeAttribute(string scheme = "Bearer") : Attribute { - public AuthorizeAttribute(string scheme = "Bearer") - { - Scheme = scheme; - } - - public string Scheme { get; } + /// + /// Gets the scheme. + /// + /// + /// The scheme. + /// + public string Scheme { get; } = scheme; } /// /// Associated value will be added to the request Uri as query-string, using a delimiter to split the values. (default: '.') /// [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property)] // Property is to allow for form url encoded data - public class QueryAttribute : Attribute + public sealed class QueryAttribute : Attribute { CollectionFormat? collectionFormat; + /// + /// Initializes a new instance of the class. + /// public QueryAttribute() { } + /// + /// Initializes a new instance of the class. + /// + /// The delimiter. public QueryAttribute(string delimiter) { Delimiter = delimiter; } + /// + /// Initializes a new instance of the class. + /// + /// The delimiter. + /// The prefix. public QueryAttribute(string delimiter, string prefix) { Delimiter = delimiter; Prefix = prefix; } + /// + /// Initializes a new instance of the class. + /// + /// The delimiter. + /// The prefix. + /// The format. public QueryAttribute(string delimiter, string prefix, string format) { Delimiter = delimiter; @@ -331,6 +456,10 @@ public QueryAttribute(string delimiter, string prefix, string format) Format = format; } + /// + /// Initializes a new instance of the class. + /// + /// The collection format. public QueryAttribute(CollectionFormat collectionFormat) { CollectionFormat = collectionFormat; @@ -386,20 +515,29 @@ public CollectionFormat CollectionFormat set => collectionFormat = value; } + /// + /// Gets a value indicating whether this instance is collection format specified. + /// + /// + /// true if this instance is collection format specified; otherwise, false. + /// public bool IsCollectionFormatSpecified => collectionFormat.HasValue; } + /// + /// QueryUriFormatAttribute. + /// + /// + /// + /// Initializes a new instance of the class. + /// + /// The URI format. [AttributeUsage(AttributeTargets.Method)] - public class QueryUriFormatAttribute : Attribute + public sealed class QueryUriFormatAttribute(UriFormat uriFormat) : Attribute { - public QueryUriFormatAttribute(UriFormat uriFormat) - { - UriFormat = uriFormat; - } - /// /// Specifies how the Query Params should be encoded. /// - public UriFormat UriFormat { get; } + public UriFormat UriFormat { get; } = uriFormat; } } diff --git a/Refit/JsonContentSerializer.cs b/Refit/JsonContentSerializer.cs index 420f99ac2..e681107a0 100644 --- a/Refit/JsonContentSerializer.cs +++ b/Refit/JsonContentSerializer.cs @@ -3,28 +3,50 @@ namespace Refit { + /// + /// JsonContentSerializer. + /// + /// [Obsolete( "Use NewtonsoftJsonContentSerializer in the Refit.Newtonsoft.Json package instead", true )] public class JsonContentSerializer : IHttpContentSerializer { - public HttpContent ToHttpContent(T item) - { - throw new NotImplementedException(); - } + /// + /// Converts to httpcontent. + /// + /// Type of the object to serialize from. + /// Object to serialize. + /// + /// that contains the serialized object. + /// + /// + public HttpContent ToHttpContent(T item) => throw new NotImplementedException(); + /// + /// Deserializes an object of type from an object. + /// + /// Type of the object to serialize to. + /// HttpContent object to deserialize. + /// CancellationToken to abort the deserialization. + /// + /// The deserialized object of type . + /// + /// public Task FromHttpContentAsync( HttpContent content, CancellationToken cancellationToken = default - ) - { - throw new NotImplementedException(); - } + ) => throw new NotImplementedException(); - public string GetFieldNameForProperty(PropertyInfo propertyInfo) - { - throw new NotImplementedException(); - } + /// + /// Calculates what the field name should be for the given property. This may be affected by custom attributes the serializer understands + /// + /// A PropertyInfo object. + /// + /// The calculated field name. + /// + /// + public string GetFieldNameForProperty(PropertyInfo propertyInfo) => throw new NotImplementedException(); } } diff --git a/Refit/MultipartItem.cs b/Refit/MultipartItem.cs index fef54f019..f0fad7ca4 100644 --- a/Refit/MultipartItem.cs +++ b/Refit/MultipartItem.cs @@ -3,26 +3,54 @@ namespace Refit { - public abstract class MultipartItem + /// + /// Initializes a new instance of the class. + /// + /// Name of the file. + /// Type of the content. + /// fileName + public abstract class MultipartItem(string fileName, string? contentType) { - public MultipartItem(string fileName, string? contentType) - { - FileName = fileName ?? throw new ArgumentNullException(nameof(fileName)); - ContentType = contentType; - } - + /// + /// Initializes a new instance of the class. + /// + /// Name of the file. + /// Type of the content. + /// The name. public MultipartItem(string fileName, string? contentType, string? name) : this(fileName, contentType) { Name = name; } + /// + /// Gets the name. + /// + /// + /// The name. + /// public string? Name { get; } - public string? ContentType { get; } - - public string FileName { get; } - + /// + /// Gets the type of the content. + /// + /// + /// The type of the content. + /// + public string? ContentType { get; } = contentType; + + /// + /// Gets the name of the file. + /// + /// + /// The name of the file. + /// + public string FileName { get; } = fileName ?? throw new ArgumentNullException(nameof(fileName)); + + /// + /// Converts to content. + /// + /// public HttpContent ToContent() { var content = CreateContent(); @@ -34,27 +62,43 @@ public HttpContent ToContent() return content; } + /// + /// Creates the content. + /// + /// protected abstract HttpContent CreateContent(); } /// /// Allows the use of a generic in a multipart form body. /// - public class StreamPart : MultipartItem + /// + /// Initializes a new instance of the class. + /// + /// The value. + /// Name of the file. + /// Type of the content. + /// The name. + /// value + public class StreamPart( + Stream value, + string fileName, + string? contentType = null, + string? name = null + ) : MultipartItem(fileName, contentType, name) { - public StreamPart( - Stream value, - string fileName, - string? contentType = null, - string? name = null - ) - : base(fileName, contentType, name) - { - Value = value ?? throw new ArgumentNullException(nameof(value)); - } - - public Stream Value { get; } - + /// + /// Gets the value. + /// + /// + /// The value. + /// + public Stream Value { get; } = value ?? throw new ArgumentNullException(nameof(value)); + + /// + /// Creates the content. + /// + /// protected override HttpContent CreateContent() { return new StreamContent(Value); @@ -64,21 +108,34 @@ protected override HttpContent CreateContent() /// /// Allows the use of a array in a multipart form body. /// - public class ByteArrayPart : MultipartItem + /// + /// Initializes a new instance of the class. + /// + /// The value. + /// Name of the file. + /// Type of the content. + /// The name. + /// value + public class ByteArrayPart( + byte[] value, + string fileName, + string? contentType = null, + string? name = null + ) : MultipartItem(fileName, contentType, name) { - public ByteArrayPart( - byte[] value, - string fileName, - string? contentType = null, - string? name = null - ) - : base(fileName, contentType, name) - { - Value = value ?? throw new ArgumentNullException(nameof(value)); - } - - public byte[] Value { get; } + /// + /// Gets the value. + /// + /// + /// The value. + /// + public byte[] Value { get; } = value ?? throw new ArgumentNullException(nameof(value)); + + /// + /// Creates the content. + /// + /// protected override HttpContent CreateContent() { return new ByteArrayContent(Value); @@ -88,21 +145,33 @@ protected override HttpContent CreateContent() /// /// Allows the use of a object in a multipart form body. /// - public class FileInfoPart : MultipartItem + /// + /// Initializes a new instance of the class. + /// + /// The value. + /// Name of the file. + /// Type of the content. + /// The name. + /// value + public class FileInfoPart( + FileInfo value, + string fileName, + string? contentType = null, + string? name = null + ) : MultipartItem(fileName, contentType, name) { - public FileInfoPart( - FileInfo value, - string fileName, - string? contentType = null, - string? name = null - ) - : base(fileName, contentType, name) - { - Value = value ?? throw new ArgumentNullException(nameof(value)); - } - - public FileInfo Value { get; } - + /// + /// Gets the value. + /// + /// + /// The value. + /// + public FileInfo Value { get; } = value ?? throw new ArgumentNullException(nameof(value)); + + /// + /// Creates the content. + /// + /// protected override HttpContent CreateContent() { return new StreamContent(Value.OpenRead()); diff --git a/Refit/PushStreamContent.cs b/Refit/PushStreamContent.cs index 8b58db275..ac5f20787 100644 --- a/Refit/PushStreamContent.cs +++ b/Refit/PushStreamContent.cs @@ -185,14 +185,9 @@ protected override void Dispose(bool disposing) /// // https://github.com/ASP-NET-MVC/aspnetwebstack/blob/d5188c8a75b5b26b09ab89bedfd7ee635ae2ff17/src/System.Net.Http.Formatting/Internal/DelegatingStream.cs [ExcludeFromCodeCoverage] - abstract class DelegatingStream : Stream + abstract class DelegatingStream(Stream innerStream) : Stream { - protected DelegatingStream(Stream innerStream) - { - InnerStream = innerStream ?? throw new ArgumentNullException(nameof(innerStream)); - } - - protected Stream InnerStream { get; private set; } + protected Stream InnerStream { get; private set; } = innerStream ?? throw new ArgumentNullException(nameof(innerStream)); public override bool CanRead { diff --git a/Refit/RefitSettings.cs b/Refit/RefitSettings.cs index 1e91f91fd..d4e124d93 100644 --- a/Refit/RefitSettings.cs +++ b/Refit/RefitSettings.cs @@ -90,10 +90,10 @@ public Func< /// /// Sets the default behavior when sending a request's body content. (defaults to false, request body is not streamed to the server) /// - public bool Buffered { get; set; } = false; + public bool Buffered { get; set; } /// - /// Optional Key-Value pairs, which are displayed in the property or . + /// Optional Key-Value pairs, which are displayed in the property . /// public Dictionary HttpRequestMessageOptions { get; set; } } @@ -136,6 +136,13 @@ public interface IHttpContentSerializer /// public interface IUrlParameterFormatter { + /// + /// Formats the specified value. + /// + /// The value. + /// The attribute provider. + /// The type. + /// string? Format(object? value, ICustomAttributeProvider attributeProvider, Type type); } @@ -144,6 +151,12 @@ public interface IUrlParameterFormatter /// public interface IFormUrlEncodedParameterFormatter { + /// + /// Formats the specified value. + /// + /// The value. + /// The format string. + /// string? Format(object? value, string? formatString); } @@ -157,6 +170,14 @@ static readonly ConcurrentDictionary< ConcurrentDictionary > EnumMemberCache = new(); + /// + /// Formats the specified parameter value. + /// + /// The parameter value. + /// The attribute provider. + /// The type. + /// + /// attributeProvider public virtual string? Format( object? parameterValue, ICustomAttributeProvider attributeProvider, @@ -214,6 +235,12 @@ static readonly ConcurrentDictionary< ConcurrentDictionary > EnumMemberCache = new(); + /// + /// Formats the specified parameter value. + /// + /// The parameter value. + /// The format string. + /// public virtual string? Format(object? parameterValue, string? formatString) { if (parameterValue == null) @@ -255,11 +282,20 @@ public class DefaultApiExceptionFactory readonly RefitSettings refitSettings; + /// + /// Initializes a new instance of the class. + /// + /// The refit settings. public DefaultApiExceptionFactory(RefitSettings refitSettings) { this.refitSettings = refitSettings; } + /// + /// Creates the asynchronous. + /// + /// The response message. + /// public Task CreateAsync(HttpResponseMessage responseMessage) { if (!responseMessage.IsSuccessStatusCode) diff --git a/Refit/RequestBuilder.cs b/Refit/RequestBuilder.cs index d543269ea..8c2741387 100644 --- a/Refit/RequestBuilder.cs +++ b/Refit/RequestBuilder.cs @@ -2,8 +2,18 @@ namespace Refit { + /// + /// IRequestBuilder. + /// public interface IRequestBuilder { + /// + /// Builds the rest result function for method. + /// + /// Name of the method. + /// The parameter types. + /// The generic argument types. + /// Func BuildRestResultFuncForMethod( string methodName, Type[]? parameterTypes = null, @@ -11,31 +21,47 @@ public interface IRequestBuilder ); } + /// + /// + /// + /// public interface IRequestBuilder : IRequestBuilder { } + /// + /// RequestBuilder. + /// public static class RequestBuilder { - static readonly IRequestBuilderFactory PlatformRequestBuilderFactory = - new RequestBuilderFactory(); + static readonly RequestBuilderFactory PlatformRequestBuilderFactory = new(); - public static IRequestBuilder ForType(RefitSettings? settings) - { - return PlatformRequestBuilderFactory.Create(settings); - } + /// + /// Fors the type. + /// + /// + /// The settings. + /// + public static IRequestBuilder ForType(RefitSettings? settings) => PlatformRequestBuilderFactory.Create(settings); - public static IRequestBuilder ForType() - { - return PlatformRequestBuilderFactory.Create(null); - } + /// + /// Fors the type. + /// + /// + /// + public static IRequestBuilder ForType() => PlatformRequestBuilderFactory.Create(null); - public static IRequestBuilder ForType(Type refitInterfaceType, RefitSettings? settings) - { - return PlatformRequestBuilderFactory.Create(refitInterfaceType, settings); - } + /// + /// Fors the type. + /// + /// Type of the refit interface. + /// The settings. + /// + public static IRequestBuilder ForType(Type refitInterfaceType, RefitSettings? settings) => PlatformRequestBuilderFactory.Create(refitInterfaceType, settings); - public static IRequestBuilder ForType(Type refitInterfaceType) - { - return PlatformRequestBuilderFactory.Create(refitInterfaceType, null); - } + /// + /// Fors the type. + /// + /// Type of the refit interface. + /// + public static IRequestBuilder ForType(Type refitInterfaceType) => PlatformRequestBuilderFactory.Create(refitInterfaceType, null); } } diff --git a/Refit/RestMethodInfo.cs b/Refit/RestMethodInfo.cs index 2403de863..dbd4c3294 100644 --- a/Refit/RestMethodInfo.cs +++ b/Refit/RestMethodInfo.cs @@ -13,6 +13,9 @@ internal static class IsExternalInit { } namespace Refit { + /// + /// RestMethodInfo + /// public record RestMethodInfo( string Name, Type HostingType, @@ -95,11 +98,11 @@ public RestMethodInfoInternal( Headers = ParseHeaders(methodInfo); HeaderParameterMap = BuildHeaderParameterMap(parameterList); - HeaderCollectionParameterMap = BuildHeaderCollectionParameterMap(parameterList); + HeaderCollectionParameterMap = RestMethodInfoInternal.BuildHeaderCollectionParameterMap(parameterList); PropertyParameterMap = BuildRequestPropertyMap(parameterList); // get names for multipart attachments - AttachmentNameMap = new Dictionary>(); + AttachmentNameMap = []; if (IsMultipart) { for (var i = 0; i < parameterList.Count; i++) @@ -125,7 +128,7 @@ public RestMethodInfoInternal( } } - QueryParameterMap = new Dictionary(); + QueryParameterMap = []; for (var i = 0; i < parameterList.Count; i++) { if ( @@ -165,7 +168,7 @@ public RestMethodInfoInternal( || ReturnResultType == typeof(IApiResponse); } - private ISet BuildHeaderCollectionParameterMap(List parameterList) + static HashSet BuildHeaderCollectionParameterMap(List parameterList) { var headerCollectionMap = new HashSet(); @@ -202,7 +205,7 @@ private ISet BuildHeaderCollectionParameterMap(List paramete } public RestMethodInfo ToRestMethodInfo() => - new RestMethodInfo(Name, Type, MethodInfo, RelativePath, ReturnType); + new(Name, Type, MethodInfo, RelativePath, ReturnType); static Dictionary BuildRequestPropertyMap(List parameterList) { @@ -238,7 +241,7 @@ static PropertyInfo[] GetParameterProperties(ParameterInfo parameter) static void VerifyUrlPathIsSane(string relativePath) { - if (relativePath == "") + if (string.IsNullOrEmpty(relativePath)) return; if (!relativePath.StartsWith("/")) @@ -288,9 +291,9 @@ List parameterInfo name = rawName; } - if (paramValidationDict.ContainsKey(name)) //if it's a standard parameter + if (paramValidationDict.TryGetValue(name, out var value)) //if it's a standard parameter { - var paramType = paramValidationDict[name].ParameterType; + var paramType = value.ParameterType; if (isRoundTripping && paramType != typeof(string)) { throw new ArgumentException( @@ -302,8 +305,7 @@ List parameterInfo : ParameterType.Normal; var restMethodParameterInfo = new RestMethodParameterInfo( name, - paramValidationDict[name] - ) +value) { Type = parameterType }; @@ -321,21 +323,21 @@ List parameterInfo #endif } //else if it's a property on a object parameter - else if (objectParamValidationDict.ContainsKey(name) && !isRoundTripping) + else if (objectParamValidationDict.TryGetValue(name, out var value1) && !isRoundTripping) { - var property = objectParamValidationDict[name]; + var property = value1; var parameterIndex = parameterInfo.IndexOf(property.Item1); //If we already have this parameter, add additional ParameterProperty - if (ret.ContainsKey(parameterIndex)) + if (ret.TryGetValue(parameterIndex, out var value2)) { - if (!ret[parameterIndex].IsObjectPropertyParameter) + if (!value2.IsObjectPropertyParameter) { throw new ArgumentException( $"Parameter {property.Item1.Name} matches both a parameter and nested parameter on a parameter object" ); } - //we already have this parameter. add the additional property - ret[parameterIndex].ParameterProperties.Add( + + value2.ParameterProperties.Add( new RestMethodParameterProperty(name, property.Item2) ); }