tmenier/flurl

Flurl is a modern, fluent, asynchronous, testable, portable, buzzword-laden URL builder and HTTP client library

PM> Install-Package Flurl

Flurl is a modern, fluent, asynchronous, testable, portable, buzzword-laden URL builder and HTTP client library

Flurl

.

var result = await "https://api.mysite.com"
    .AppendPathSegment("person")
    .SetQueryParams(new { api_key = "xyz" })
    .WithOAuthBearerToken("my_oauth_token")
    .PostJsonAsync(new { first_name = firstName, last_name = lastName })
    .ReceiveJson<T>();

[Test]
public void Can_Create_Person() {
    // fake & record all http calls in the test subject
    using (var httpTest = new HttpTest()) {
        // arrange
        httpTest.RespondWith("OK", 200);

        // act
        await sut.CreatePersonAsync("Claire", "Underwood");
        
        // assert
        httpTest.ShouldHaveCalled("http://api.mysite.com/*")
            .WithVerb(HttpMethod.Post)
            .WithContentType("application/json");
    }
}

Get it on NuGet:

PM> Install-Package Flurl.Http

Or get just the stand-alone URL builder without the HTTP features:

PM> Install-Package Flurl

For updates and announcements, follow @FlurlHttp on Twitter.

For detailed documentation, please visit the main site.

Issues

Quick list of the latest Issues we found

whl2606555

whl2606555

enhancement
Icon For Comments1

Now that we can limit the max redirect count, I don't think mandatory detection of circular redirects is necessary. And there are indeed many website functions that rely on circular redirection (login, for example).

So I think we can remove the Circular Redirect Detect or at least add a switch.

develorem

develorem

enhancement
Icon For Comments2

Please describe the feature/enhancement in as much detail as possible. CancellationToken is accepted on some async methods. While I haven't audited the code base, the class I care about currently is FlurlResponse and methods such as:

  • GetJsonAsync()
  • GetStreamAsync()

The underlying calls to HttpResponseMessage.Content.ReadAsStreamAsync() supports CancellationTokens, FlurlResponse should too

tmenier

tmenier

4.0
Icon For Comments1

As part of a planned move to GitHub Actions for automating some of my processes, I'm taking a closer look at the processes themselves to see if there's room for improvements. I started by looking at a number of popular .NET open source projects to make sure I have a good handle on the latest best practices and where Flurl might differ currently. Here are some observations about those projects:

  • Almost all repos live under an organization, not a user. Flurl is taken...dang. FlurlHttp? FlurlDev? FlurlOrg?
  • Most have a very simple branching strategy: main and small number of feature branches. Smells like GitHub Flow. I'll consider dropping my dev branch and getting in the habit of creating feature branches for my own work.
  • Most diverge from GitHub Flow in one regard: releases aren't "continuous". If they were, I'd expect to see a release for every merge to main. That probably makes more sense for hosted web apps than for libraries, so I don't think I'll change anything there.
  • Most PRs tend to go fork/feature-branch -> main/main. (No need for most feature branches to live in the main repo.)
  • Most don't use GH Projects. Am I getting much value out of it? Kanban is nice for tracking issue statuses but maybe there's a simpler way?
  • I usually don't close issues until a fix is released, but it seems like a more common practice is to close them when the fix is committed/merged. (And how did I not know about auto-closing via commit comment??)

Once settled on any process changes, I'll want to add some new GH Actions workflows to automate them as much as possible.

tmenier

tmenier

breaking
Icon For Comments3

Flurl.Http 2.0 introduced the ConnectionLeaseTimeout setting for platforms that don't support ServicePoint, in order to deal with this infamous DNS problem. A lot changed since them, most notably the introduction of SocketsHttpHandler in .NET Core 2.1, which more elegantly solved the problem, is far superior to Flurl's solution, and is now the default handler out of the box with HttpClient. Flurl kept its setting around and improved upon it, primarily to cover gaps in platforms that supported neither ServicePoint nor SocketsHttpHandler.

Those platforms that support neither? .NET Core 1.x, which has been out of support for 3 years and isn't usable with Flurl anymore anyway.

