commit
a025bf274b
@ -2,7 +2,7 @@
|
||||
<package >
|
||||
<metadata>
|
||||
<id>Flurl.Http</id>
|
||||
<version>1.0.3</version>
|
||||
<version>1.1.0-pre</version>
|
||||
<title>Flurl.Http</title>
|
||||
<authors>Todd Menier</authors>
|
||||
<projectUrl>http://tmenier.github.io/Flurl</projectUrl>
|
||||
@ -13,6 +13,7 @@
|
||||
A fluent, portable, testable HTTP client library that extends Flurl's URL builder chain.
|
||||
</description>
|
||||
<releaseNotes>
|
||||
1.1.0 - Parallel testing (github #67), better DI/IoC/mocking support (github #146), assert query params (github #102)
|
||||
1.0.3 - .NET Core 1.0.1, fixed assembly references (github #131)
|
||||
1.0.2 - Updated Flurl dependency to 2.2.1 https://www.nuget.org/packages/Flurl/2.2.1
|
||||
1.0.1 - Updated Flurl dependency to 2.2 https://www.nuget.org/packages/Flurl/2.2.0
|
||||
|
@ -8,45 +8,37 @@ using NUnit.Framework;
|
||||
|
||||
namespace Flurl.Test.Http
|
||||
{
|
||||
[TestFixture]
|
||||
[TestFixture, Parallelizable]
|
||||
public class ClientLifetimeTests
|
||||
{
|
||||
private readonly TestHttpClientFactoryWithCounter _fac;
|
||||
|
||||
public ClientLifetimeTests() {
|
||||
_fac = new TestHttpClientFactoryWithCounter();
|
||||
FlurlHttp.Configure(settings => settings.HttpClientFactory = _fac);
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public void CreateHttpTest() {
|
||||
_fac.NewClientCount = 0;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task autodispose_true_creates_new_httpclients() {
|
||||
var fc = new FlurlClient("http://www.mysite.com", true);
|
||||
var fac = new TestHttpClientFactoryWithCounter();
|
||||
var fc = new FlurlClient("http://www.mysite.com") {
|
||||
Settings = { HttpClientFactory = fac, AutoDispose = true }
|
||||
};
|
||||
var x = await fc.GetAsync();
|
||||
var y = await fc.GetAsync();
|
||||
var z = await fc.GetAsync();
|
||||
Assert.AreEqual(3, _fac.NewClientCount);
|
||||
Assert.AreEqual(3, fac.NewClientCount);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task autodispose_false_resues_httpclient() {
|
||||
var fc = new FlurlClient("http://www.mysite.com", false);
|
||||
public async Task autodispose_false_reuses_httpclient() {
|
||||
var fac = new TestHttpClientFactoryWithCounter();
|
||||
var fc = new FlurlClient("http://www.mysite.com") {
|
||||
Settings = { HttpClientFactory = fac, AutoDispose = false }
|
||||
};
|
||||
var x = await fc.GetAsync();
|
||||
var y = await fc.GetAsync();
|
||||
var z = await fc.GetAsync();
|
||||
Assert.AreEqual(1, _fac.NewClientCount);
|
||||
Assert.AreEqual(1, fac.NewClientCount);
|
||||
}
|
||||
|
||||
private class TestHttpClientFactoryWithCounter : TestHttpClientFactory
|
||||
{
|
||||
public int NewClientCount { get; set; }
|
||||
|
||||
public TestHttpClientFactoryWithCounter() : base(new HttpTest()) { }
|
||||
|
||||
public override HttpClient CreateClient(Url url, HttpMessageHandler handler) {
|
||||
NewClientCount++;
|
||||
return base.CreateClient(url, handler);
|
||||
|
@ -5,7 +5,7 @@ using NUnit.Framework;
|
||||
|
||||
namespace Flurl.Test.Http
|
||||
{
|
||||
[TestFixture]
|
||||
[TestFixture, Parallelizable]
|
||||
public class FlurlClientTests
|
||||
{
|
||||
[Test]
|
||||
|
@ -5,7 +5,6 @@ using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Flurl.Http;
|
||||
using Flurl.Http.Testing;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Flurl.Test.Http
|
||||
|
@ -12,6 +12,7 @@ namespace Flurl.Test.Http
|
||||
/// All global settings can also be set at the client level, so this base class allows ClientConfigTests to
|
||||
/// inherit all the same tests.
|
||||
/// </summary>
|
||||
[Parallelizable]
|
||||
public abstract class ConfigTestsBase
|
||||
{
|
||||
protected abstract FlurlHttpSettings GetSettings();
|
||||
|
@ -4,7 +4,7 @@ using NUnit.Framework;
|
||||
|
||||
namespace Flurl.Test.Http
|
||||
{
|
||||
[TestFixture]
|
||||
[TestFixture, Parallelizable]
|
||||
public class HttpStatusRangeParserTests
|
||||
{
|
||||
[TestCase("4**", 399, ExpectedResult = false)]
|
||||
|
@ -6,6 +6,7 @@ using NUnit.Framework;
|
||||
|
||||
namespace Flurl.Test.Http
|
||||
{
|
||||
[Parallelizable]
|
||||
public abstract class HttpTestFixtureBase
|
||||
{
|
||||
protected HttpTest HttpTest { get; private set; }
|
||||
|
@ -10,7 +10,7 @@ using NUnit.Framework;
|
||||
|
||||
namespace Flurl.Test.Http
|
||||
{
|
||||
[TestFixture]
|
||||
[TestFixture, Parallelizable]
|
||||
public class MultipartTests
|
||||
{
|
||||
[Test]
|
||||
|
@ -13,7 +13,7 @@ namespace Flurl.Test.Http
|
||||
/// http://httpbin.org. One important aspect these verify is that AutoDispose behavior is not preventing us from getting
|
||||
/// stuff out of the response (i.e. that we're not disposing too early).
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
[TestFixture, Parallelizable]
|
||||
public class RealHttpTests
|
||||
{
|
||||
[Test]
|
||||
|
@ -1,8 +1,10 @@
|
||||
using System.Linq;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Flurl.Http;
|
||||
using Flurl.Http.Testing;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Flurl.Test.Http
|
||||
@ -63,6 +65,25 @@ namespace Flurl.Test.Http
|
||||
HttpTest.ShouldNotHaveCalled("http://www.otherapi.com/*");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task can_assert_query_params() {
|
||||
await "http://www.api.com?x=111&y=222&z=333".GetAsync();
|
||||
|
||||
HttpTest.ShouldHaveCalled("http://www.api.com*").WithQueryParam("x");
|
||||
HttpTest.ShouldHaveCalled("http://www.api.com*").WithQueryParam("y", 222);
|
||||
HttpTest.ShouldHaveCalled("*").WithQueryParam("z", "*3");
|
||||
HttpTest.ShouldHaveCalled("*").WithQueryParams(new { z = 333, y = 222 });
|
||||
|
||||
Assert.Throws<HttpCallAssertException>(() =>
|
||||
HttpTest.ShouldHaveCalled("http://www.api.com*").WithQueryParam("w"));
|
||||
Assert.Throws<HttpCallAssertException>(() =>
|
||||
HttpTest.ShouldHaveCalled("http://www.api.com*").WithQueryParam("y", 223));
|
||||
Assert.Throws<HttpCallAssertException>(() =>
|
||||
HttpTest.ShouldHaveCalled("*").WithQueryParam("z", "*4"));
|
||||
Assert.Throws<HttpCallAssertException>(() =>
|
||||
HttpTest.ShouldHaveCalled("*").WithQueryParams(new { x = 111, y = 666 }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task can_simulate_timeout() {
|
||||
HttpTest.SimulateTimeout();
|
||||
@ -95,5 +116,29 @@ namespace Flurl.Test.Http
|
||||
Assert.AreEqual(1, fc.Cookies.Count());
|
||||
Assert.AreEqual("foo", fc.Cookies["c1"].Value);
|
||||
}
|
||||
|
||||
// parallel testing not supported in PCL
|
||||
#if !PORTABLE
|
||||
[Test]
|
||||
public async Task can_test_in_parallel() {
|
||||
await Task.WhenAll(
|
||||
CallAndAssertCountAsync(7),
|
||||
CallAndAssertCountAsync(5),
|
||||
CallAndAssertCountAsync(3),
|
||||
CallAndAssertCountAsync(4),
|
||||
CallAndAssertCountAsync(6));
|
||||
}
|
||||
#endif
|
||||
|
||||
private async Task CallAndAssertCountAsync(int calls) {
|
||||
using (var test = new HttpTest()) {
|
||||
for (int i = 0; i < calls; i++) {
|
||||
await "http://www.api.com".GetAsync();
|
||||
await Task.Delay(100);
|
||||
}
|
||||
test.ShouldHaveCalled("http://www.api.com").Times(calls);
|
||||
//Console.WriteLine($"{calls} calls expected, {test.CallLog.Count} calls made");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ namespace Flurl.Http.CodeGen
|
||||
return
|
||||
from httpVerb in new[] { null, "Get", "Post", "Head", "Put", "Delete", "Patch" }
|
||||
from bodyType in new[] { null, "Json", /*"Xml",*/ "String", "UrlEncoded" }
|
||||
from extensionType in new[] { "FlurlClient", "Url", "string" }
|
||||
from extensionType in new[] { "IFlurlClient", "Url", "string" }
|
||||
where SupportedCombo(httpVerb, bodyType, extensionType)
|
||||
from deserializeType in new[] { null, "Json", "JsonList", /*"Xml",*/ "String", "Stream", "Bytes" }
|
||||
where httpVerb == "Get" || deserializeType == null
|
||||
@ -27,7 +27,7 @@ namespace Flurl.Http.CodeGen
|
||||
private static bool SupportedCombo(string verb, string bodyType, string extensionType) {
|
||||
switch (verb) {
|
||||
case null: // Send
|
||||
return bodyType != null || extensionType != "FlurlClient";
|
||||
return bodyType != null || extensionType != "IFlurlClient";
|
||||
case "Post":
|
||||
return true;
|
||||
case "Put":
|
||||
|
@ -66,14 +66,14 @@ namespace Flurl.Http.CodeGen
|
||||
name = xm.Name;
|
||||
}
|
||||
writer.WriteLine("/// <summary>");
|
||||
var summaryStart = (xm.ExtentionOfType == "FlurlClient") ? "Sends" : "Creates a FlurlClient from the URL and sends";
|
||||
var summaryStart = (xm.ExtentionOfType == "IFlurlClient") ? "Sends" : "Creates a FlurlClient from the URL and sends";
|
||||
if (xm.HttpVerb == null)
|
||||
writer.WriteLine("/// @0 an asynchronous request.", summaryStart);
|
||||
else
|
||||
writer.WriteLine("/// @0 an asynchronous @1 request.", summaryStart, xm.HttpVerb.ToUpperInvariant());
|
||||
writer.WriteLine("/// </summary>");
|
||||
if (xm.ExtentionOfType == "FlurlClient")
|
||||
writer.WriteLine("/// <param name=\"client\">The Flurl client.</param>");
|
||||
if (xm.ExtentionOfType == "IFlurlClient")
|
||||
writer.WriteLine("/// <param name=\"client\">The IFlurlClient instance.</param>");
|
||||
if (xm.ExtentionOfType == "Url" || xm.ExtentionOfType == "string")
|
||||
writer.WriteLine("/// <param name=\"url\">The URL.</param>");
|
||||
if (xm.HttpVerb == null)
|
||||
@ -87,7 +87,7 @@ namespace Flurl.Http.CodeGen
|
||||
writer.WriteLine("/// <returns>A Task whose result is @0.</returns>", xm.ReturnTypeDescription);
|
||||
|
||||
var args = new List<string>();
|
||||
args.Add("this " + xm.ExtentionOfType + (xm.ExtentionOfType == "FlurlClient" ? " client" : " url"));
|
||||
args.Add("this " + xm.ExtentionOfType + (xm.ExtentionOfType == "IFlurlClient" ? " client" : " url"));
|
||||
if (xm.HttpVerb == null)
|
||||
args.Add("HttpMethod verb");
|
||||
if (xm.BodyType != null)
|
||||
@ -101,7 +101,7 @@ namespace Flurl.Http.CodeGen
|
||||
|
||||
writer.WriteLine("public static Task<@0> @1@2(@3) {", xm.TaskArg, xm.Name, xm.IsGeneric ? "<T>" : "", string.Join(", ", args));
|
||||
|
||||
if (xm.ExtentionOfType == "FlurlClient")
|
||||
if (xm.ExtentionOfType == "IFlurlClient")
|
||||
{
|
||||
args.Clear();
|
||||
args.Add(
|
||||
@ -118,10 +118,10 @@ namespace Flurl.Http.CodeGen
|
||||
if (xm.BodyType != null) {
|
||||
writer.WriteLine("var content = new Captured@0Content(@1);",
|
||||
xm.BodyType,
|
||||
xm.BodyType == "String" ? "data" : string.Format("client.Settings.{0}Serializer.Serialize(data)", xm.BodyType));
|
||||
xm.BodyType == "String" ? "data" : $"client.Settings.{xm.BodyType}Serializer.Serialize(data)");
|
||||
}
|
||||
|
||||
var client = (xm.ExtentionOfType == "FlurlClient") ? "client" : "new FlurlClient(url, false)";
|
||||
var client = (xm.ExtentionOfType == "IFlurlClient") ? "client" : "new FlurlClient(url, false)";
|
||||
var receive = (xm.DeserializeToType == null) ? "" : string.Format(".Receive{0}{1}()", xm.DeserializeToType, xm.IsGeneric ? "<T>" : "");
|
||||
writer.WriteLine("return @0.SendAsync(@1)@2;", client, string.Join(", ", args), receive);
|
||||
}
|
||||
|
@ -15,37 +15,37 @@ namespace Flurl.Http
|
||||
public static class ClientConfigExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns a new FlurlClient where all state (HttpClient, etc) is shared but with a different URL.
|
||||
/// Returns a new IFlurlClient where all state (HttpClient, etc) is shared but with a different URL.
|
||||
/// Allows you to re-use the underlying HttpClient instance (such as to share cookies, etc) with
|
||||
/// different URLs in a thread-safe way.
|
||||
/// </summary>
|
||||
/// <param name="client">The client.</param>
|
||||
/// <param name="url">The Url to call.</param>
|
||||
public static FlurlClient WithUrl(this FlurlClient client, Url url) {
|
||||
public static IFlurlClient WithUrl(this IFlurlClient client, Url url) {
|
||||
var fc = client.Clone();
|
||||
fc.Url = url;
|
||||
// prevent the new client from automatically disposing the parent's HttpClient
|
||||
fc.AutoDispose = false;
|
||||
fc.Settings.AutoDispose = false;
|
||||
return fc;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fluently specify that an existing FlurlClient should be used to call the Url, rather than creating a new one.
|
||||
/// Fluently specify that an existing IFlurlClient should be used to call the Url, rather than creating a new one.
|
||||
/// Enables re-using the underlying HttpClient.
|
||||
/// </summary>
|
||||
/// <param name="url">The URL.</param>
|
||||
/// <param name="client">The FlurlClient to use in calling the Url</param>
|
||||
public static FlurlClient WithClient(this Url url, FlurlClient client) {
|
||||
/// <param name="client">The IFlurlClient to use in calling the Url</param>
|
||||
public static IFlurlClient WithClient(this Url url, IFlurlClient client) {
|
||||
return client.WithUrl(url);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fluently specify that an existing FlurlClient should be used to call the Url, rather than creating a new one.
|
||||
/// Fluently specify that an existing IFlurlClient should be used to call the Url, rather than creating a new one.
|
||||
/// Enables re-using the underlying HttpClient.
|
||||
/// </summary>
|
||||
/// <param name="url">The URL.</param>
|
||||
/// <param name="client">The FlurlClient to use in calling the Url</param>
|
||||
public static FlurlClient WithClient(this string url, FlurlClient client) {
|
||||
/// <param name="client">The IFlurlClient to use in calling the Url</param>
|
||||
public static IFlurlClient WithClient(this string url, IFlurlClient client) {
|
||||
return client.WithUrl(url);
|
||||
}
|
||||
|
||||
@ -54,8 +54,8 @@ namespace Flurl.Http
|
||||
/// </summary>
|
||||
/// <param name="client">The client.</param>
|
||||
/// <param name="action">Action defining the settings changes.</param>
|
||||
/// <returns>The FlurlClient with the modified HttpClient</returns>
|
||||
public static FlurlClient ConfigureClient(this FlurlClient client, Action<FlurlHttpSettings> action) {
|
||||
/// <returns>The IFlurlClient with the modified HttpClient</returns>
|
||||
public static IFlurlClient ConfigureClient(this IFlurlClient client, Action<FlurlHttpSettings> action) {
|
||||
action(client.Settings);
|
||||
return client;
|
||||
}
|
||||
@ -65,8 +65,8 @@ namespace Flurl.Http
|
||||
/// </summary>
|
||||
/// <param name="url">The URL.</param>
|
||||
/// <param name="action">Action defining the settings changes.</param>
|
||||
/// <returns>The FlurlClient with the modified HttpClient</returns>
|
||||
public static FlurlClient ConfigureClient(this Url url, Action<FlurlHttpSettings> action) {
|
||||
/// <returns>The IFlurlClient with the modified HttpClient</returns>
|
||||
public static IFlurlClient ConfigureClient(this Url url, Action<FlurlHttpSettings> action) {
|
||||
return new FlurlClient(url, true).ConfigureClient(action);
|
||||
}
|
||||
|
||||
@ -76,7 +76,7 @@ namespace Flurl.Http
|
||||
/// <param name="url">The URL.</param>
|
||||
/// <param name="action">Action defining the settings changes.</param>
|
||||
/// <returns>The FlurlClient with the modified HttpClient</returns>
|
||||
public static FlurlClient ConfigureClient(this string url, Action<FlurlHttpSettings> action) {
|
||||
public static IFlurlClient ConfigureClient(this string url, Action<FlurlHttpSettings> action) {
|
||||
return new FlurlClient(url, true).ConfigureClient(action);
|
||||
}
|
||||
|
||||
@ -86,7 +86,7 @@ namespace Flurl.Http
|
||||
/// <param name="client">The client.</param>
|
||||
/// <param name="action">Action to perform on the HttpClient.</param>
|
||||
/// <returns>The FlurlClient with the modified HttpClient</returns>
|
||||
public static FlurlClient ConfigureHttpClient(this FlurlClient client, Action<HttpClient> action) {
|
||||
public static IFlurlClient ConfigureHttpClient(this IFlurlClient client, Action<HttpClient> action) {
|
||||
action(client.HttpClient);
|
||||
return client;
|
||||
}
|
||||
@ -97,7 +97,7 @@ namespace Flurl.Http
|
||||
/// <param name="url">The URL.</param>
|
||||
/// <param name="action">Action to perform on the HttpClient.</param>
|
||||
/// <returns>The FlurlClient with the modified HttpClient</returns>
|
||||
public static FlurlClient ConfigureHttpClient(this Url url, Action<HttpClient> action) {
|
||||
public static IFlurlClient ConfigureHttpClient(this Url url, Action<HttpClient> action) {
|
||||
return new FlurlClient(url, true).ConfigureHttpClient(action);
|
||||
}
|
||||
|
||||
@ -107,7 +107,7 @@ namespace Flurl.Http
|
||||
/// <param name="url">The URL.</param>
|
||||
/// <param name="action">Action to perform on the HttpClient.</param>
|
||||
/// <returns>The FlurlClient with the modified HttpClient</returns>
|
||||
public static FlurlClient ConfigureHttpClient(this string url, Action<HttpClient> action) {
|
||||
public static IFlurlClient ConfigureHttpClient(this string url, Action<HttpClient> action) {
|
||||
return new FlurlClient(url, true).ConfigureHttpClient(action);
|
||||
}
|
||||
|
||||
@ -117,7 +117,7 @@ namespace Flurl.Http
|
||||
/// <param name="client">The client.</param>
|
||||
/// <param name="timespan">Time to wait before the request times out.</param>
|
||||
/// <returns>The modified FlurlClient.</returns>
|
||||
public static FlurlClient WithTimeout(this FlurlClient client, TimeSpan timespan) {
|
||||
public static IFlurlClient WithTimeout(this IFlurlClient client, TimeSpan timespan) {
|
||||
client.HttpClient.Timeout = timespan;
|
||||
return client;
|
||||
}
|
||||
@ -128,7 +128,7 @@ namespace Flurl.Http
|
||||
/// <param name="url">The URL.</param>
|
||||
/// <param name="timespan">Time to wait before the request times out.</param>
|
||||
/// <returns>The created FlurlClient.</returns>
|
||||
public static FlurlClient WithTimeout(this Url url, TimeSpan timespan) {
|
||||
public static IFlurlClient WithTimeout(this Url url, TimeSpan timespan) {
|
||||
return new FlurlClient(url, true).WithTimeout(timespan);
|
||||
}
|
||||
|
||||
@ -138,7 +138,7 @@ namespace Flurl.Http
|
||||
/// <param name="url">The URL.</param>
|
||||
/// <param name="timespan">Time to wait before the request times out.</param>
|
||||
/// <returns>The created FlurlClient.</returns>
|
||||
public static FlurlClient WithTimeout(this string url, TimeSpan timespan) {
|
||||
public static IFlurlClient WithTimeout(this string url, TimeSpan timespan) {
|
||||
return new FlurlClient(url, true).WithTimeout(timespan);
|
||||
}
|
||||
|
||||
@ -149,7 +149,7 @@ namespace Flurl.Http
|
||||
/// <param name="seconds">Number of seconds to wait before the request times out.</param>
|
||||
/// <returns>The modified FlurlClient.</returns>
|
||||
/// <exception cref="OverflowException"><paramref name="seconds" /> is less than <see cref="F:System.TimeSpan.MinValue" /> or greater than <see cref="F:System.TimeSpan.MaxValue" />.-or-<paramref name="seconds" /> is <see cref="F:System.Double.PositiveInfinity" />.-or-<paramref name="seconds" /> is <see cref="F:System.Double.NegativeInfinity" />. </exception>
|
||||
public static FlurlClient WithTimeout(this FlurlClient client, int seconds) {
|
||||
public static IFlurlClient WithTimeout(this IFlurlClient client, int seconds) {
|
||||
return client.WithTimeout(TimeSpan.FromSeconds(seconds));
|
||||
}
|
||||
|
||||
@ -160,7 +160,7 @@ namespace Flurl.Http
|
||||
/// <param name="seconds">Number of seconds to wait before the request times out.</param>
|
||||
/// <returns>The created FlurlClient.</returns>
|
||||
/// <exception cref="OverflowException"><paramref name="seconds" /> is less than <see cref="F:System.TimeSpan.MinValue" /> or greater than <see cref="F:System.TimeSpan.MaxValue" />.-or-<paramref name="seconds" /> is <see cref="F:System.Double.PositiveInfinity" />.-or-<paramref name="seconds" /> is <see cref="F:System.Double.NegativeInfinity" />. </exception>
|
||||
public static FlurlClient WithTimeout(this Url url, int seconds) {
|
||||
public static IFlurlClient WithTimeout(this Url url, int seconds) {
|
||||
return new FlurlClient(url, true).WithTimeout(seconds);
|
||||
}
|
||||
|
||||
@ -171,7 +171,7 @@ namespace Flurl.Http
|
||||
/// <param name="seconds">Number of seconds to wait before the request times out.</param>
|
||||
/// <returns>The created FlurlClient.</returns>
|
||||
/// <exception cref="OverflowException"><paramref name="seconds" /> is less than <see cref="F:System.TimeSpan.MinValue" /> or greater than <see cref="F:System.TimeSpan.MaxValue" />.-or-<paramref name="seconds" /> is <see cref="F:System.Double.PositiveInfinity" />.-or-<paramref name="seconds" /> is <see cref="F:System.Double.NegativeInfinity" />. </exception>
|
||||
public static FlurlClient WithTimeout(this string url, int seconds) {
|
||||
public static IFlurlClient WithTimeout(this string url, int seconds) {
|
||||
return new FlurlClient(url, true).WithTimeout(seconds);
|
||||
}
|
||||
|
||||
@ -182,7 +182,7 @@ namespace Flurl.Http
|
||||
/// <param name="name">HTTP header name.</param>
|
||||
/// <param name="value">HTTP header value.</param>
|
||||
/// <returns>The modified FlurlClient.</returns>
|
||||
public static FlurlClient WithHeader(this FlurlClient client, string name, object value) {
|
||||
public static IFlurlClient WithHeader(this IFlurlClient client, string name, object value) {
|
||||
var values = new[] { value?.ToString() };
|
||||
client.HttpClient.DefaultRequestHeaders.Add(name, values);
|
||||
return client;
|
||||
@ -195,7 +195,7 @@ namespace Flurl.Http
|
||||
/// <param name="name">HTTP header name.</param>
|
||||
/// <param name="value">HTTP header value.</param>
|
||||
/// <returns>The modified FlurlClient.</returns>
|
||||
public static FlurlClient WithHeader(this Url url, string name, object value) {
|
||||
public static IFlurlClient WithHeader(this Url url, string name, object value) {
|
||||
return new FlurlClient(url, true).WithHeader(name, value);
|
||||
}
|
||||
|
||||
@ -206,7 +206,7 @@ namespace Flurl.Http
|
||||
/// <param name="name">HTTP header name.</param>
|
||||
/// <param name="value">HTTP header value.</param>
|
||||
/// <returns>The modified FlurlClient.</returns>
|
||||
public static FlurlClient WithHeader(this string url, string name, object value) {
|
||||
public static IFlurlClient WithHeader(this string url, string name, object value) {
|
||||
return new FlurlClient(url, true).WithHeader(name, value);
|
||||
}
|
||||
|
||||
@ -216,7 +216,7 @@ namespace Flurl.Http
|
||||
/// <param name="client">The client.</param>
|
||||
/// <param name="headers">Names/values of HTTP headers to set. Typically an anonymous object or IDictionary.</param>
|
||||
/// <returns>The modified FlurlClient.</returns>
|
||||
public static FlurlClient WithHeaders(this FlurlClient client, object headers) {
|
||||
public static IFlurlClient WithHeaders(this IFlurlClient client, object headers) {
|
||||
if (headers == null)
|
||||
return client;
|
||||
|
||||
@ -236,7 +236,7 @@ namespace Flurl.Http
|
||||
/// <param name="url">The URL.</param>
|
||||
/// <param name="headers">Names/values of HTTP headers to set. Typically an anonymous object or IDictionary.</param>
|
||||
/// <returns>The modified FlurlClient.</returns>
|
||||
public static FlurlClient WithHeaders(this Url url, object headers) {
|
||||
public static IFlurlClient WithHeaders(this Url url, object headers) {
|
||||
return new FlurlClient(url, true).WithHeaders(headers);
|
||||
}
|
||||
|
||||
@ -246,7 +246,7 @@ namespace Flurl.Http
|
||||
/// <param name="url">The URL.</param>
|
||||
/// <param name="headers">Names/values of HTTP headers to set. Typically an anonymous object or IDictionary.</param>
|
||||
/// <returns>The modified FlurlClient.</returns>
|
||||
public static FlurlClient WithHeaders(this string url, object headers) {
|
||||
public static IFlurlClient WithHeaders(this string url, object headers) {
|
||||
return new FlurlClient(url, true).WithHeaders(headers);
|
||||
}
|
||||
|
||||
@ -257,7 +257,7 @@ namespace Flurl.Http
|
||||
/// <param name="username">Username of authenticating user.</param>
|
||||
/// <param name="password">Password of authenticating user.</param>
|
||||
/// <returns>The modified FlurlClient.</returns>
|
||||
public static FlurlClient WithBasicAuth(this FlurlClient client, string username, string password) {
|
||||
public static IFlurlClient WithBasicAuth(this IFlurlClient client, string username, string password) {
|
||||
// http://stackoverflow.com/questions/14627399/setting-authorization-header-of-httpclient
|
||||
var value = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{username}:{password}"));
|
||||
client.HttpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", value);
|
||||
@ -270,8 +270,8 @@ namespace Flurl.Http
|
||||
/// <param name="url">The URL.</param>
|
||||
/// <param name="username">Username of authenticating user.</param>
|
||||
/// <param name="password">Password of authenticating user.</param>
|
||||
/// <returns>The new FlurlClient.</returns>
|
||||
public static FlurlClient WithBasicAuth(this Url url, string username, string password) {
|
||||
/// <returns>The new IFlurlClient instance.</returns>
|
||||
public static IFlurlClient WithBasicAuth(this Url url, string username, string password) {
|
||||
return new FlurlClient(url, true).WithBasicAuth(username, password);
|
||||
}
|
||||
|
||||
@ -281,8 +281,8 @@ namespace Flurl.Http
|
||||
/// <param name="url">The URL.</param>
|
||||
/// <param name="username">Username of authenticating user.</param>
|
||||
/// <param name="password">Password of authenticating user.</param>
|
||||
/// <returns>The new FlurlClient.</returns>
|
||||
public static FlurlClient WithBasicAuth(this string url, string username, string password) {
|
||||
/// <returns>The new IFlurlClient instance.</returns>
|
||||
public static IFlurlClient WithBasicAuth(this string url, string username, string password) {
|
||||
return new FlurlClient(url, true).WithBasicAuth(username, password);
|
||||
}
|
||||
|
||||
@ -292,7 +292,7 @@ namespace Flurl.Http
|
||||
/// <param name="client">The client.</param>
|
||||
/// <param name="token">The acquired bearer token to pass.</param>
|
||||
/// <returns>The modified FlurlClient.</returns>
|
||||
public static FlurlClient WithOAuthBearerToken(this FlurlClient client, string token) {
|
||||
public static IFlurlClient WithOAuthBearerToken(this IFlurlClient client, string token) {
|
||||
client.HttpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
|
||||
return client;
|
||||
}
|
||||
@ -302,8 +302,8 @@ namespace Flurl.Http
|
||||
/// </summary>
|
||||
/// <param name="url">The URL.</param>
|
||||
/// <param name="token">The acquired bearer token to pass.</param>
|
||||
/// <returns>The new FlurlClient.</returns>
|
||||
public static FlurlClient WithOAuthBearerToken(this Url url, string token) {
|
||||
/// <returns>The new IFlurlClient instance.</returns>
|
||||
public static IFlurlClient WithOAuthBearerToken(this Url url, string token) {
|
||||
return new FlurlClient(url, true).WithOAuthBearerToken(token);
|
||||
}
|
||||
|
||||
@ -312,8 +312,8 @@ namespace Flurl.Http
|
||||
/// </summary>
|
||||
/// <param name="url">The URL.</param>
|
||||
/// <param name="token">The acquired bearer token to pass.</param>
|
||||
/// <returns>The new FlurlClient.</returns>
|
||||
public static FlurlClient WithOAuthBearerToken(this string url, string token) {
|
||||
/// <returns>The new IFlurlClient instance.</returns>
|
||||
public static IFlurlClient WithOAuthBearerToken(this string url, string token) {
|
||||
return new FlurlClient(url, true).WithOAuthBearerToken(token);
|
||||
}
|
||||
|
||||
@ -323,7 +323,7 @@ namespace Flurl.Http
|
||||
/// <param name="client">The client.</param>
|
||||
/// <param name="pattern">Examples: "3xx", "100,300,600", "100-299,6xx"</param>
|
||||
/// <returns>The modified FlurlClient.</returns>
|
||||
public static FlurlClient AllowHttpStatus(this FlurlClient client, string pattern) {
|
||||
public static IFlurlClient AllowHttpStatus(this IFlurlClient client, string pattern) {
|
||||
if (!string.IsNullOrWhiteSpace(pattern)) {
|
||||
var current = client.Settings.AllowedHttpStatusRange;
|
||||
if (string.IsNullOrWhiteSpace(current))
|
||||
@ -339,8 +339,8 @@ namespace Flurl.Http
|
||||
/// </summary>
|
||||
/// <param name="url">The URL.</param>
|
||||
/// <param name="pattern">Examples: "3xx", "100,300,600", "100-299,6xx"</param>
|
||||
/// <returns>The new FlurlClient.</returns>
|
||||
public static FlurlClient AllowHttpStatus(this Url url, string pattern) {
|
||||
/// <returns>The new IFlurlClient instance.</returns>
|
||||
public static IFlurlClient AllowHttpStatus(this Url url, string pattern) {
|
||||
return new FlurlClient(url, true).AllowHttpStatus(pattern);
|
||||
}
|
||||
|
||||
@ -349,8 +349,8 @@ namespace Flurl.Http
|
||||
/// </summary>
|
||||
/// <param name="url">The URL.</param>
|
||||
/// <param name="pattern">Examples: "3xx", "100,300,600", "100-299,6xx"</param>
|
||||
/// <returns>The new FlurlClient.</returns>
|
||||
public static FlurlClient AllowHttpStatus(this string url, string pattern) {
|
||||
/// <returns>The new IFlurlClient instance.</returns>
|
||||
public static IFlurlClient AllowHttpStatus(this string url, string pattern) {
|
||||
return new FlurlClient(url, true).AllowHttpStatus(pattern);
|
||||
}
|
||||
|
||||
@ -360,7 +360,7 @@ namespace Flurl.Http
|
||||
/// <param name="client">The client.</param>
|
||||
/// <param name="statusCodes">Examples: HttpStatusCode.NotFound</param>
|
||||
/// <returns>The modified FlurlClient.</returns>
|
||||
public static FlurlClient AllowHttpStatus(this FlurlClient client, params HttpStatusCode[] statusCodes) {
|
||||
public static IFlurlClient AllowHttpStatus(this IFlurlClient client, params HttpStatusCode[] statusCodes) {
|
||||
var pattern = string.Join(",", statusCodes.Select(c => (int)c));
|
||||
return AllowHttpStatus(client, pattern);
|
||||
}
|
||||
@ -370,8 +370,8 @@ namespace Flurl.Http
|
||||
/// </summary>
|
||||
/// <param name="url">The URL.</param>
|
||||
/// <param name="statusCodes">Examples: HttpStatusCode.NotFound</param>
|
||||
/// <returns>The new FlurlClient.</returns>
|
||||
public static FlurlClient AllowHttpStatus(this Url url, params HttpStatusCode[] statusCodes) {
|
||||
/// <returns>The new IFlurlClient instance.</returns>
|
||||
public static IFlurlClient AllowHttpStatus(this Url url, params HttpStatusCode[] statusCodes) {
|
||||
return new FlurlClient(url, true).AllowHttpStatus(statusCodes);
|
||||
}
|
||||
|
||||
@ -380,16 +380,16 @@ namespace Flurl.Http
|
||||
/// </summary>
|
||||
/// <param name="url">The URL.</param>
|
||||
/// <param name="statusCodes">Examples: HttpStatusCode.NotFound</param>
|
||||
/// <returns>The new FlurlClient.</returns>
|
||||
public static FlurlClient AllowHttpStatus(this string url, params HttpStatusCode[] statusCodes) {
|
||||
/// <returns>The new IFlurlClient instance.</returns>
|
||||
public static IFlurlClient AllowHttpStatus(this string url, params HttpStatusCode[] statusCodes) {
|
||||
return new FlurlClient(url, true).AllowHttpStatus(statusCodes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prevents a FlurlHttpException from being thrown on any completed response, regardless of the HTTP status code.
|
||||
/// </summary>
|
||||
/// <returns>The modified FlurlClient.</returns>
|
||||
public static FlurlClient AllowAnyHttpStatus(this FlurlClient client) {
|
||||
/// <returns>The modified IFlurlClient.</returns>
|
||||
public static IFlurlClient AllowAnyHttpStatus(this IFlurlClient client) {
|
||||
client.Settings.AllowedHttpStatusRange = "*";
|
||||
return client;
|
||||
}
|
||||
@ -397,16 +397,16 @@ namespace Flurl.Http
|
||||
/// <summary>
|
||||
/// Creates a FlurlClient from the URL and prevents a FlurlHttpException from being thrown on any completed response, regardless of the HTTP status code.
|
||||
/// </summary>
|
||||
/// <returns>The new FlurlClient.</returns>
|
||||
public static FlurlClient AllowAnyHttpStatus(this Url url) {
|
||||
/// <returns>The new IFlurlClient instance.</returns>
|
||||
public static IFlurlClient AllowAnyHttpStatus(this Url url) {
|
||||
return new FlurlClient(url, true).AllowAnyHttpStatus();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a FlurlClient from the URL and prevents a FlurlHttpException from being thrown on any completed response, regardless of the HTTP status code.
|
||||
/// </summary>
|
||||
/// <returns>The new FlurlClient.</returns>
|
||||
public static FlurlClient AllowAnyHttpStatus(this string url) {
|
||||
/// <returns>The new IFlurlClient instance.</returns>
|
||||
public static IFlurlClient AllowAnyHttpStatus(this string url) {
|
||||
return new FlurlClient(url, true).AllowAnyHttpStatus();
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,11 @@ namespace Flurl.Http.Configuration
|
||||
ResetDefaults();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets value indicating whether to automatically dispose underlying HttpClient immediately after each call.
|
||||
/// </summary>
|
||||
public bool AutoDispose { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the default timeout for every HTTP request.
|
||||
/// </summary>
|
||||
@ -87,6 +92,7 @@ namespace Flurl.Http.Configuration
|
||||
/// Clear all custom global options and set default values.
|
||||
/// </summary>
|
||||
public void ResetDefaults() {
|
||||
AutoDispose = false;
|
||||
DefaultTimeout = new HttpClient().Timeout;
|
||||
AllowedHttpStatusRange = null;
|
||||
CookiesEnabled = false;
|
||||
|
@ -23,7 +23,7 @@ namespace Flurl.Http.Configuration
|
||||
/// <param name="request">The request.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) {
|
||||
var call = HttpCall.Get(request);
|
||||
var call = request.GetFlurlHttpCall();
|
||||
|
||||
var stringContent = request.Content as CapturedStringContent;
|
||||
if (stringContent != null)
|
||||
|
@ -18,7 +18,7 @@ namespace Flurl.Http
|
||||
/// <summary>
|
||||
/// Allows cookies to be sent and received in calls made with this client. Not necessary to call when setting cookies via WithCookie/WithCookies.
|
||||
/// </summary>
|
||||
public static FlurlClient EnableCookies(this FlurlClient client) {
|
||||
public static IFlurlClient EnableCookies(this IFlurlClient client) {
|
||||
client.Settings.CookiesEnabled = true;
|
||||
return client;
|
||||
}
|
||||
@ -26,14 +26,14 @@ namespace Flurl.Http
|
||||
/// <summary>
|
||||
/// Allows cookies to be sent and received in calls made to this Url. Not necessary to call when setting cookies via WithCookie/WithCookies.
|
||||
/// </summary>
|
||||
public static FlurlClient EnableCookies(this Url url) {
|
||||
public static IFlurlClient EnableCookies(this Url url) {
|
||||
return new FlurlClient(url).EnableCookies();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allows cookies to be sent and received in calls made to this Url. Not necessary to call when setting cookies via WithCookie/WithCookies.
|
||||
/// </summary>
|
||||
public static FlurlClient EnableCookies(this string url) {
|
||||
public static IFlurlClient EnableCookies(this string url) {
|
||||
return new FlurlClient(url).EnableCookies();
|
||||
}
|
||||
|
||||
@ -44,7 +44,7 @@ namespace Flurl.Http
|
||||
/// <param name="cookie">The cookie to set.</param>
|
||||
/// <returns>The modified FlurlClient.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="cookie" /> is null.</exception>
|
||||
public static FlurlClient WithCookie(this FlurlClient client, Cookie cookie) {
|
||||
public static IFlurlClient WithCookie(this IFlurlClient client, Cookie cookie) {
|
||||
client.Settings.CookiesEnabled = true;
|
||||
client.Cookies[cookie.Name] = cookie;
|
||||
return client;
|
||||
@ -57,7 +57,7 @@ namespace Flurl.Http
|
||||
/// <param name="cookie">the cookie to set.</param>
|
||||
/// <returns>The modified FlurlClient.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="cookie" /> is null.</exception>
|
||||
public static FlurlClient WithCookie(this string url, Cookie cookie) {
|
||||
public static IFlurlClient WithCookie(this string url, Cookie cookie) {
|
||||
return new FlurlClient(url, true).WithCookie(cookie);
|
||||
}
|
||||
|
||||
@ -68,7 +68,7 @@ namespace Flurl.Http
|
||||
/// <param name="cookie">the cookie to set.</param>
|
||||
/// <returns>The modified FlurlClient.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="cookie" /> is null.</exception>
|
||||
public static FlurlClient WithCookie(this Url url, Cookie cookie) {
|
||||
public static IFlurlClient WithCookie(this Url url, Cookie cookie) {
|
||||
return new FlurlClient(url, true).WithCookie(cookie);
|
||||
}
|
||||
|
||||
@ -81,7 +81,7 @@ namespace Flurl.Http
|
||||
/// <param name="expires">cookie expiration (optional). If excluded, cookie only lives for duration of session.</param>
|
||||
/// <returns>The modified FlurlClient.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="value" /> is null.</exception>
|
||||
public static FlurlClient WithCookie(this FlurlClient client, string name, object value, DateTime? expires = null) {
|
||||
public static IFlurlClient WithCookie(this IFlurlClient client, string name, object value, DateTime? expires = null) {
|
||||
var cookie = new Cookie(name, value?.ToInvariantString()) { Expires = expires ?? DateTime.MinValue };
|
||||
return client.WithCookie(cookie);
|
||||
}
|
||||
@ -95,7 +95,7 @@ namespace Flurl.Http
|
||||
/// <param name="expires">cookie expiration (optional). If excluded, cookie only lives for duration of session.</param>
|
||||
/// <returns>The modified FlurlClient.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="value" /> is null.</exception>
|
||||
public static FlurlClient WithCookie(this string url, string name, object value, DateTime? expires = null) {
|
||||
public static IFlurlClient WithCookie(this string url, string name, object value, DateTime? expires = null) {
|
||||
return new FlurlClient(url, true).WithCookie(name, value, expires);
|
||||
}
|
||||
|
||||
@ -108,7 +108,7 @@ namespace Flurl.Http
|
||||
/// <param name="expires">cookie expiration (optional). If excluded, cookie only lives for duration of session.</param>
|
||||
/// <returns>The modified FlurlClient.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="value" /> is null.</exception>
|
||||
public static FlurlClient WithCookie(this Url url, string name, object value, DateTime? expires = null) {
|
||||
public static IFlurlClient WithCookie(this Url url, string name, object value, DateTime? expires = null) {
|
||||
return new FlurlClient(url, true).WithCookie(name, value, expires);
|
||||
}
|
||||
|
||||
@ -120,7 +120,7 @@ namespace Flurl.Http
|
||||
/// <param name="expires">Expiration for all cookies (optional). If excluded, cookies only live for duration of session.</param>
|
||||
/// <returns>The modified FlurlClient.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="cookies" /> is null.</exception>
|
||||
public static FlurlClient WithCookies(this FlurlClient client, object cookies, DateTime? expires = null) {
|
||||
public static IFlurlClient WithCookies(this IFlurlClient client, object cookies, DateTime? expires = null) {
|
||||
if (cookies == null)
|
||||
return client;
|
||||
|
||||
@ -138,7 +138,7 @@ namespace Flurl.Http
|
||||
/// <param name="expires">Expiration for all cookies (optional). If excluded, cookies only live for duration of session.</param>
|
||||
/// <returns>The modified FlurlClient.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="cookies" /> is null.</exception>
|
||||
public static FlurlClient WithCookies(this Url url, object cookies, DateTime? expires = null) {
|
||||
public static IFlurlClient WithCookies(this Url url, object cookies, DateTime? expires = null) {
|
||||
return new FlurlClient(url, true).WithCookies(cookies);
|
||||
}
|
||||
|
||||
@ -150,7 +150,7 @@ namespace Flurl.Http
|
||||
/// <param name="expires">Expiration for all cookies (optional). If excluded, cookies only live for duration of session.</param>
|
||||
/// <returns>The modified FlurlClient.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="cookies" /> is null.</exception>
|
||||
public static FlurlClient WithCookies(this string url, object cookies, DateTime? expires = null) {
|
||||
public static IFlurlClient WithCookies(this string url, object cookies, DateTime? expires = null) {
|
||||
return new FlurlClient(url, true).WithCookies(cookies);
|
||||
}
|
||||
}
|
||||
|
@ -17,13 +17,13 @@ namespace Flurl.Http
|
||||
/// <param name="localFileName">Name of local file. If not specified, the source filename (last segment of the URL) is used.</param>
|
||||
/// <param name="bufferSize">Buffer size in bytes. Default is 4096.</param>
|
||||
/// <returns>A Task whose result is the local path of the downloaded file.</returns>
|
||||
public static async Task<string> DownloadFileAsync(this FlurlClient client, string localFolderPath, string localFileName = null, int bufferSize = 4096) {
|
||||
public static async Task<string> DownloadFileAsync(this IFlurlClient client, string localFolderPath, string localFileName = null, int bufferSize = 4096) {
|
||||
if (localFileName == null)
|
||||
localFileName = client.Url.Path.Split('/').Last();
|
||||
|
||||
// need to temporarily disable autodispose if set, otherwise reading from stream will fail
|
||||
var autoDispose = client.AutoDispose;
|
||||
client.AutoDispose = false;
|
||||
var autoDispose = client.Settings.AutoDispose;
|
||||
client.Settings.AutoDispose = false;
|
||||
|
||||
try {
|
||||
var response = await client.SendAsync(HttpMethod.Get, completionOption: HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);
|
||||
@ -37,8 +37,8 @@ namespace Flurl.Http
|
||||
return FileUtil.CombinePath(localFolderPath, localFileName);
|
||||
}
|
||||
finally {
|
||||
client.AutoDispose = autoDispose;
|
||||
if (client.AutoDispose)
|
||||
client.Settings.AutoDispose = autoDispose;
|
||||
if (client.Settings.AutoDispose)
|
||||
client.Dispose();
|
||||
}
|
||||
}
|
||||
|
@ -6,55 +6,116 @@ using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Flurl.Http.Configuration;
|
||||
using Flurl.Http.Testing;
|
||||
|
||||
namespace Flurl.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface defining FlurlClient's contract (useful for mocking and DI)
|
||||
/// </summary>
|
||||
public interface IFlurlClient : IDisposable {
|
||||
/// <summary>
|
||||
/// Creates a copy of this FlurlClient with a shared instance of HttpClient and HttpMessageHandler
|
||||
/// </summary>
|
||||
FlurlClient Clone();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the FlurlHttpSettings object used by this client.
|
||||
/// </summary>
|
||||
FlurlHttpSettings Settings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the URL to be called.
|
||||
/// </summary>
|
||||
Url Url { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Collection of HttpCookies sent and received.
|
||||
/// </summary>
|
||||
IDictionary<string, Cookie> Cookies { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the HttpClient to be used in subsequent HTTP calls. Creation (when necessary) is delegated
|
||||
/// to FlurlHttp.HttpClientFactory. Reused for the life of the FlurlClient.
|
||||
/// </summary>
|
||||
HttpClient HttpClient { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the HttpMessageHandler to be used in subsequent HTTP calls. Creation (when necessary) is delegated
|
||||
/// to FlurlHttp.HttpClientFactory.
|
||||
/// </summary>
|
||||
HttpMessageHandler HttpMessageHandler { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates and asynchronously sends an HttpRequestMethod, disposing HttpClient if AutoDispose it true.
|
||||
/// Mainly used to implement higher-level extension methods (GetJsonAsync, etc).
|
||||
/// </summary>
|
||||
/// <param name="verb">The HTTP method used to make the request.</param>
|
||||
/// <param name="content">Contents of the request body.</param>
|
||||
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional.</param>
|
||||
/// <param name="completionOption">The HttpCompletionOption used in the request. Optional.</param>
|
||||
/// <returns>A Task whose result is the received HttpResponseMessage.</returns>
|
||||
Task<HttpResponseMessage> SendAsync(HttpMethod verb, HttpContent content = null, CancellationToken? cancellationToken = null, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A chainable wrapper around HttpClient and Flurl.Url.
|
||||
/// </summary>
|
||||
public class FlurlClient : IDisposable
|
||||
public class FlurlClient : IFlurlClient
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FlurlClient"/> class.
|
||||
/// </summary>
|
||||
/// <param name="url">The URL.</param>
|
||||
/// <param name="autoDispose">if set to <c>true</c> [automatic dispose].</param>
|
||||
public FlurlClient(Url url, bool autoDispose) {
|
||||
Url = url;
|
||||
AutoDispose = autoDispose;
|
||||
Settings = FlurlHttp.GlobalSettings.Clone();
|
||||
/// <param name="settings">The FlurlHttpSettings associated with this instance.</param>
|
||||
public FlurlClient(FlurlHttpSettings settings = null) {
|
||||
Settings = settings ?? FlurlHttp.GlobalSettings.Clone();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FlurlClient"/> class.
|
||||
/// </summary>
|
||||
/// <param name="url">The URL.</param>
|
||||
/// <param name="autoDispose">if set to <c>true</c> [automatic dispose].</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="url" /> is <see langword="null" />.</exception>
|
||||
public FlurlClient(string url, bool autoDispose) : this(new Url(url), autoDispose) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FlurlClient"/> class.
|
||||
/// </summary>
|
||||
/// <param name="url">The URL.</param>
|
||||
public FlurlClient(Url url) : this(url, false) { }
|
||||
/// <param name="configure">Action allowing you to overide default settings inline.</param>
|
||||
public FlurlClient(Action<FlurlHttpSettings> configure) : this() {
|
||||
configure(Settings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FlurlClient"/> class.
|
||||
/// </summary>
|
||||
/// <param name="url">The URL.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="url" /> is <see langword="null" />.</exception>
|
||||
public FlurlClient(string url) : this(new Url(url), false) { }
|
||||
|
||||
/// <param name="url">The URL to call with this FlurlClient instance.</param>
|
||||
public FlurlClient(Url url) : this() {
|
||||
Url = url;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FlurlClient"/> class.
|
||||
/// </summary>
|
||||
public FlurlClient() : this((Url)null, false) { }
|
||||
/// <param name="url">The URL to call with this FlurlClient instance.</param>
|
||||
public FlurlClient(string url) : this() {
|
||||
Url = new Url(url);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FlurlClient"/> class.
|
||||
/// </summary>
|
||||
/// <param name="url">The URL to call with this FlurlClient instance.</param>
|
||||
/// <param name="autoDispose">Indicates whether to automatically dispose underlying HttpClient immediately after each call.</param>
|
||||
public FlurlClient(Url url, bool autoDispose) : this(url) {
|
||||
Settings.AutoDispose = autoDispose;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FlurlClient"/> class.
|
||||
/// </summary>
|
||||
/// <param name="url">The URL to call with this FlurlClient instance.</param>
|
||||
/// <param name="autoDispose">Indicates whether to automatically dispose underlying HttpClient immediately after each call.</param>
|
||||
public FlurlClient(string url, bool autoDispose) : this(url) {
|
||||
Settings.AutoDispose = autoDispose;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a copy of this FlurlClient with a shared instance of HttpClient and HttpMessageHandler
|
||||
/// </summary>
|
||||
|
||||
public FlurlClient Clone() {
|
||||
return new FlurlClient {
|
||||
_httpClient = _httpClient,
|
||||
@ -62,8 +123,7 @@ namespace Flurl.Http
|
||||
_parent = this,
|
||||
Settings = Settings,
|
||||
Url = Url,
|
||||
Cookies = Cookies,
|
||||
AutoDispose = AutoDispose
|
||||
Cookies = Cookies
|
||||
};
|
||||
}
|
||||
|
||||
@ -86,18 +146,18 @@ namespace Flurl.Http
|
||||
/// </summary>
|
||||
public IDictionary<string, Cookie> Cookies { get; private set; } = new Dictionary<string, Cookie>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the underlying HttpClient
|
||||
/// should be disposed immediately after the first HTTP call is made.
|
||||
/// </summary>
|
||||
public bool AutoDispose { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the HttpClient to be used in subsequent HTTP calls. Creation (when necessary) is delegated
|
||||
/// to FlurlHttp.HttpClientFactory. Reused for the life of the FlurlClient.
|
||||
/// </summary>
|
||||
public HttpClient HttpClient => EnsureHttpClient();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the HttpMessageHandler to be used in subsequent HTTP calls. Creation (when necessary) is delegated
|
||||
/// to FlurlHttp.HttpClientFactory.
|
||||
/// </summary>
|
||||
public HttpMessageHandler HttpMessageHandler => EnsureHttpMessageHandler();
|
||||
|
||||
private HttpClient EnsureHttpClient(HttpClient hc = null) {
|
||||
if (_httpClient == null) {
|
||||
if (hc == null) {
|
||||
@ -110,6 +170,19 @@ namespace Flurl.Http
|
||||
return _httpClient;
|
||||
}
|
||||
|
||||
private HttpMessageHandler EnsureHttpMessageHandler(HttpMessageHandler handler = null) {
|
||||
if (_httpMessageHandler == null) {
|
||||
if (handler == null) {
|
||||
handler = (HttpTest.Current == null) ?
|
||||
Settings.HttpClientFactory.CreateMessageHandler() :
|
||||
new FakeHttpMessageHandler();
|
||||
}
|
||||
_httpMessageHandler = handler;
|
||||
_parent?.EnsureHttpMessageHandler(handler);
|
||||
}
|
||||
return _httpMessageHandler;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates and asynchronously sends an HttpRequestMethod, disposing HttpClient if AutoDispose it true.
|
||||
/// Mainly used to implement higher-level extension methods (GetJsonAsync, etc).
|
||||
@ -124,14 +197,14 @@ namespace Flurl.Http
|
||||
var request = new HttpRequestMessage(verb, Url) { Content = content };
|
||||
if (Settings.CookiesEnabled)
|
||||
WriteRequestCookies(request);
|
||||
HttpCall.Set(request, Settings);
|
||||
request.SetFlurlHttpCall(Settings);
|
||||
var resp = await HttpClient.SendAsync(request, completionOption, cancellationToken ?? CancellationToken.None).ConfigureAwait(false);
|
||||
if (Settings.CookiesEnabled)
|
||||
ReadResponseCookies(resp);
|
||||
return resp;
|
||||
}
|
||||
finally {
|
||||
if (AutoDispose) Dispose();
|
||||
if (Settings.AutoDispose) Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@ -175,22 +248,6 @@ namespace Flurl.Http
|
||||
Cookies[cookie.Name] = cookie;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the HttpMessageHandler to be used in subsequent HTTP calls. Creation (when necessary) is delegated
|
||||
/// to FlurlHttp.HttpClientFactory.
|
||||
/// </summary>
|
||||
public HttpMessageHandler HttpMessageHandler => EnsureHttpMessageHandler();
|
||||
|
||||
private HttpMessageHandler EnsureHttpMessageHandler(HttpMessageHandler hmh = null) {
|
||||
if (_httpMessageHandler == null) {
|
||||
if (hmh == null)
|
||||
hmh = Settings.HttpClientFactory.CreateMessageHandler();
|
||||
_httpMessageHandler = hmh;
|
||||
_parent?.EnsureHttpMessageHandler(hmh);
|
||||
}
|
||||
return _httpMessageHandler;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes the underlying HttpClient and HttpMessageHandler, setting both properties to null.
|
||||
/// This FlurlClient can still be reused, but those underlying objects will be re-created as needed. Previously set headers, etc, will be lost.
|
||||
|
@ -37,7 +37,7 @@ namespace Flurl.Http
|
||||
/// Triggers the specified sync and async event handlers, usually defined on
|
||||
/// </summary>
|
||||
public static Task RaiseEventAsync(HttpRequestMessage request, FlurlEventType eventType) {
|
||||
var call = HttpCall.Get(request);
|
||||
var call = request.GetFlurlHttpCall();
|
||||
if (call == null)
|
||||
return NoOpTask.Instance;
|
||||
|
||||
|
@ -12,7 +12,7 @@ namespace Flurl.Http
|
||||
/// <summary>
|
||||
/// An object containing details about the failed HTTP call
|
||||
/// </summary>
|
||||
public HttpCall Call { get; private set; }
|
||||
public HttpCall Call { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FlurlHttpException"/> class.
|
||||
@ -41,16 +41,15 @@ namespace Flurl.Http
|
||||
if (call.Response != null && !call.Succeeded) {
|
||||
return string.Format("Request to {0} failed with status code {1} ({2}).",
|
||||
call.Request.RequestUri.AbsoluteUri,
|
||||
(int) call.Response.StatusCode,
|
||||
(int)call.Response.StatusCode,
|
||||
call.Response.ReasonPhrase);
|
||||
}
|
||||
if (inner != null) {
|
||||
return string.Format("Request to {0} failed. {1}",
|
||||
call.Request.RequestUri.AbsoluteUri, inner.Message);
|
||||
return $"Request to {call.Request.RequestUri.AbsoluteUri} failed. {inner.Message}";
|
||||
}
|
||||
|
||||
// in theory we should never get here.
|
||||
return string.Format("Request to {0} failed.", call.Request.RequestUri.AbsoluteUri);
|
||||
return $"Request to {call.Request.RequestUri.AbsoluteUri} failed.";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -94,7 +93,7 @@ namespace Flurl.Http
|
||||
public FlurlHttpTimeoutException(HttpCall call, Exception inner) : base(call, BuildMessage(call), inner) { }
|
||||
|
||||
private static string BuildMessage(HttpCall call) {
|
||||
return string.Format("Request to {0} timed out.", call);
|
||||
return $"Request to {call} timed out.";
|
||||
}
|
||||
}
|
||||
}
|
@ -13,30 +13,20 @@ namespace Flurl.Http
|
||||
/// </summary>
|
||||
public class HttpCall
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the Flurl HttpCall that was set for the given request, or null if Flurl.Http was not used to make the request
|
||||
/// </summary>
|
||||
public static HttpCall Get(HttpRequestMessage request) {
|
||||
object obj;
|
||||
if (request != null && request.Properties != null && request.Properties.TryGetValue("FlurlHttpCall", out obj) && obj is HttpCall)
|
||||
return (HttpCall)obj;
|
||||
return null;
|
||||
}
|
||||
|
||||
internal static void Set(HttpRequestMessage request, FlurlHttpSettings settings) {
|
||||
if (request != null && request.Properties != null)
|
||||
request.Properties["FlurlHttpCall"] = new HttpCall { Request = request, Settings = settings };
|
||||
internal HttpCall(HttpRequestMessage request, FlurlHttpSettings settings) {
|
||||
Request = request;
|
||||
Settings = settings;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// FlurlHttpSettings used for this call.
|
||||
/// </summary>
|
||||
public FlurlHttpSettings Settings { get; private set; }
|
||||
public FlurlHttpSettings Settings { get; }
|
||||
|
||||
/// <summary>
|
||||
/// HttpRequestMessage associated with this call.
|
||||
/// </summary>
|
||||
public HttpRequestMessage Request { get; private set; }
|
||||
public HttpRequestMessage Request { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Captured request body. More reliably available than HttpRequestMessage.Content, which is a forward-only, read-once stream.
|
||||
@ -72,46 +62,53 @@ namespace Flurl.Http
|
||||
/// <summary>
|
||||
/// Total duration of the call if it completed, otherwise null.
|
||||
/// </summary>
|
||||
public TimeSpan? Duration {
|
||||
get { return EndedUtc - StartedUtc; }
|
||||
}
|
||||
public TimeSpan? Duration => EndedUtc - StartedUtc;
|
||||
|
||||
/// <summary>
|
||||
/// Absolute URI being called.
|
||||
/// </summary>
|
||||
public string Url {
|
||||
get { return Request.RequestUri.AbsoluteUri; }
|
||||
}
|
||||
public string Url => Request.RequestUri.AbsoluteUri;
|
||||
|
||||
/// <summary>
|
||||
/// True if a response was received, regardless of whether it is an error status.
|
||||
/// </summary>
|
||||
public bool Completed {
|
||||
get { return Response != null; }
|
||||
}
|
||||
public bool Completed => Response != null;
|
||||
|
||||
/// <summary>
|
||||
/// True if a response with a successful HTTP status was received.
|
||||
/// </summary>
|
||||
public bool Succeeded {
|
||||
get {
|
||||
return
|
||||
!Completed ? false :
|
||||
Response.IsSuccessStatusCode ? true :
|
||||
HttpStatusRangeParser.IsMatch(Settings.AllowedHttpStatusRange, Response.StatusCode);
|
||||
}
|
||||
}
|
||||
public bool Succeeded => Completed &&
|
||||
(Response.IsSuccessStatusCode || HttpStatusRangeParser.IsMatch(Settings.AllowedHttpStatusRange, Response.StatusCode));
|
||||
|
||||
/// <summary>
|
||||
/// HttpStatusCode of the response if the call completed, otherwise null.
|
||||
/// </summary>
|
||||
public HttpStatusCode? HttpStatus {
|
||||
get { return Completed ? (HttpStatusCode?)Response.StatusCode : null; }
|
||||
}
|
||||
public HttpStatusCode? HttpStatus => Completed ? (HttpStatusCode?)Response.StatusCode : null;
|
||||
|
||||
/// <summary>
|
||||
/// Body of the HTTP response if unsuccessful, otherwise null. (Successful responses are not captured as strings, mainly for performance reasons.)
|
||||
/// </summary>
|
||||
public string ErrorResponseBody { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flurl extensions to HttpRequestMessage
|
||||
/// </summary>
|
||||
public static class HttpRequestMessageExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the Flurl HttpCall that was set for the given request, or null if Flurl.Http was not used to make the request
|
||||
/// </summary>
|
||||
public static HttpCall GetFlurlHttpCall(this HttpRequestMessage request) {
|
||||
object obj;
|
||||
if (request?.Properties != null && request.Properties.TryGetValue("FlurlHttpCall", out obj) && obj is HttpCall)
|
||||
return (HttpCall)obj;
|
||||
return null;
|
||||
}
|
||||
|
||||
internal static void SetFlurlHttpCall(this HttpRequestMessage request, FlurlHttpSettings settings) {
|
||||
if (request?.Properties != null)
|
||||
request.Properties["FlurlHttpCall"] = new HttpCall(request, settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -43,13 +43,13 @@ namespace Flurl.Http
|
||||
/// <summary>
|
||||
/// Sends an asynchronous request.
|
||||
/// </summary>
|
||||
/// <param name="client">The Flurl client.</param>
|
||||
/// <param name="client">The IFlurlClient instance.</param>
|
||||
/// <param name="verb">The HTTP method used to make the request.</param>
|
||||
/// <param name="data">Contents of the request body.</param>
|
||||
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional.</param>
|
||||
/// <param name="completionOption">The HttpCompletionOption used in the request. Optional.</param>
|
||||
/// <returns>A Task whose result is the received HttpResponseMessage.</returns>
|
||||
public static Task<HttpResponseMessage> SendJsonAsync(this FlurlClient client, HttpMethod verb, object data, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
public static Task<HttpResponseMessage> SendJsonAsync(this IFlurlClient client, HttpMethod verb, object data, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
var content = new CapturedJsonContent(client.Settings.JsonSerializer.Serialize(data));
|
||||
return client.SendAsync(verb, content: content, cancellationToken: cancellationToken, completionOption: completionOption);
|
||||
}
|
||||
@ -83,13 +83,13 @@ namespace Flurl.Http
|
||||
/// <summary>
|
||||
/// Sends an asynchronous request.
|
||||
/// </summary>
|
||||
/// <param name="client">The Flurl client.</param>
|
||||
/// <param name="client">The IFlurlClient instance.</param>
|
||||
/// <param name="verb">The HTTP method used to make the request.</param>
|
||||
/// <param name="data">Contents of the request body.</param>
|
||||
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional.</param>
|
||||
/// <param name="completionOption">The HttpCompletionOption used in the request. Optional.</param>
|
||||
/// <returns>A Task whose result is the received HttpResponseMessage.</returns>
|
||||
public static Task<HttpResponseMessage> SendStringAsync(this FlurlClient client, HttpMethod verb, string data, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
public static Task<HttpResponseMessage> SendStringAsync(this IFlurlClient client, HttpMethod verb, string data, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
var content = new CapturedStringContent(data);
|
||||
return client.SendAsync(verb, content: content, cancellationToken: cancellationToken, completionOption: completionOption);
|
||||
}
|
||||
@ -123,13 +123,13 @@ namespace Flurl.Http
|
||||
/// <summary>
|
||||
/// Sends an asynchronous request.
|
||||
/// </summary>
|
||||
/// <param name="client">The Flurl client.</param>
|
||||
/// <param name="client">The IFlurlClient instance.</param>
|
||||
/// <param name="verb">The HTTP method used to make the request.</param>
|
||||
/// <param name="data">Contents of the request body.</param>
|
||||
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional.</param>
|
||||
/// <param name="completionOption">The HttpCompletionOption used in the request. Optional.</param>
|
||||
/// <returns>A Task whose result is the received HttpResponseMessage.</returns>
|
||||
public static Task<HttpResponseMessage> SendUrlEncodedAsync(this FlurlClient client, HttpMethod verb, object data, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
public static Task<HttpResponseMessage> SendUrlEncodedAsync(this IFlurlClient client, HttpMethod verb, object data, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
var content = new CapturedUrlEncodedContent(client.Settings.UrlEncodedSerializer.Serialize(data));
|
||||
return client.SendAsync(verb, content: content, cancellationToken: cancellationToken, completionOption: completionOption);
|
||||
}
|
||||
@ -163,77 +163,77 @@ namespace Flurl.Http
|
||||
/// <summary>
|
||||
/// Sends an asynchronous GET request.
|
||||
/// </summary>
|
||||
/// <param name="client">The Flurl client.</param>
|
||||
/// <param name="client">The IFlurlClient instance.</param>
|
||||
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional.</param>
|
||||
/// <param name="completionOption">The HttpCompletionOption used in the request. Optional.</param>
|
||||
/// <returns>A Task whose result is the received HttpResponseMessage.</returns>
|
||||
public static Task<HttpResponseMessage> GetAsync(this FlurlClient client, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
public static Task<HttpResponseMessage> GetAsync(this IFlurlClient client, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
return client.SendAsync(HttpMethod.Get, cancellationToken: cancellationToken, completionOption: completionOption);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends an asynchronous GET request.
|
||||
/// </summary>
|
||||
/// <param name="client">The Flurl client.</param>
|
||||
/// <param name="client">The IFlurlClient instance.</param>
|
||||
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional.</param>
|
||||
/// <param name="completionOption">The HttpCompletionOption used in the request. Optional.</param>
|
||||
/// <returns>A Task whose result is the JSON response body deserialized to an object of type T.</returns>
|
||||
public static Task<T> GetJsonAsync<T>(this FlurlClient client, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
public static Task<T> GetJsonAsync<T>(this IFlurlClient client, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
return client.SendAsync(HttpMethod.Get, cancellationToken: cancellationToken, completionOption: completionOption).ReceiveJson<T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends an asynchronous GET request.
|
||||
/// </summary>
|
||||
/// <param name="client">The Flurl client.</param>
|
||||
/// <param name="client">The IFlurlClient instance.</param>
|
||||
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional.</param>
|
||||
/// <param name="completionOption">The HttpCompletionOption used in the request. Optional.</param>
|
||||
/// <returns>A Task whose result is the JSON response body deserialized to a dynamic.</returns>
|
||||
public static Task<dynamic> GetJsonAsync(this FlurlClient client, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
public static Task<dynamic> GetJsonAsync(this IFlurlClient client, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
return client.SendAsync(HttpMethod.Get, cancellationToken: cancellationToken, completionOption: completionOption).ReceiveJson();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends an asynchronous GET request.
|
||||
/// </summary>
|
||||
/// <param name="client">The Flurl client.</param>
|
||||
/// <param name="client">The IFlurlClient instance.</param>
|
||||
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional.</param>
|
||||
/// <param name="completionOption">The HttpCompletionOption used in the request. Optional.</param>
|
||||
/// <returns>A Task whose result is the JSON response body deserialized to a list of dynamics.</returns>
|
||||
public static Task<IList<dynamic>> GetJsonListAsync(this FlurlClient client, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
public static Task<IList<dynamic>> GetJsonListAsync(this IFlurlClient client, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
return client.SendAsync(HttpMethod.Get, cancellationToken: cancellationToken, completionOption: completionOption).ReceiveJsonList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends an asynchronous GET request.
|
||||
/// </summary>
|
||||
/// <param name="client">The Flurl client.</param>
|
||||
/// <param name="client">The IFlurlClient instance.</param>
|
||||
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional.</param>
|
||||
/// <param name="completionOption">The HttpCompletionOption used in the request. Optional.</param>
|
||||
/// <returns>A Task whose result is the response body as a string.</returns>
|
||||
public static Task<string> GetStringAsync(this FlurlClient client, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
public static Task<string> GetStringAsync(this IFlurlClient client, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
return client.SendAsync(HttpMethod.Get, cancellationToken: cancellationToken, completionOption: completionOption).ReceiveString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends an asynchronous GET request.
|
||||
/// </summary>
|
||||
/// <param name="client">The Flurl client.</param>
|
||||
/// <param name="client">The IFlurlClient instance.</param>
|
||||
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional.</param>
|
||||
/// <param name="completionOption">The HttpCompletionOption used in the request. Optional.</param>
|
||||
/// <returns>A Task whose result is the response body as a Stream.</returns>
|
||||
public static Task<Stream> GetStreamAsync(this FlurlClient client, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
public static Task<Stream> GetStreamAsync(this IFlurlClient client, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
return client.SendAsync(HttpMethod.Get, cancellationToken: cancellationToken, completionOption: completionOption).ReceiveStream();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends an asynchronous GET request.
|
||||
/// </summary>
|
||||
/// <param name="client">The Flurl client.</param>
|
||||
/// <param name="client">The IFlurlClient instance.</param>
|
||||
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional.</param>
|
||||
/// <param name="completionOption">The HttpCompletionOption used in the request. Optional.</param>
|
||||
/// <returns>A Task whose result is the response body as a byte array.</returns>
|
||||
public static Task<byte[]> GetBytesAsync(this FlurlClient client, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
public static Task<byte[]> GetBytesAsync(this IFlurlClient client, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
return client.SendAsync(HttpMethod.Get, cancellationToken: cancellationToken, completionOption: completionOption).ReceiveBytes();
|
||||
}
|
||||
|
||||
@ -394,12 +394,12 @@ namespace Flurl.Http
|
||||
/// <summary>
|
||||
/// Sends an asynchronous POST request.
|
||||
/// </summary>
|
||||
/// <param name="client">The Flurl client.</param>
|
||||
/// <param name="client">The IFlurlClient instance.</param>
|
||||
/// <param name="content">Contents of the request body.</param>
|
||||
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional.</param>
|
||||
/// <param name="completionOption">The HttpCompletionOption used in the request. Optional.</param>
|
||||
/// <returns>A Task whose result is the received HttpResponseMessage.</returns>
|
||||
public static Task<HttpResponseMessage> PostAsync(this FlurlClient client, HttpContent content, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
public static Task<HttpResponseMessage> PostAsync(this IFlurlClient client, HttpContent content, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
return client.SendAsync(HttpMethod.Post, content: content, cancellationToken: cancellationToken, completionOption: completionOption);
|
||||
}
|
||||
|
||||
@ -430,12 +430,12 @@ namespace Flurl.Http
|
||||
/// <summary>
|
||||
/// Sends an asynchronous POST request.
|
||||
/// </summary>
|
||||
/// <param name="client">The Flurl client.</param>
|
||||
/// <param name="client">The IFlurlClient instance.</param>
|
||||
/// <param name="data">Contents of the request body.</param>
|
||||
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional.</param>
|
||||
/// <param name="completionOption">The HttpCompletionOption used in the request. Optional.</param>
|
||||
/// <returns>A Task whose result is the received HttpResponseMessage.</returns>
|
||||
public static Task<HttpResponseMessage> PostJsonAsync(this FlurlClient client, object data, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
public static Task<HttpResponseMessage> PostJsonAsync(this IFlurlClient client, object data, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
var content = new CapturedJsonContent(client.Settings.JsonSerializer.Serialize(data));
|
||||
return client.SendAsync(HttpMethod.Post, content: content, cancellationToken: cancellationToken, completionOption: completionOption);
|
||||
}
|
||||
@ -467,12 +467,12 @@ namespace Flurl.Http
|
||||
/// <summary>
|
||||
/// Sends an asynchronous POST request.
|
||||
/// </summary>
|
||||
/// <param name="client">The Flurl client.</param>
|
||||
/// <param name="client">The IFlurlClient instance.</param>
|
||||
/// <param name="data">Contents of the request body.</param>
|
||||
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional.</param>
|
||||
/// <param name="completionOption">The HttpCompletionOption used in the request. Optional.</param>
|
||||
/// <returns>A Task whose result is the received HttpResponseMessage.</returns>
|
||||
public static Task<HttpResponseMessage> PostStringAsync(this FlurlClient client, string data, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
public static Task<HttpResponseMessage> PostStringAsync(this IFlurlClient client, string data, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
var content = new CapturedStringContent(data);
|
||||
return client.SendAsync(HttpMethod.Post, content: content, cancellationToken: cancellationToken, completionOption: completionOption);
|
||||
}
|
||||
@ -504,12 +504,12 @@ namespace Flurl.Http
|
||||
/// <summary>
|
||||
/// Sends an asynchronous POST request.
|
||||
/// </summary>
|
||||
/// <param name="client">The Flurl client.</param>
|
||||
/// <param name="client">The IFlurlClient instance.</param>
|
||||
/// <param name="data">Contents of the request body.</param>
|
||||
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional.</param>
|
||||
/// <param name="completionOption">The HttpCompletionOption used in the request. Optional.</param>
|
||||
/// <returns>A Task whose result is the received HttpResponseMessage.</returns>
|
||||
public static Task<HttpResponseMessage> PostUrlEncodedAsync(this FlurlClient client, object data, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
public static Task<HttpResponseMessage> PostUrlEncodedAsync(this IFlurlClient client, object data, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
var content = new CapturedUrlEncodedContent(client.Settings.UrlEncodedSerializer.Serialize(data));
|
||||
return client.SendAsync(HttpMethod.Post, content: content, cancellationToken: cancellationToken, completionOption: completionOption);
|
||||
}
|
||||
@ -541,11 +541,11 @@ namespace Flurl.Http
|
||||
/// <summary>
|
||||
/// Sends an asynchronous HEAD request.
|
||||
/// </summary>
|
||||
/// <param name="client">The Flurl client.</param>
|
||||
/// <param name="client">The IFlurlClient instance.</param>
|
||||
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional.</param>
|
||||
/// <param name="completionOption">The HttpCompletionOption used in the request. Optional.</param>
|
||||
/// <returns>A Task whose result is the received HttpResponseMessage.</returns>
|
||||
public static Task<HttpResponseMessage> HeadAsync(this FlurlClient client, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
public static Task<HttpResponseMessage> HeadAsync(this IFlurlClient client, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
return client.SendAsync(HttpMethod.Head, cancellationToken: cancellationToken, completionOption: completionOption);
|
||||
}
|
||||
|
||||
@ -574,12 +574,12 @@ namespace Flurl.Http
|
||||
/// <summary>
|
||||
/// Sends an asynchronous PUT request.
|
||||
/// </summary>
|
||||
/// <param name="client">The Flurl client.</param>
|
||||
/// <param name="client">The IFlurlClient instance.</param>
|
||||
/// <param name="content">Contents of the request body.</param>
|
||||
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional.</param>
|
||||
/// <param name="completionOption">The HttpCompletionOption used in the request. Optional.</param>
|
||||
/// <returns>A Task whose result is the received HttpResponseMessage.</returns>
|
||||
public static Task<HttpResponseMessage> PutAsync(this FlurlClient client, HttpContent content, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
public static Task<HttpResponseMessage> PutAsync(this IFlurlClient client, HttpContent content, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
return client.SendAsync(HttpMethod.Put, content: content, cancellationToken: cancellationToken, completionOption: completionOption);
|
||||
}
|
||||
|
||||
@ -610,12 +610,12 @@ namespace Flurl.Http
|
||||
/// <summary>
|
||||
/// Sends an asynchronous PUT request.
|
||||
/// </summary>
|
||||
/// <param name="client">The Flurl client.</param>
|
||||
/// <param name="client">The IFlurlClient instance.</param>
|
||||
/// <param name="data">Contents of the request body.</param>
|
||||
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional.</param>
|
||||
/// <param name="completionOption">The HttpCompletionOption used in the request. Optional.</param>
|
||||
/// <returns>A Task whose result is the received HttpResponseMessage.</returns>
|
||||
public static Task<HttpResponseMessage> PutJsonAsync(this FlurlClient client, object data, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
public static Task<HttpResponseMessage> PutJsonAsync(this IFlurlClient client, object data, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
var content = new CapturedJsonContent(client.Settings.JsonSerializer.Serialize(data));
|
||||
return client.SendAsync(HttpMethod.Put, content: content, cancellationToken: cancellationToken, completionOption: completionOption);
|
||||
}
|
||||
@ -647,12 +647,12 @@ namespace Flurl.Http
|
||||
/// <summary>
|
||||
/// Sends an asynchronous PUT request.
|
||||
/// </summary>
|
||||
/// <param name="client">The Flurl client.</param>
|
||||
/// <param name="client">The IFlurlClient instance.</param>
|
||||
/// <param name="data">Contents of the request body.</param>
|
||||
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional.</param>
|
||||
/// <param name="completionOption">The HttpCompletionOption used in the request. Optional.</param>
|
||||
/// <returns>A Task whose result is the received HttpResponseMessage.</returns>
|
||||
public static Task<HttpResponseMessage> PutStringAsync(this FlurlClient client, string data, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
public static Task<HttpResponseMessage> PutStringAsync(this IFlurlClient client, string data, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
var content = new CapturedStringContent(data);
|
||||
return client.SendAsync(HttpMethod.Put, content: content, cancellationToken: cancellationToken, completionOption: completionOption);
|
||||
}
|
||||
@ -684,11 +684,11 @@ namespace Flurl.Http
|
||||
/// <summary>
|
||||
/// Sends an asynchronous DELETE request.
|
||||
/// </summary>
|
||||
/// <param name="client">The Flurl client.</param>
|
||||
/// <param name="client">The IFlurlClient instance.</param>
|
||||
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional.</param>
|
||||
/// <param name="completionOption">The HttpCompletionOption used in the request. Optional.</param>
|
||||
/// <returns>A Task whose result is the received HttpResponseMessage.</returns>
|
||||
public static Task<HttpResponseMessage> DeleteAsync(this FlurlClient client, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
public static Task<HttpResponseMessage> DeleteAsync(this IFlurlClient client, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
return client.SendAsync(HttpMethod.Delete, cancellationToken: cancellationToken, completionOption: completionOption);
|
||||
}
|
||||
|
||||
@ -717,12 +717,12 @@ namespace Flurl.Http
|
||||
/// <summary>
|
||||
/// Sends an asynchronous PATCH request.
|
||||
/// </summary>
|
||||
/// <param name="client">The Flurl client.</param>
|
||||
/// <param name="client">The IFlurlClient instance.</param>
|
||||
/// <param name="content">Contents of the request body.</param>
|
||||
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional.</param>
|
||||
/// <param name="completionOption">The HttpCompletionOption used in the request. Optional.</param>
|
||||
/// <returns>A Task whose result is the received HttpResponseMessage.</returns>
|
||||
public static Task<HttpResponseMessage> PatchAsync(this FlurlClient client, HttpContent content, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
public static Task<HttpResponseMessage> PatchAsync(this IFlurlClient client, HttpContent content, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
return client.SendAsync(new HttpMethod("PATCH"), content: content, cancellationToken: cancellationToken, completionOption: completionOption);
|
||||
}
|
||||
|
||||
@ -753,12 +753,12 @@ namespace Flurl.Http
|
||||
/// <summary>
|
||||
/// Sends an asynchronous PATCH request.
|
||||
/// </summary>
|
||||
/// <param name="client">The Flurl client.</param>
|
||||
/// <param name="client">The IFlurlClient instance.</param>
|
||||
/// <param name="data">Contents of the request body.</param>
|
||||
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional.</param>
|
||||
/// <param name="completionOption">The HttpCompletionOption used in the request. Optional.</param>
|
||||
/// <returns>A Task whose result is the received HttpResponseMessage.</returns>
|
||||
public static Task<HttpResponseMessage> PatchJsonAsync(this FlurlClient client, object data, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
public static Task<HttpResponseMessage> PatchJsonAsync(this IFlurlClient client, object data, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
var content = new CapturedJsonContent(client.Settings.JsonSerializer.Serialize(data));
|
||||
return client.SendAsync(new HttpMethod("PATCH"), content: content, cancellationToken: cancellationToken, completionOption: completionOption);
|
||||
}
|
||||
@ -790,12 +790,12 @@ namespace Flurl.Http
|
||||
/// <summary>
|
||||
/// Sends an asynchronous PATCH request.
|
||||
/// </summary>
|
||||
/// <param name="client">The Flurl client.</param>
|
||||
/// <param name="client">The IFlurlClient instance.</param>
|
||||
/// <param name="data">Contents of the request body.</param>
|
||||
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional.</param>
|
||||
/// <param name="completionOption">The HttpCompletionOption used in the request. Optional.</param>
|
||||
/// <returns>A Task whose result is the received HttpResponseMessage.</returns>
|
||||
public static Task<HttpResponseMessage> PatchStringAsync(this FlurlClient client, string data, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
public static Task<HttpResponseMessage> PatchStringAsync(this IFlurlClient client, string data, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead) {
|
||||
var content = new CapturedStringContent(data);
|
||||
return client.SendAsync(new HttpMethod("PATCH"), content: content, cancellationToken: cancellationToken, completionOption: completionOption);
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ namespace Flurl.Http
|
||||
/// <exception cref="FlurlHttpException">Condition.</exception>
|
||||
public static async Task<T> ReceiveJson<T>(this Task<HttpResponseMessage> response) {
|
||||
var resp = await response.ConfigureAwait(false);
|
||||
var call = HttpCall.Get(resp.RequestMessage);
|
||||
var call = resp.RequestMessage.GetFlurlHttpCall();
|
||||
try {
|
||||
using (var stream = await resp.Content.ReadAsStreamAsync().ConfigureAwait(false))
|
||||
return call.Settings.JsonSerializer.Deserialize<T>(stream);
|
||||
|
@ -18,7 +18,7 @@ namespace Flurl.Http
|
||||
/// <param name="client">The Flurl client.</param>
|
||||
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
|
||||
/// <returns>A Task whose result is the received HttpResponseMessage.</returns>
|
||||
public static Task<HttpResponseMessage> PostMultipartAsync(this FlurlClient client, Action<CapturedMultipartContent> buildContent, CancellationToken cancellationToken = default(CancellationToken)) {
|
||||
public static Task<HttpResponseMessage> PostMultipartAsync(this IFlurlClient client, Action<CapturedMultipartContent> buildContent, CancellationToken cancellationToken = default(CancellationToken)) {
|
||||
var cmc = new CapturedMultipartContent(client.Settings);
|
||||
buildContent(cmc);
|
||||
return client.SendAsync(HttpMethod.Post, cmc, cancellationToken);
|
||||
|
@ -11,24 +11,15 @@ namespace Flurl.Http.Testing
|
||||
/// </summary>
|
||||
public class FakeHttpMessageHandler : HttpMessageHandler
|
||||
{
|
||||
private readonly Func<HttpResponseMessage> _responseFactory;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FakeHttpMessageHandler"/> class.
|
||||
/// </summary>
|
||||
/// <param name="responseFactory">The response factory.</param>
|
||||
public FakeHttpMessageHandler(Func<HttpResponseMessage> responseFactory) {
|
||||
_responseFactory = responseFactory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends the request asynchronous.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) {
|
||||
var resp = _responseFactory();
|
||||
HttpTest.Current?.CallLog.Add(request.GetFlurlHttpCall());
|
||||
var tcs = new TaskCompletionSource<HttpResponseMessage>();
|
||||
var resp = HttpTest.Current?.GetNextResponse() ?? new HttpResponseMessage();
|
||||
if (resp is TimeoutResponseMessage)
|
||||
tcs.SetCanceled();
|
||||
else
|
||||
|
@ -4,6 +4,7 @@ using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Flurl.Util;
|
||||
|
||||
namespace Flurl.Http.Testing
|
||||
{
|
||||
@ -45,7 +46,40 @@ namespace Flurl.Http.Testing
|
||||
/// <param name="urlPattern">Can contain * wildcard.</param>
|
||||
public HttpCallAssertion WithUrlPattern(string urlPattern) {
|
||||
_urlPattern = urlPattern; // this will land in the exception message when we assert, which is the only reason for capturing it
|
||||
return With(c => MatchesPattern(c.Request.RequestUri.AbsoluteUri, urlPattern));
|
||||
return With(c => MatchesPattern(c.Url, urlPattern));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asserts whether calls were made containing the given query parameter (regardless of its value).
|
||||
/// </summary>
|
||||
/// <param name="name">The query parameter name.</param>
|
||||
/// <returns></returns>
|
||||
public HttpCallAssertion WithQueryParam(string name) {
|
||||
return With(c => new Url(c.Url).QueryParams.Any(q => q.Name == name));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asserts whether calls were made containing the given query parameter name/value.
|
||||
/// </summary>
|
||||
/// <param name="name">The query parameter name.</param>
|
||||
/// <param name="value">The query parameter value. Can contain * wildcard.</param>
|
||||
/// <returns></returns>
|
||||
public HttpCallAssertion WithQueryParam(string name, object value) {
|
||||
return With(c => new Url(c.Url).QueryParams.Any(q => q.Name == name && MatchesPattern(q.Value.ToString(), value.ToString())));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asserts whether calls were made containing all of the given query parameters.
|
||||
/// </summary>
|
||||
/// <param name="values">Object (usually anonymous) or dictionary that is parsed to name/value query parameters to check for.</param>
|
||||
/// <returns></returns>
|
||||
public HttpCallAssertion WithQueryParams(object values) {
|
||||
return With(c => {
|
||||
var expected = values.ToKeyValuePairs().Select(kv => $"{kv.Key}={kv.Value}");
|
||||
var actual = new Url(c.Url).QueryParams.Select(q => $"{q.Name}={q.Value}");
|
||||
//http://stackoverflow.com/a/333034/62600
|
||||
return !expected.Except(actual).Any();
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -14,6 +14,11 @@ namespace Flurl.Http.Testing
|
||||
/// </summary>
|
||||
public class HttpTest : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the current HttpTest from the logical (async) call context
|
||||
/// </summary>
|
||||
public static HttpTest Current => GetCurrentTest();
|
||||
|
||||
private static readonly HttpResponseMessage EmptyResponse = new HttpResponseMessage {
|
||||
StatusCode = HttpStatusCode.OK,
|
||||
Content = new StringContent("")
|
||||
@ -24,13 +29,10 @@ namespace Flurl.Http.Testing
|
||||
/// </summary>
|
||||
/// <exception cref="Exception">A delegate callback throws an exception.</exception>
|
||||
public HttpTest() {
|
||||
FlurlHttp.Configure(settings => {
|
||||
settings.HttpClientFactory = new TestHttpClientFactory(this);
|
||||
settings.AfterCall = call => CallLog.Add(call);
|
||||
});
|
||||
ResponseQueue = new Queue<HttpResponseMessage>();
|
||||
CallLog = new List<HttpCall>();
|
||||
}
|
||||
SetCurrentTest(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an HttpResponseMessage to the response queue.
|
||||
@ -118,15 +120,29 @@ namespace Flurl.Http.Testing
|
||||
/// Throws an HttpCallAssertException if a URL matching the given pattern was called.
|
||||
/// </summary>
|
||||
/// <param name="urlPattern">URL that should not have been called. Can include * wildcard character.</param>
|
||||
public HttpCallAssertion ShouldNotHaveCalled(string urlPattern) {
|
||||
return new HttpCallAssertion(CallLog, true).WithUrlPattern(urlPattern);
|
||||
public void ShouldNotHaveCalled(string urlPattern) {
|
||||
new HttpCallAssertion(CallLog, true).WithUrlPattern(urlPattern);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases unmanaged and - optionally - managed resources.
|
||||
/// </summary>
|
||||
public void Dispose() {
|
||||
SetCurrentTest(null);
|
||||
FlurlHttp.GlobalSettings.ResetDefaults();
|
||||
}
|
||||
|
||||
#if PORTABLE
|
||||
private static HttpTest _test;
|
||||
private static void SetCurrentTest(HttpTest test) => _test = test;
|
||||
private static HttpTest GetCurrentTest() => _test;
|
||||
#elif NET45
|
||||
private static void SetCurrentTest(HttpTest test) => System.Runtime.Remoting.Messaging.CallContext.LogicalSetData("FlurlHttpTest", test);
|
||||
private static HttpTest GetCurrentTest() => System.Runtime.Remoting.Messaging.CallContext.LogicalGetData("FlurlHttpTest") as HttpTest;
|
||||
#else
|
||||
private static System.Threading.AsyncLocal<HttpTest> _test = new System.Threading.AsyncLocal<HttpTest>();
|
||||
private static void SetCurrentTest(HttpTest test) => _test.Value = test;
|
||||
private static HttpTest GetCurrentTest() => _test.Value;
|
||||
#endif
|
||||
}
|
||||
}
|
@ -8,22 +8,12 @@ namespace Flurl.Http.Testing
|
||||
/// </summary>
|
||||
public class TestHttpClientFactory : DefaultHttpClientFactory
|
||||
{
|
||||
private readonly HttpTest _test;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TestHttpClientFactory"/> class.
|
||||
/// </summary>
|
||||
/// <param name="test">The test.</param>
|
||||
public TestHttpClientFactory(HttpTest test) {
|
||||
_test = test;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the message handler.
|
||||
/// Creates an instance of FakeHttpMessageHander, which prevents actual HTTP calls from being made.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override HttpMessageHandler CreateMessageHandler() {
|
||||
return new FakeHttpMessageHandler(_test.GetNextResponse);
|
||||
return new FakeHttpMessageHandler();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"title": "Flurl.Http",
|
||||
"version": "1.0.3",
|
||||
"version": "1.1.0-pre",
|
||||
|
||||
"dependencies": {
|
||||
"Flurl": "2.2.1",
|
||||
|
Loading…
x
Reference in New Issue
Block a user