Skip to content

Commit

Permalink
v109 (#1963)
Browse files Browse the repository at this point in the history
* Added .NET Framework 471 as a target. .NET 5 is out
* Fix the media type issue with .NET 7 #1969
* `IRestClient` Interface is back
* String type for ContentType
* Added Authenticator to RestRequest
* Made Options immutable to make the client thread-safe
* Ignore exceptions parsing response cookies (#2015)
* V109 (#2010)
* Added a simple factory with opt-in

---------

Co-authored-by: Francesc Castells <fcastells76@gmail.com>
Co-authored-by: Francesc Castells <francesc.castells@sermo.com>
Co-authored-by: Edward Lichtman <E.Lichtman2@gmail.com>
  • Loading branch information
4 people committed Mar 12, 2023
1 parent 3e43c5a commit 507ed87
Show file tree
Hide file tree
Showing 105 changed files with 2,010 additions and 1,526 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: '7.0'
dotnet-version: '7.0.102'
-
name: Unshallow
run: git fetch --prune --unshallow
Expand Down
35 changes: 35 additions & 0 deletions RestSharp.sln
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RestSharp.Serializers.CsvHe
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RestSharp.Tests.Serializers.Csv", "test\RestSharp.Tests.Serializers.Csv\RestSharp.Tests.Serializers.Csv.csproj", "{E6D94FFD-7811-40BE-ABC4-6D6AB41F0060}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SourceGen", "SourceGen", "{55B8F371-B2BA-4DEE-AB98-5BAB8A21B1C2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SourceGenerator", "gen\SourceGenerator\SourceGenerator.csproj", "{FE778406-ADCF-45A1-B775-A054B55BFC50}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug.Appveyor|Any CPU = Debug.Appveyor|Any CPU
Expand Down Expand Up @@ -444,6 +448,36 @@ Global
{E6D94FFD-7811-40BE-ABC4-6D6AB41F0060}.Release|x64.Build.0 = Release|Any CPU
{E6D94FFD-7811-40BE-ABC4-6D6AB41F0060}.Release|x86.ActiveCfg = Release|Any CPU
{E6D94FFD-7811-40BE-ABC4-6D6AB41F0060}.Release|x86.Build.0 = Release|Any CPU
{FE778406-ADCF-45A1-B775-A054B55BFC50}.Debug.Appveyor|Any CPU.ActiveCfg = Debug|Any CPU
{FE778406-ADCF-45A1-B775-A054B55BFC50}.Debug.Appveyor|Any CPU.Build.0 = Debug|Any CPU
{FE778406-ADCF-45A1-B775-A054B55BFC50}.Debug.Appveyor|ARM.ActiveCfg = Debug|Any CPU
{FE778406-ADCF-45A1-B775-A054B55BFC50}.Debug.Appveyor|ARM.Build.0 = Debug|Any CPU
{FE778406-ADCF-45A1-B775-A054B55BFC50}.Debug.Appveyor|Mixed Platforms.ActiveCfg = Debug|Any CPU
{FE778406-ADCF-45A1-B775-A054B55BFC50}.Debug.Appveyor|Mixed Platforms.Build.0 = Debug|Any CPU
{FE778406-ADCF-45A1-B775-A054B55BFC50}.Debug.Appveyor|x64.ActiveCfg = Debug|Any CPU
{FE778406-ADCF-45A1-B775-A054B55BFC50}.Debug.Appveyor|x64.Build.0 = Debug|Any CPU
{FE778406-ADCF-45A1-B775-A054B55BFC50}.Debug.Appveyor|x86.ActiveCfg = Debug|Any CPU
{FE778406-ADCF-45A1-B775-A054B55BFC50}.Debug.Appveyor|x86.Build.0 = Debug|Any CPU
{FE778406-ADCF-45A1-B775-A054B55BFC50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FE778406-ADCF-45A1-B775-A054B55BFC50}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FE778406-ADCF-45A1-B775-A054B55BFC50}.Debug|ARM.ActiveCfg = Debug|Any CPU
{FE778406-ADCF-45A1-B775-A054B55BFC50}.Debug|ARM.Build.0 = Debug|Any CPU
{FE778406-ADCF-45A1-B775-A054B55BFC50}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{FE778406-ADCF-45A1-B775-A054B55BFC50}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{FE778406-ADCF-45A1-B775-A054B55BFC50}.Debug|x64.ActiveCfg = Debug|Any CPU
{FE778406-ADCF-45A1-B775-A054B55BFC50}.Debug|x64.Build.0 = Debug|Any CPU
{FE778406-ADCF-45A1-B775-A054B55BFC50}.Debug|x86.ActiveCfg = Debug|Any CPU
{FE778406-ADCF-45A1-B775-A054B55BFC50}.Debug|x86.Build.0 = Debug|Any CPU
{FE778406-ADCF-45A1-B775-A054B55BFC50}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FE778406-ADCF-45A1-B775-A054B55BFC50}.Release|Any CPU.Build.0 = Release|Any CPU
{FE778406-ADCF-45A1-B775-A054B55BFC50}.Release|ARM.ActiveCfg = Release|Any CPU
{FE778406-ADCF-45A1-B775-A054B55BFC50}.Release|ARM.Build.0 = Release|Any CPU
{FE778406-ADCF-45A1-B775-A054B55BFC50}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{FE778406-ADCF-45A1-B775-A054B55BFC50}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{FE778406-ADCF-45A1-B775-A054B55BFC50}.Release|x64.ActiveCfg = Release|Any CPU
{FE778406-ADCF-45A1-B775-A054B55BFC50}.Release|x64.Build.0 = Release|Any CPU
{FE778406-ADCF-45A1-B775-A054B55BFC50}.Release|x86.ActiveCfg = Release|Any CPU
{FE778406-ADCF-45A1-B775-A054B55BFC50}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -461,6 +495,7 @@ Global
{5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0} = {9051DDA0-E563-45D5-9504-085EBAACF469}
{2150E333-8FDC-42A3-9474-1A3956D46DE8} = {8C7B43EB-2F93-483C-B433-E28F9386AD67}
{E6D94FFD-7811-40BE-ABC4-6D6AB41F0060} = {9051DDA0-E563-45D5-9504-085EBAACF469}
{FE778406-ADCF-45A1-B775-A054B55BFC50} = {55B8F371-B2BA-4DEE-AB98-5BAB8A21B1C2}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {77FF357B-03FA-4FA5-A68F-BFBE5800FEBA}
Expand Down
4 changes: 2 additions & 2 deletions docs/.vuepress/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ module.exports = {
themeConfig: {
logo: "/restsharp.png",
navbar: [
{text: "Migration to v107", link: "/v107/"},
{text: "Migration from legacy", link: "/v107/"},
{text: "Documentation", link: "/intro.html"},
{text: "Get help", link: "/support/"},
{text: "NuGet", link: "https://nuget.org/packages/RestSharp"}
Expand All @@ -34,7 +34,7 @@ module.exports = {
"/v107/": [
{
text: "",
header: "Migration to v107",
header: "Migration from legacy",
children: [
"/v107/README.md"
]
Expand Down
4 changes: 2 additions & 2 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ heroText: RestSharp
tagline: Probably, the most popular REST API client library for .NET
actions:
- text: Get Started →
link: /v107/
link: /intro.html
features:
- title: Serialization
details: JSON, XML and custom serialization and deserialization
Expand All @@ -24,7 +24,7 @@ footer: Apache 2.0 Licensed | Copyright (c) .NET Foundation and Contributors

RestSharp is probably the most popular HTTP client library for .NET. Featuring automatic serialization and deserialization, request and response type detection, variety of authentications and other useful features, it is being used by hundreds of thousands of projects.

RestSharp passed over 165 million downloads on NuGet, with average daily download count close to 42,000. It's being used by many popular OSS projects, including Roslyn and Swagger.
RestSharp passed over 190 million downloads on NuGet, with average daily download count over 43,000. It's being used by many popular OSS projects, including Roslyn and Swagger.

Supported by [AWS](https://aws.amazon.com/developer/language/net/solutions/).
<div style="text-align: center;"><a href="https://aws.amazon.com"><img src="/aws_logo.png" alt="AWS logo"></a></div>
Expand Down
22 changes: 22 additions & 0 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,28 @@ First, there's `DownloadDataAsync`, which returns `Task<byte[]`. It will read th

For larger responses, you can use `DownloadStreamAsync` that returns `Task<Stream>`. This function allows you to open a stream reader and asynchronously stream large responses to memory or disk.


## Reusing HttpClient

RestSharp uses `HttpClient` internally to make HTTP requests. It's possible to reuse the same `HttpClient` instance for multiple `RestClient` instances. This is useful when you want to share the same connection pool between multiple `RestClient` instances.

One way of doing it is to use `RestClient` constructors that accept an instance of `HttpClient` or `HttpMessageHandler` as an argument. Note that in that case not all the options provided via `RestClientOptions` will be used. Here is the list of options that will work:

- `BaseAddress` will be used to set the base address of the `HttpClient` instance if base address is not set there already.
- `MaxTimeout`
- `UserAgent` will be set if the `User-Agent` header is not set on the `HttpClient` instance already.
- `Expect100Continue`

Another option is to use a simple HTTP client factory. It is a static factory, which holds previously instantiated `HttpClient` instances. It can be used to create `RestClient` instances that share the same `HttpClient` instance. The cache key is the `BaseUrl` provided in the options. When you opt-in to use the factory and don't set `BaseUrl`, the `RestClient` constructor will crash.

```csharp
var client = new RestClient(new Uri("https://example.org/api"), useClientFactory: true);
```

::: warning
Note that the `RestClient` constructor will not reconfigure the `HttpClient` instance if it's already in the cache. Therefore, you should not try using the factory when providing different options for the same base URL.
:::

## Blazor support

Inside a Blazor webassembly app, you can make requests to external API endpoints. Microsoft examples show how to do it with `HttpClient`, and it's also possible to use RestSharp for the same purpose.
Expand Down
19 changes: 6 additions & 13 deletions docs/v107/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
---
title: RestSharp Next (v107)
title: RestSharp Next (v107+)
---

## RestSharp v107
## RestSharp v107+

The latest version of RestSharp is v107. It's a major upgrade, which contains quite a few breaking changes.
RestSharp got a major upgrade in v107, which contains quite a few breaking changes.

The most important change is that RestSharp stop using the legacy `HttpWebRequest` class, and uses well-known 'HttpClient' instead.
This move solves lots of issues, like hanging connections due to improper `HttpClient` instance cache, updated protocols support, and many other problems.
Expand All @@ -17,7 +17,7 @@ Finally, most of the interfaces are now gone.

### RestClient and options

The `IRestClient` interface is deprecated. You will be using the `RestClient` class instance.
The `IRestClient` interface is deprecated in v107, but brought back in v109. The new interface, however, has a much smaller API compared to previous versions. You will be using the `RestClient` class instance.

Most of the client options are moved to `RestClientOptions`. If you can't find the option you used to set on `IRestClient`, check the options, it's probably there.

Expand Down Expand Up @@ -187,23 +187,16 @@ The next RestSharp version presumably solves the following issues:
## Deprecated interfaces

The following interfaces are removed from RestSharp:
- `IRestClient`
- `IRestRequest`
- `IRestResponse`
- `IHttp`

### Motivation

All the deprecated interfaces had only one implementation in RestSharp, so those interfaces were abstracting nothing. It is now unclear what was the purpose for adding those interfaces initially.

What about mocking it, you might ask? The answer is: what would you do if you use a plain `HttpClient` instance? It doesn't implement any interface for the same reason - there's nothing to abstract, and there's only one implementation. We don't recommend mocking `RestClient` in your tests when you are testing against APIs that are controlled by you or people in your organisation. Test your clients against the real thing, as REST calls are I/O-bound. Mocking REST calls is like mocking database calls, and lead to a lot of issues in production even if all your tests pass against mocks.

As mentioned in [Recommended usage](#recommended-usage), we advise against using `RestClient` in the application code, and advocate wrapping it inside particular API client classes. Those classes would be under your control, and you are totally free to use interfaces there. If you absolutely must mock, you can mock your interfaces instead.

### Mocking

Mocking an infrastructure component like RestSharp (or HttpClient) is not the best idea. Even if you check that all the parameters are added correctly to the request, your "unit test" will only give you a false sense of safety that your code actually works. But, you have no guarantee that the remote server will accept your request, or if you can handle the actual response correctly.

However, since v109 you can still mock the `IRestClient` interface, but you only need to implement the `ExecuteAsync` method. The `ExecuteAsync` method is the only one that actually makes a call to the remote server. All other methods are just wrappers around it.

The best way to test HTTP calls is to make some, using the actual service you call. However, you might still want to check if your API client forms requests in a certain way. You might also be sure about what the remote server responds to your calls with, so you can build a set of JSON (or XML) responses, so you can simulate remote calls.

It is perfectly doable without using interfaces. As RestSharp uses `HttpClient` internally, it certainly uses `HttpMessageHandler`. Features like delegating handlers allow you to intercept the request pipeline, inspect the request, and substitute the response. You can do it yourself, or use a library like [MockHttp](https://github.com/richardszalay/mockhttp). They have an example provided in the repository README, so we have changed it for RestClient here:
Expand Down

0 comments on commit 507ed87

Please sign in to comment.