So Flurl's ConnectionLeaseTimeout setting will be dropped in the next 4.0 prerelease. I don't expect much protest, but it's possible those on platforms that don't support SocketsHttpHandler (full framework and Core 2.0) might find Flurl's ConnectionLeaseTimeout setting nicer to use than ServicePoint. I'm open to hearing that argument if it's out there, but I just have a hunch not many are using it, and major version upgrades are always a good opportunity to trim some fat.

tmenier

tmenier

breaking
Icon For Comments0

This one's long overdue. It is considered a best practice for methods that support cancellation to specify CancellationToken as the last argument, and developers have come to expect it. At one point long ago, Flurl's HTTP-sending methods were enhanced to support an optional HttpCompletionOption, and in order for this not to be a breaking change, it was added to the end of these methods, leaving CancellationToken in the middle.

But major-version updates are the time to right such wrongs, even if it break things. Hopefully making this change in 4.0 won't cause people significant pains. Affected methods include all "core" and extension methods fitting the pattern SendAsync, Send{ContentType}Async}, {Verb}Async, or {Verb}{ContentType}Async.

tmenier

tmenier

breaking
Icon For Comments0

4.0 will drop the the Newtonsoft.Json dependency and use System.Text.Json instead. But that library does not support deserializing to dynamic as Newtonsoft does, making it difficult at best to continue to support Flurl's non-generic dynamic-returning methods like GetJsonAsync(). The .NET team's rationale includes the fact that dynamic is now "archived" tech and therefore newer APIs shouldn't take a dependency on it.

So far the consensus seems to favor the outright removal of these methods from the core library, but feel free to weigh in here with your thoughts.

