Skip to content

Commit 1370c33

Browse files
Added remaining overloads (PATCH, HEAD, OPTIONS, DELETE) (#2050)
* Added remaining overloads (PATCH, HEAD, OPTIONS, DELETE) * Fixed sync extensions to use `IRestClient`
1 parent 84db183 commit 1370c33

20 files changed

+1056
-809
lines changed

benchmarks/RestSharp.Benchmarks/RestSharp.Benchmarks.csproj

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99

1010
<ItemGroup>
1111
<PackageReference Include="AutoFixture" Version="4.18.0" />
12-
<PackageReference Include="BenchmarkDotNet" Version="0.13.2" />
12+
<PackageReference Include="BenchmarkDotNet" Version="0.13.5" />
13+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.6.0" />
1314
</ItemGroup>
1415
<ItemGroup>
1516
<ProjectReference Include="..\..\src\RestSharp.Serializers.NewtonsoftJson\RestSharp.Serializers.NewtonsoftJson.csproj" />

gen/SourceGenerator/SourceGenerator.csproj

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@
1111
</PropertyGroup>
1212

1313
<ItemGroup>
14-
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" PrivateAssets="All"/>
15-
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.5.0" PrivateAssets="All"/>
14+
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" PrivateAssets="All" />
15+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.6.0" PrivateAssets="All" />
1616
</ItemGroup>
1717

1818
<ItemGroup>
19-
<None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false"/>
19+
<None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
2020
</ItemGroup>
2121
</Project>
File renamed without changes.

src/RestSharp/Request/RequestContent.cs

+32-34
Original file line numberDiff line numberDiff line change
@@ -36,47 +36,44 @@ public RequestContent(RestClient client, RestRequest request) {
3636
_parameters = new RequestParameters(_request.Parameters.Union(_client.DefaultParameters));
3737
}
3838

39-
public HttpContent BuildContent()
40-
{
41-
var postParameters = _parameters.GetContentParameters(_request.Method).ToArray();
39+
public HttpContent BuildContent() {
40+
var postParameters = _parameters.GetContentParameters(_request.Method).ToArray();
4241
var postParametersExists = postParameters.Length > 0;
4342
var bodyParametersExists = _request.TryGetBodyParameter(out var bodyParameter);
44-
var filesExists = _request.Files.Any();
43+
var filesExists = _request.Files.Any();
4544

46-
if (filesExists)
47-
AddFiles();
45+
if (_request.HasFiles() ||
46+
BodyShouldBeMultipartForm(bodyParameter) ||
47+
filesExists ||
48+
_request.AlwaysMultipartFormData) {
49+
Content = CreateMultipartFormDataContent();
50+
}
51+
52+
if (filesExists) AddFiles();
4853

49-
if (bodyParametersExists)
50-
AddBody(postParametersExists, bodyParameter!);
54+
if (bodyParametersExists) AddBody(postParametersExists, bodyParameter!);
5155

52-
if (postParametersExists)
53-
AddPostParameters(postParameters);
56+
if (postParametersExists) AddPostParameters(postParameters);
5457

5558
AddHeaders();
5659

5760
return Content!;
5861
}
59-
60-
void AddFiles()
61-
{
62-
// File uploading without multipart/form-data
63-
if (_request.AlwaysSingleFileAsContent && _request.Files.Count == 1)
64-
{
65-
var fileParameter = _request.Files.First();
66-
Content = ToStreamContent(fileParameter);
67-
return;
68-
}
69-
70-
var mpContent = new MultipartFormDataContent(GetOrSetFormBoundary());
71-
72-
foreach (var fileParameter in _request.Files)
73-
mpContent.Add(ToStreamContent(fileParameter));
74-
75-
Content = mpContent;
76-
}
77-
78-
StreamContent ToStreamContent(FileParameter fileParameter)
79-
{
62+
63+
void AddFiles() {
64+
// File uploading without multipart/form-data
65+
if (_request is { AlwaysSingleFileAsContent: true, Files.Count: 1 }) {
66+
var fileParameter = _request.Files.First();
67+
Content?.Dispose();
68+
Content = ToStreamContent(fileParameter);
69+
return;
70+
}
71+
72+
var mpContent = Content as MultipartFormDataContent;
73+
foreach (var fileParameter in _request.Files) mpContent!.Add(ToStreamContent(fileParameter));
74+
}
75+
76+
StreamContent ToStreamContent(FileParameter fileParameter) {
8077
var stream = fileParameter.GetFile();
8178
_streams.Add(stream);
8279
var streamContent = new StreamContent(stream);
@@ -123,7 +120,9 @@ HttpContent GetSerialized() {
123120
}
124121
}
125122

126-
static bool BodyShouldBeMultipartForm(BodyParameter bodyParameter) {
123+
static bool BodyShouldBeMultipartForm(BodyParameter? bodyParameter) {
124+
if (bodyParameter == null) return false;
125+
127126
var bodyContentType = bodyParameter.ContentType.OrValue(bodyParameter.Name);
128127
return bodyParameter.Name.IsNotEmpty() && bodyParameter.Name != bodyContentType;
129128
}
@@ -139,8 +138,7 @@ MultipartFormDataContent CreateMultipartFormDataContent() {
139138
return mpContent;
140139
}
141140

142-
void AddBody(bool hasPostParameters, BodyParameter bodyParameter)
143-
{
141+
void AddBody(bool hasPostParameters, BodyParameter bodyParameter) {
144142
var bodyContent = Serialize(bodyParameter);
145143

146144
// we need to send the body

src/RestSharp/RestClient.Async.cs

+4-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,10 @@ async Task<HttpResponse> ExecuteRequestAsync(RestRequest request, CancellationTo
7979

8080
request.ValidateParameters();
8181
var authenticator = request.Authenticator ?? Options.Authenticator;
82-
if (authenticator != null) await authenticator.Authenticate(this, request).ConfigureAwait(false);
82+
83+
if (authenticator != null) {
84+
await authenticator.Authenticate(this, request).ConfigureAwait(false);
85+
}
8386

8487
using var requestContent = new RequestContent(this, request);
8588

src/RestSharp/RestClient.Extensions.Config.cs

-37
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// Copyright (c) .NET Foundation and Contributors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
//
15+
16+
namespace RestSharp;
17+
18+
public static partial class RestClientExtensions {
19+
/// <summary>
20+
/// Executes a DELETE-style request asynchronously, authenticating if needed
21+
/// </summary>
22+
/// <param name="client"></param>
23+
/// <param name="request">Request to be executed</param>
24+
/// <param name="cancellationToken">Cancellation token</param>
25+
public static Task<RestResponse> ExecuteDeleteAsync(this IRestClient client, RestRequest request, CancellationToken cancellationToken = default)
26+
=> client.ExecuteAsync(request, Method.Delete, cancellationToken);
27+
28+
/// <summary>
29+
/// Executes a DELETE-style synchronously, authenticating if needed
30+
/// </summary>
31+
/// <param name="client"></param>
32+
/// <param name="request">Request to be executed</param>
33+
public static RestResponse ExecuteDelete(this IRestClient client, RestRequest request)
34+
=> AsyncHelpers.RunSync(() => client.ExecuteAsync(request, Method.Delete));
35+
36+
/// <summary>
37+
/// Executes a DELETE-style request asynchronously, authenticating if needed.
38+
/// The response content then gets deserialized to T.
39+
/// </summary>
40+
/// <typeparam name="T">Target deserialization type</typeparam>
41+
/// <param name="client"></param>
42+
/// <param name="request">Request to be executed</param>
43+
/// <param name="cancellationToken">The cancellation token</param>
44+
/// <returns>Deserialized response content</returns>
45+
public static Task<RestResponse<T>> ExecuteDeleteAsync<T>(
46+
this IRestClient client,
47+
RestRequest request,
48+
CancellationToken cancellationToken = default
49+
)
50+
=> client.ExecuteAsync<T>(request, Method.Delete, cancellationToken);
51+
52+
/// <summary>
53+
/// Executes a DELETE-style request synchronously, authenticating if needed.
54+
/// The response content then gets deserialized to T.
55+
/// </summary>
56+
/// <typeparam name="T">Target deserialization type</typeparam>
57+
/// <param name="client"></param>
58+
/// <param name="request">Request to be executed</param>
59+
/// <returns>Deserialized response content</returns>
60+
public static RestResponse<T> ExecuteDelete<T>(this IRestClient client, RestRequest request)
61+
=> AsyncHelpers.RunSync(() => client.ExecuteAsync<T>(request, Method.Delete));
62+
63+
/// <summary>
64+
/// Execute the request using DELETE HTTP method. Exception will be thrown if the request does not succeed.
65+
/// The response data is deserialized to the Data property of the returned response object.
66+
/// </summary>
67+
/// <param name="client">RestClient instance</param>
68+
/// <param name="request">The request</param>
69+
/// <param name="cancellationToken">Cancellation token</param>
70+
/// <typeparam name="T">Expected result type</typeparam>
71+
/// <returns></returns>
72+
public static async Task<T?> DeleteAsync<T>(this IRestClient client, RestRequest request, CancellationToken cancellationToken = default) {
73+
var response = await client.ExecuteAsync<T>(request, Method.Delete, cancellationToken).ConfigureAwait(false);
74+
return response.ThrowIfError().Data;
75+
}
76+
77+
/// <summary>
78+
/// Execute the request using DELETE HTTP method. Exception will be thrown if the request does not succeed.
79+
/// The response data is deserialized to the Data property of the returned response object.
80+
/// </summary>
81+
/// <param name="client">RestClient instance</param>
82+
/// <param name="request">The request</param>
83+
/// <typeparam name="T">Expected result type</typeparam>
84+
/// <returns></returns>
85+
public static T? Delete<T>(this IRestClient client, RestRequest request) => AsyncHelpers.RunSync(() => client.DeleteAsync<T>(request));
86+
87+
/// <summary>
88+
/// Execute the request using DELETE HTTP method. Exception will be thrown if the request does not succeed.
89+
/// </summary>
90+
/// <param name="client">RestClient instance</param>
91+
/// <param name="request">The request</param>
92+
/// <param name="cancellationToken">Cancellation token</param>
93+
/// <returns></returns>
94+
public static async Task<RestResponse> DeleteAsync(this IRestClient client, RestRequest request, CancellationToken cancellationToken = default) {
95+
var response = await client.ExecuteAsync(request, Method.Delete, cancellationToken).ConfigureAwait(false);
96+
return response.ThrowIfError();
97+
}
98+
99+
/// <summary>
100+
/// Execute the request using DELETE HTTP method. Exception will be thrown if the request does not succeed.
101+
/// </summary>
102+
/// <param name="client">RestClient instance</param>
103+
/// <param name="request">The request</param>
104+
/// <returns></returns>
105+
public static RestResponse Delete(this IRestClient client, RestRequest request) => AsyncHelpers.RunSync(() => client.DeleteAsync(request));
106+
}

0 commit comments

Comments
 (0)