I intend to provide a NewtonsoftSerializer implementation compatible with 4.0 and onward for anyone who wants it. This will either be in the form of a separate NuGet package or just a gist (it's pretty tiny). Some of those pre-4.0 methods could be included, although doing it without them is as easy as:

gunr2171

gunr2171

enhancement
Icon For Comments0

This feature request has two parts:

  1. New TryParse static method
  2. *Parse methods actually parse

Part 1 - TryParse

I think it would be beneficial to add a TryParse static method to the Url class. This would act similar to int.TryParse. An example of it's usage would be:

The TryParse would remove the need to have a method such as this (using 3.0.6)

Currently, Url.Parse() and new Url(string) don't actually do any parsing; they're lazy. EnsureParsed (the private instance method) only gets called when accessing one of the Url's properties. This means that a Url object can be successfully constructed from an improperly formatted URL string, and an exception will only be thrown when a property is used.

While TryParse could be implemented with my example implementation above, I think it would be better for the Url class to call EnsuredParse itself after the constructor has been run because it has access to it.

Part 2 - Parse should parse

This will cause a breaking change, and I 100% understand if it's not feasible.

int has Parse and TryParse. Both methods attempt to convert a string into an integer, but Parse will let exceptions bubble up while TryParse will capture the exception and instead return a boolean based on if one was thrown.

As a developer, I would expect the Parse method to throw an exception if the value I pass it can't be parsed. That's true with int.Parse, that's not true with Url.Parse.

tmenier

tmenier

help wanted
Icon For Comments6

Not an absolute necessity, but having heard only good things about Actions I'm thinking getting everything under the GH umbrella might be a good idea, and 4.0 might be the right time to do it. Adding some automation to the publishing process could be part of this too, or a 2nd phase. But replacing the current AppVeyor build would be a good start.

I welcome help if anyone has experience with this. @kroniak @gitfool Let me know if you have thoughts on this.

Maybe helpful: https://dusted.codes/github-actions-for-dotnet-core-nuget-packages https://dev.to/petrsvihlik/lessons-learned-migrating-from-appveyor-to-github-actions-1gh8

tmenier

tmenier

enhancement
Icon For Comments0

Add methods similar to SetQueryParam(s), except that never overwrite.

Example using SetQueryParam:

Same using AppendQueryParam:

This will also form a basis for fixing #370, which on its own is a bit involved, and would be better bang for the buck to expose this functionality more generally.

ryan-singleton

ryan-singleton

4.0
Icon For Comments6

I'm trying to write integration tests for a .NET 6 AspNetCore service.

By default, as it is an integration test, I want the Flurl http calls to do their actual http logic. However, there is one api that we are hitting where files are uploaded within the processors. That service is already tested elsewhere, so it would not be ideal to post many files during our testing strategy for no real value.

So I want to mock the behavior of calls to that API and only that API.

It would seem, then, that the answer would be to treat it something like this:

However, this results in the following exception "Call failed. No connection could be made because the target machine actively refused it. (localhost:80): PUT http://localhost/terms"

However, if I remove the HttpTest from this test, everything works. We just end up barraging the file storage API, which I do not want to do. We're getting the local base address from our WebApplicationFactory default.

What this tells me is that calling "httpTest.AllowRealHttp()" does not return the internally stored HttpClient to its default behavior for the url that I specify, such as locahost.

I apologize if I missed some documentation somewhere on this matter. Any help would be appreciated.

maxkoshevoi

maxkoshevoi

enhancement
Icon For Comments5

If I provide Flurl with Access Token URL, Client ID, and Client Secret, can it

  • obtain the OAuth token and cache it
  • send it with the request
  • use cached token when new request it issued with the same Access Token URL, Client ID, and Client Secret
  • obtain new token when old one expires
kkd83

kkd83

enhancement
Icon For Comments3

Not all responses can be purely static, some are dynamic based on the request.

For example, a user defines a request identifier in the body/header and expects the response to include this.

There are lots of good methods for filtering the request but none as far as I could see for creating a dynamic response.

Potential changes required

No breaking changes are needed

FakeHttpMessageHandler:

HttpTestSetup:

CreatedAutomated

CreatedAutomated

enhancement
Icon For Comments3

Please describe the feature/enhancement in as much detail as possible. Is it possible to make it easily use http/2? I have tried the custom httpclient factory and I am still getting the same issues with only http/1.0 and http/1.1 being supported.

It would be amazing if you could set via the client object the version to use

cremor

cremor

enhancement
Icon For Comments1

It just took some time until I figured out why my unit test that that uses WithRequestBody always fails for code that uses PostMultipartAsync. I had to check the Flurl code and finally the comment on FlurlCall.RequestBody explained it ("Available ONLY if HttpRequestMessage.Content is a Flurl.Http.Content.CapturedStringContent."). So MultipartContent is simply not supported here.

It would be nice if that could be changed. But TBH I'm not sure how the API should look like. Just supporting it in WithRequestBody (that accepts a string pattern) would be a great start. But maybe a separate WithRequestMultipart (like WithRequestUrlEncoded) would be better. That could then somehow allow asserting the parts in the CapturedMultipartContent.

Here is how I do this now with an extension method:

Usage example:

This works, but an API that requires less code for the usage would be even better. E.g. something that allows checking all headers and content with pattern support.

I also suggest a quick win until this is implemented: The fact that MultipartContent is not supported in WithRequestBody should be documented. Either directly on the method, or on https://flurl.dev/docs/testable-http/ (or on both).

kostas-baltsoft

kostas-baltsoft

enhancement
Icon For Comments6

This piece of code seems to complete only after the whole stream was read into memory. This causes timeout for some large file requests:

Shouldn't it behave something like HttpClient.GetStreamAsync Method? The Microsoft documentation clearly states that:

This operation will not block. The returned Task object will complete after the response headers are read. This method does not read nor buffer the response body.

I expect it should Flurl's method GetStreamAsync() should do the same?

eoneillcarrillo

eoneillcarrillo

enhancement
Icon For Comments10

Great job with the library!

It'd be nice to have some or all of these capabilities:

  • New Url constructor overload that takes a Url instance. This overload avoids a Url instance from being casted to string/Uri. Sort of like the Clone() method.
  • New ReadOnlyUrl class This one may be more difficult to implement. Make class Url inherit from ReadOnlyUrl; or provide an interface IReadOnlyUrl and implement that interface in class Url. The relationship would be similar to List<> and IReadOnlyList<>. Perfect for method parameters to prevent methods from accidentally changing a Url instance. Also, this prevents the unnecessary cloning of Url instances simply to fake immutability. An interface IReadOnlyUrl is even better because a parameter with this type can receive a Url or ReadOnlyUrl instance. Being immutable, code may only call ToString() or ToUri() or Clone() or create a new Url instance passing in the IReadOnlyUrl instance. Code may also access the different parts of the URL.

The problem with the current immutability option is that you're forced to cast Url to a string/Uri. Then the called code has to recreate a Url instance.

For example, in my instance, the URL is created by a piece of code. I want to send the URL to a method via parameter so the method can perform some logic. Some of this logic is controlled by segments, fragments, and query string parameters.

Currently, the calling code builds the URL, casts to string, and sends that to the method. The method has to re-parse the URL and then access the URL components.

If an IReadOnlyUrl existed, the calling code can send the Url instance in the parameter and the method wouldn't need to create anything.

Another plus of IReadOnlyUrl is code security. A method that receives a Url instance is dangerous because the dev may add mutability incorrectly. In contrast, if the method receives IReadOnlyUrl, the dev can't add mutability, even inadvertedly.

Pyrobolser

Pyrobolser

enhancement
Icon For Comments4

Hello,

I have been inheriting from FlurlClientFactoryBase for a while now, I have multiple clients returned by the factory depending on multiple BaseUrl, each client uses its own user/password and way of authenticating.

But, I am now facing a new challenge. I need to use two different couple user/password for the same client, everything else is going to be the same. So I was just thinking of creating two different clients, one configured for each couple user/password APIClientUser1 and APIClientUser2. But since they share the same BaseUrl I can't really base my caching strategy on the BaseUrl anymore. I wanted to use a simple string as a key or even a combo BaseUrl/Username but it looks like the factory only wants the get method like this Get(Url url)

Do you think that would make sense as a feature to be able to just put whatever you want as a key? Not necessarily based on the BaseUrl for your request? I would rather ask even if I realize I might need to create my own factory right now.

Thank you!

Richiban

Richiban

breaking
Icon For Comments3

[Original bug report]

The following code:

worked on v2.x but on v3 it throws the error:

It seems a bug was introduced where the base URL can't be set on the client any more.

gitfool

gitfool

enhancement
Icon For Comments4

Following up from https://github.com/tmenier/Flurl/issues/506#issuecomment-727280179.

Specifically, serializing CookieJar (and FlurlCookie) works without requiring custom converters, although Url is serialized as a nested complex type instead of as a simple string, which is not desirable.

However, deserializing the above types fails due to limited functionality and specific requirements of System.Text.Json.

FlurlRepro.zip

FlurlRepro output:

CookieJar.json:

a-teece

a-teece

bug
Icon For Comments5

When using the callbacks available in settings the function Flurl is not executing the delegate in the context of the calling code block - this causes the update of member variables to only work "sometimes"; Intermittent due to the fact the ConfigureAwait does nothing if the task has already completed.

This seems to be because configureAwait(false) is set when raising the event.

I appreciate that setting configureAwait(false) is all over Flurl, and that this is likely correct and best-practice. However; as described in https://devblogs.microsoft.com/dotnet/configureawait-faq one exception to the rule "if you’re writing general-purpose library code, use ConfigureAwait(false)" is when passing a delegate to be invoked.

Can i suggest that the calling of these delegates does not set ConfigureAwait(false).

Cohote

Cohote

enhancement
Icon For Comments2

Ran into an odd issue over the last few days. My client's server (which is a black-box to me) kept giving me a 400 Bad Request response.

After some troubleshooting, I was able to narrow it down. This may be an issue with HttpClient, and NOT Flurl, but in case, mentioning it here -

When sending a form post using a browser, the Content-Type looks like: Content-Type: multipart/form-data; boundary=---------------------------22836054058151123032940981487 (this, specifically, is from Firefox).

When using Flurl, the Content-Type looks like: Content-Type: multipart/form-data; boundary="22aa74c8-f893-4eef-a12e-b8e821fb6f12" (this is from Flurl, using full .NET 4.8.)

The boundary itself isn't the issue - it's the quotes. Apparently my client's server software can not deal with that, as the body has sections like: --22aa74c8-f893-4eef-a12e-b8e821fb6f12 .. Without the quotes. Using a tool like Wireshark, if I manually edit and resend my request without the "quotes" in the boundary, it gives me the result I'm expecting.

I'm not 100% sure what the expected result is (i.e. In the specs, quotes are only used when there's a space, and the body does NOT have the quotes. I haven't yet tried that with my client's server yet.

While this is likely an outlier, my main quesiton is - can I get rid of these quotes? (Or, specify the boundary directly?)

gitfool

gitfool

enhancement
Icon For Comments11

Following up from #514, Flurl really should seriously consider dropping unsupported target frameworks, especially given the upcoming bump in major version. What do you reckon, @tmenier?

tmenier

tmenier

enhancement
Icon For Comments0

The latest RFC describing cookies (6265) concedes that effectively preventing "supercookies" from being set at too high of a domain level (.com, .co.uk, etc.) can't be done via simple dot-counting algorithms and requires validating against an actual list of public suffixes. In addition to com, co.uk, etc, this list includes things like blogspot.com (and about 9000 others). Validation would ensure that my.blogspot.com can't set a cookie for your.blogspot.com by sending Domain=blogspot.com in the Set-Cookie header. In other words, our blogs should be treated as independent "sites" from a privacy perspective.

The official(est) list of public suffixes is maintained here. Flurl could use this list to validate, but it's too big to simply embed in the library. It could fetch the list via an HTTP call and/or allow specifying a local file cache.

Is Flurl obligated to do this validation?

No. Most any HTTP client library (including .NET's HttpClient) gives you the ability to set whatever request headers you want and ultimately can't prevent the programmer from doing something malicious. In other words, absolutely enforcing security/privacy rules is outside the scope of the library. So just to be clear, this would be an opt-in feature, not something required by any standard or spec.

eldonferranpol

eldonferranpol

enhancement
Icon For Comments1

Intending to put in a pull request for headers to allow for the passing of tuples something along these lines:

Meberem

Meberem

enhancement
Icon For Comments5

LinqPad snippet:

With this environment variable set, System.Net.Http.HttpClient has the static property DefaultProxy set to System.Net.Http.HttpEnvironmentProxy, which acts as a proxy for all the requests. When the proxy server is not accessible the error message generates is:

Whilst this is correct, no connection could be made to http://google.com it is because of the proxy server. I didn't realize I had an environment variable set, and spend a while trying to figure out what on earth was going on, would it be possible to enchance the error message when a proxy server is being used?

ghost

ghost

enhancement
Icon For Comments44

Please describe the feature/enhancement in as much detail as possible. Recent Microsoft documents show some advantages of the System.Text.Json library such as high performance ... Although I do not deny that Newtonsoft.Json is still too good and popular, however We can replace it for a better Flurl library, limiting the dependencies of external packages

Versions

Quick list of the latest released versions

Flurl.Http.4.0.0-pre2 - Jun 20, 2022

  • Default GetStreamAsync to unbuffered behavior (#630, breaking)
  • Drop WithClient extension methods (#590, breaking)
  • Drop ConnectionLeaseTimeout setting (#703, breaking)
  • Move CancellationToken to last arg everywhere that it isn't (#702, breaking)

Flurl.Http.4.0.0-pre1 - Jun 05, 2022

  • Drop dependency on Newtonsoft.Json in favor of System.Text.Json (#517)*
  • Drop non-generic dynamic-returning JSON methods (#699)
  • Update target frameworks (#544 )

*WARNING: Your code may fail in subtle ways after upgrading if it depends on things like serialization attributes or global settings from the Newtonsoft library. To continue to use Newtonsoft with Flurl.Http 4.0 and later, add and register this Newtonsoft serializer in your code.

Flurl.Http.3.2.4 - May 20, 2022

  • Create symbols package for upload to nuget.org (#601, thx @gitfool)
  • BUGFIX: NullRefEx when no body specified in RespondWith (#606)
  • Trim leading/trailing whitespace from header values (#623)

Flurl.3.0.6 - May 20, 2022

  • Create symbols package for upload to nuget.org (#601, thx @gitfool)

Flurl.Http.3.2.3 - Apr 25, 2022

  • New feature: HttpTest.SimulateException (#554)
  • Update Flurl dependency

Flurl.3.0.5 - Apr 25, 2022

  • BUGFIX: SetQueryParams + IEnumerable model prop (#672)

Flurl.Http.3.2.2 - Jan 27, 2022

Updated Flurl dependency for bug fix (#669)

Flurl.3.0.4 - Jan 27, 2022

Bug - SetQueryParams using object with nullable properties (#669)

Flurl.Http.3.2.1 - Jan 22, 2022

  • Deserialize to different type in callbacks (#571)
  • CapturedMultipartContent ctor allowing custom boundary (#611)
  • Better thread safety with headers and query params (#642)
  • IntelliSense fail - incorrect doc file name (#636)

Flurl.3.0.3 - Jan 22, 2022

Minor bug fixes for SetQueryParams (#641 & #632)

Flurl.Http.3.2.0 - May 04, 2021

Note: This was supposed to be released as 3.1 but mistakenly released as 3.2 and published, at which point it's basically too late. Oh well.

  • Do not URL-encode cookie values (#594, potentially breaking)
  • Opt-in header forwarding on redirect (#608, potentially breaking)
  • Test setups/asserts more forgiving about ignoring query strings (#596, potentially breaking)
  • net472 target to avoid unnecessary package dependency (#616)
  • BUGFIX: Sending cookies on redirect (#602)
  • BUGFIX: Redircts where Location excludes scheme (#595)
  • BUGFIX: Exception on .NET Framework if content headers are forwarded on redirect GET (#583)

Flurl.3.0.2 - May 04, 2021

  • Trim whitespace from start and end of Url (#603)
  • net472 target to avoid unnecessary package dependency (#616)
  • BUGFIX: Appending "/" to Url (#609)
  • BUGFIX: Encoding inconsistency when string is cast to object (#620)

Flurl.Http.3.0.1 - Dec 14, 2020

  • StatusCode (nullable int) property added to FlurlHttpException (#565)
  • BUGFIX: Incorrect parsing of redirect URL when Location header has query params (#586)
  • BUGFIX: FlurlCall.Succeeded error when Response is null (#573)
  • BUGFIX: Error building FlurlHttpException.Message when Call is null (#579)
  • BUGFIX: URL-encoded query params messed up cookie processing in some scenarios (#585)
  • BUGFIX: Don't clear multipart "Parts" collection after send (#580)

Flurl.3.0.1 - Dec 14, 2020

  • BUGFIX: Parsing bug when host contains upper-case characters. (#574)
  • BUGFIX: Don't add leading slash to relative URL that doesn't contain one. (#568)
  • BUGFIX: Encode date (or any other non-string) after stringifying for query params. (#582)

Flurl.Http.3.0.0 - Nov 09, 2019

New Features

  • FlurlResponse introduced, primarily to enable inspecting response and deserializing body in separate steps. (#354)
  • Major overhaul of cookie functionality. (#506)
  • Overhaul of redirect handling. (#500)
  • Tests can be set up to return different fake responses depending on the URL or any other request conditions. (#481)
  • HttpTest.ForCallsTo(...).AllowRealHttp() for allowing real calls to be made in a test for specific URLs or any other request conditions. (#225)
  • New/more complete set of test assertions for headers and cookies. (#508)
  • All extension methods on Flurl.Url and string are now also available on System.Uri. (#489)
  • Providing a body for PostAsync, PutAsync, and PatchAsync now optional. (#515)

Breaking Changes from 2.x

Making HTTP calls

  • Fluent methods that previously returned HttpResponseMessage (such GetAsync, PostAsync, etc) now return FlurlResponse. If you're using GetJsonAsync or chaining ReceiveXXX methods, this shouldn't break anything. (#354)
  • HttpCall is now FlurlCall, and several properties of FlurlCall and FlurlHttpException were moved or renamed. (#488)
  • Slightly different rules on when a redirect causes the verb to change to GET. (Never on 300, always on 303. #500)
  • Minor changes to CapturedStringContent constructors. (#452)

Headers

  • New collection type for IFlurlRequest.Headers and IFlurlClient.Headers. (#541)
  • HttpRequestMessage.GetHeaderValue and HttpResponseMessage.GetHeaderValue extension methods removed. (#553)
  • For multipart requests, Content-Type header for text parts allowed but not defaulted. (#452)
  • Cookie request header and Set-Cookie response headers are always visible in Headers collection of request and response. (#506)

Cookies

  • CookiesEnabled removed at all settings levels. (#506)
  • Cookies, WithCookie and WithCookies removed from IFlurlClient. Use CookieSession instead. (#506)
  • IFlurlRequest.Cookies is now read-only IEnumerable<(string Name, string Value)>. Use WithCookies instead. (#506)

Testing

  • When asserting a specific URL was called, it must be a full string match rather than "contains" or "starts with". Add a * wildcard to the beginning or end if you need partial match behavior. (#323)
  • When faking responses in tests, the last response in the queue becomes "sticky" rather than falling back to empty 200 responses. (#482)
  • HttpTest.ResponseQueue public property has been removed. Underlying queue implementation changed significantly to support new features, and hopefully accessing it directly isn't needed. Use RespondWith methods to build the queues.
  • Minor changes/enhancements to HttpCallAssertion. (#483)

Other

  • UseCookies and AllowAutoRedirect are disabled on the default HttpClientHandler . Any custom factory-provided handler must do the same if Flurl's new cookie and redirect features are required. (#500 & #506)
  • Default HttpClient caching strategy based on host, scheme, and port, rather than just host. (#550)
  • Dropping support for older platforms. (#544)

Bug Fixes

  • In tests, dequeuing fake responses is fully thread-safe. (#366)
  • Culture-neutral string comparisons throughout library. (#485)

Flurl.3.0.0 - Sep 13, 2019

Flurl 3.0 contains a major rewrite of the URL building/parsing engine. It brings Flurl.Url's feature set more in line with System.Uri, while also addressing some of its quirks.

New Features

  • New Url properties (#440)

    • Scheme (read/write)
    • UserInfo (read/write)
    • Host (read/write)
    • Port (read/write)
    • Authority (read-only, UserInfo + Host + Port)
    • Root (read-only, Scheme + Authority)
    • PathSegments (modifiable)
    • IsRelative (read-only)
    • IsSecureScheme (read-only, true for https or wss)
  • All URL-building extension methods currently on string now available on System.Uri (#489)

  • New fluent builder methods on Flurl.Url, System.Uri, and string:

    • RemovePathSegment() (removes the last segment)
    • RemovePath()
    • RemoveQuery()
    • Reset() (restores Url to its original state as constructed, NOT available on string)
  • Support for relative URLs (#407)

  • Parameterless constructor for Url (#518)

  • New static utility method: Url.ParsePathSegments(string) (assumes entire string is the path portion of a URL)

Breaking Changes from 2.x

  • New collection type for Url.QueryParams (#555)
  • Url.Path changed to be more in line with the formal definition. Previously it included everything (scheme, host, etc.) up to the query string. It now starts after the host/port, including the leading / if present.
  • Url.IsValid() instance method was removed. It was confusing in the case of relative URLs since arguably any string could be considered a valid relative URL. Check the IsRelative property instead. (Static Url.IsValid(string) method is still available but, same a before, returns true only for valid absolute URLs.)
  • Dropping support for older platforms (#544)

Bug fixes:

  • Url.ToUri() now works for relative URLs (#407)

Flurl.Http.2.4.2 - Apr 28, 2019

  • Updated package dependencies

Flurl.2.8.2 - Apr 28, 2019

  • Bug when decoding encoded + (#437)

Flurl.Http.2.4.1 - Feb 15, 2019

  • Multipart enhancement: allow alternate filename when adding file based on local path (#402)
  • Improvements to downloaded file name inference (#404)
  • Ensure FlurlClientFactory.Get is only called once when sending request (#374)
  • BUGFIX: Plugged memory leak by disposing CancellationTokenSource (#395)
  • BUGFIX: Prevent adding Content-Type header to multipart strings (#392)
  • BUGFIX: Missed a few cases when setting headers at request vs content level (#405)

Flurl.2.8.1 - Feb 15, 2019

  • Added Url.Clone method (#420)
  • Added Url ctor that takes a Uri (#406)
  • BUGFIX: Skip write-only props when converting objects to kv pairs (#373)

Flurl.Http.2.4.0 - Aug 31, 2018

  • Improved ConnectionLeaseTimeout implementation (#330)
  • Consistent disposal of HttpResponseMessage (#329)
  • Added ConfigureClient method to IFlurlClientFactory (#356)
  • Added optional CancelationToken to DownloadFileAsync (#360)
  • Added WithRequestUrlEncoded method to HttpCallAssertion (#347)
  • Upgraded dependencies to latest Flurl & Newtonsoft

Flurl.2.8.0 - Jul 22, 2018

  • Overridden Url.Equals method (#337)
  • Url.ToUri() method (#339)

Flurl.Http.2.3.2 - Jul 03, 2018

  • Header normalization and underscore logic used in core HTTP methods now also used in HttpTest header methods. (#331)
  • New extension methods SetHeader and GetHeaderValue on HttpRequestMessage and HttpResponseMessage, allowing you to read/write headers without caring whether they're at the message level or HttpContent level. (#331)
  • Use AsyncLocal to store HttpTest.Current in .NET Framework 4.6+ (#325)
  • BUGFIX: NullReferenceException when disposing FlurlClient constructed with existing HttpClient. (#334)
  • BUGFIX: NullReferenceException when setting a content-type header but not actually sending content. (#313)
  • BUGFIX: Calls made with FlurlClient.HttpClient result in null entries in HttpTest's call log, causing errors. (#335)
  • Better comments on methods that serialize POCOs to JSON. (#312)

Flurl.Http.2.3.1 - Apr 17, 2018

  • First-class support for OPTIONS requests via OptionsAsync (#220)
  • Support building & testing on Mac and Linux (#290 & #286, thx @nlowe )
  • FlurlClient constructor for wrapping an existing HttpClient (#298)
  • Public constructor for HttpCall so that fakes can be easily created (#304)
  • BREAKING: IFlurlClientFactory implements IDisposable (#309)
  • BUGFIX: Don't overwrite content headers when set explicitly (#256)
  • BUGFIX: WithHeader assert failed when header had space (#307)

Flurl.Http.2.3.0 - Mar 31, 2018

This release focuses on enhancements to exception handling:

  • Less verbose FlurlHttpException.Message (#297)
  • BREAKING: new FlurlParsingException, can be handled globally (#299)
  • BREAKING: FlurlHttpException.GetResponseString & GetResponseJson replaced by async equivalents (#300)
  • BREAKING: HttpCall.ErrorResponseBody removed (#300)
  • Response string available on JSON parsing errors (#288)
  • BUGFIX: Null ref exception in ShouldHaveCalled..WithContentType when body is empty (#285)

Flurl.2.7.1 - Mar 31, 2018

  • SetQueryParam with array should add multiple QueryParameters (#301, #276)
  • Added public method QueryParamCollection.Merge (#301)

Flurl.Http.2.2.1 - Mar 08, 2018

  • WithHeader should exclude/remove header if value is null (#282)

Flurl.Http.2.2.0 - Feb 18, 2018

  • Add target for .NET Standard 2.0 (#267)
  • Automatic decompression of GZIP and DEFLATE by default (#266)
  • Fix to HttpTest for MSTest runner (#207)
  • Remove TestFlurlClientFactory (#269)
  • Bump Flurl dependency to 2.7
  • Bump Json.NET dependency to 11.0

Flurl.2.7.0 - Feb 18, 2018

  • Add target for .NET Standard 2.0 (#267)
  • Do not encode reserved characters on the name side of query name/value pair (#272)

Flurl.Http.2.1.1 - Dec 19, 2017

  • Up'd Flurl dependency to 2.6

Library Stats (Sep 21, 2022)

Subscribers: 97
Stars: 3.3K
Forks: 327
Issues: 52
CLI

593

A simple command-line HTTP server

NET 5+ and run this command:

A simple command-line HTTP server

NET library for caching responses easily with an HttpClient through an API that is simple...

NET library for caching responses easily with an HttpClient through an API that is simple and elegant yet powerful

NET library for caching responses easily with an HttpClient through an API that is simple...
HTTP

912

Easyhttp is a fast HTTP client for C#

This project is active and maintained by an ever growing developer community

Easyhttp is a fast HTTP client for C#

MockHttp for HttpClient

MockHttp is a testing layer for Microsoft's HttpClient library

MockHttp for HttpClient

An implementation of HTTP Caching in

NET MVC Core and shortcomings of previous approach while the client-side mostly remained the same

An implementation of HTTP Caching in

OpenFaaS C# HTTP Template

This is no longer being maintained as the OpenFaaS community has decided to prefer

OpenFaaS C# HTTP Template

OpenFaaS C# HTTP Template

This repository contains the template for OpenFaaS using the upgraded of-watchdog which allows for higher throughput

OpenFaaS C# HTTP Template

Fluently Http Client

NET Standard with fluent APIs which are intuitive, easy to use and also highly extensible

Fluently Http Client

A lightweight library that is inpired in Angular 2+ Http Client built on top of

NET Http Client that help programmers to make asynchronous http requests

A lightweight library that is inpired in Angular 2+ Http Client built on top of