使用Flurl轻松构建URL并在.NET中进行可测试的HttpClient调用

I posted about using Refit along with ASP.NET Core 2.1's HttpClientFactory earlier this week. Several times when exploring this space (both on Twitter, googling around, and in my own blog comments) I come upon Flurl as in, "Fluent URL."

本周早些时候发布了有关将Refit与ASP.NET Core 2.1的HttpClientFactory一起使用的信息。 在探索这个空间时,有好几次(在Twitter上,在谷歌上搜索以及在我自己的博客评论中),我对Flurl的看法都是“ Fluent URL”。

Not only is that a killer name for an open source project, Flurl is very active, very complete, and very interesting. By the way, take a look at the https://flurl.dev/ site for a great example of a good home page for a well-run open source library. Clear, crisp, unambiguous, with links on how to Get It, Learn It, and Contribute. Not to mention extensive docs. Kudos!

Flurl不仅是开源项目的杀手name,而且非常活跃,非常完整并且非常有趣。 顺便说一下,看看https://flurl.dev/网站,这是一个运行良好的开源库的良好主页的绝佳示例。 清晰,清晰,明确,并包含有关如何获取,学习和贡献的链接。 更不用说广泛的文档了。 荣誉!

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

Flurl是一个现代,流畅,异步,可测试,可移植,带有流行语的URL构建器和.NET的HTTP客户端库。

You had me at buzzword-laden! Flurl embraces the .NET Standard and works on .NET Framework, .NET Core, Xamarin, and UWP - so, everywhere.

你让我满口时髦! Flurl包含.NET标准,可在.NET Framework,.NET Core,Xamarin和UWP上使用-因此,无处不在。

To use just the Url Builder by installing Flurl. For the kitchen sink (recommended) you'll install Flurl.Http. In fact, Todd Menier was kind enough to share what a Flurl implementation of my SimpleCastClient would look like! Just to refresh you, my podcast site uses the SimpleCast podcast hosting API as its back-end.

通过安装Flurl仅使用Url Builder。 对于厨房水槽(推荐),您将安装Flurl.Http 。 实际上, Todd Menier非常乐于分享我的SimpleCastClient的Flurl实现。 为了让您耳目一新,我的播客站点使用SimpleCast播客托管API作为其后端。

My super basic typed implementation that "has a" HttpClient looks like this. To be clear this sample is WITHOUT FLURL.

我的“具有” HttpClient的超级基本类型实现看起来像这样。 要明确的是,此示例是WITHFLURL。

public class SimpleCastClient
{
private HttpClient _client;
private ILogger<SimpleCastClient> _logger;
private readonly string _apiKey;

public SimpleCastClient(HttpClient client, ILogger<SimpleCastClient> logger, IConfiguration config)
{
_client = client;
_client.BaseAddress = new Uri($"https://api.simplecast.com"); //Could also be set in Startup.cs
_logger = logger;
_apiKey = config["SimpleCastAPIKey"];
}

public async Task<List<Show>> GetShows()
{
try
{
var episodesUrl = new Uri($"/v1/podcasts/shownum/episodes.json?api_key={_apiKey}", UriKind.Relative);
_logger.LogWarning($"HttpClient: Loading {episodesUrl}");
var res = await _client.GetAsync(episodesUrl);
res.EnsureSuccessStatusCode();
return await res.Content.ReadAsAsync<List<Show>>();
}
catch (HttpRequestException ex)
{
_logger.LogError($"An error occurred connecting to SimpleCast API {ex.ToString()}");
throw;
}
}
}

Let's explore Tim's expression of the same client using the Flurl library!

让我们使用Flurl库探索Tim对同一客户端的表达

Not we set up a client in Startup.cs, use the same configuration, and also put in some nice aspect-oriented events for logging the befores and afters. This is VERY nice and you'll note it pulls my cluttered logging code right out of the client!

我们不是在Startup.cs中设置客户端,使用相同的配置,还放置了一些不错的面向方面的事件来记录事前和事后。 这非常好,您会注意到它将我混乱的日志记录代码从客户端中拉出了!

// Do this in Startup. All calls to SimpleCast will use the same HttpClient instance.
FlurlHttp.ConfigureClient(Configuration["SimpleCastServiceUri"], cli => cli
.Configure(settings =>
{
// keeps logging & error handling out of SimpleCastClient
settings.BeforeCall = call => logger.LogWarning($"Calling {call.Request.RequestUri}");
settings.OnError = call => logger.LogError($"Call to SimpleCast failed: {call.Exception}");
})
// adds default headers to send with every call
.WithHeaders(new
{
Accept = "application/json",
User_Agent = "MyCustomUserAgent" // Flurl will convert that underscore to a hyphen
}));

Again, this set up code lives in Startup.cs and is a one-time thing. The Headers, User Agent all are dealt with once there and in a one-line chained "fluent" manner.

同样,此设置代码位于Startup.cs中,是一次性的事情。 标头,用户代理都在这里以单行链接的“流利”方式处理。

Here's the new SimpleCastClient with Flurl.

这是带有Flurl的新SimpleCastClient

using Flurl;
using Flurl.Http;

public class SimpleCastClient
{
// look ma, no client!
private readonly string _baseUrl;
private readonly string _apiKey;

public SimpleCastClient(IConfiguration config)
{
_baseUrl = config["SimpleCastServiceUri"];
_apiKey = config["SimpleCastAPIKey"];
}

public Task<List<Show>> GetShows()
{
return _baseUrl
.AppendPathSegment("v1/podcasts/shownum/episodes.json")
.SetQueryParam("api_key", _apiKey)
.GetJsonAsync<List<Show>>();
}
}

See in GetShows() how we're also using the Url Builder fluent extensions in the Flurl library. See that _baseUrl is actually a string? We all know that we're supposed to use System.Uri but it's such a hassle. Flurl adds extension methods to strings so that you can seamlessly transition from the strings (that we all use) representations of Urls/Uris and build up a Query String, and in this case, a GET that returns JSON.

在GetShows()中了解我们如何在Flurl库中使用Url Builder fluent扩展。 看到_baseUrl实际上是一个字符串吗? 大家都知道我们应该使用System.Uri,但这很麻烦。 Flurl将扩展方法添加到字符串中,以便您可以从Urls / Uris的字符串表示形式(我们都使用)无缝过渡,并构建查询字符串,在这种情况下,还可以返回JSON。

Very clean!

很干净!

Flurl also prides itself on making HttpClient testing easier as well. Here's a more sophisticated example of a library from their site:

Flurl还以使HttpClient测试更加轻松而自豪。 这是他们站点中图书馆的更复杂的示例:

// Flurl will use 1 HttpClient instance per host
var person = await "https://api.com"
.AppendPathSegment("person")
.SetQueryParams(new { a = 1, b = 2 })
.WithOAuthBearerToken("my_oauth_token")
.PostJsonAsync(new
{
first_name = "Claire",
last_name = "Underwood"
})
.ReceiveJson<Person>();

This example is doing a post with an anonymous object that will automatically turn into JSON when it hits the wire. It also receives JSON as the response. Even the query params are created with a C# POCO (Plain Old CLR Object) and turned into name=value strings automatically.

这个例子正在做一个带有匿名对象的帖子,当它碰到网络时,它将自动变成JSON。 它还接收JSON作为响应。 甚至查询参数都是使用C#POCO(普通的旧CLR对象)创建的,并自动转换为name = value字符串。

Here's a test Flurl-style!

这是测试Flurl风格的!

// fake & record all http calls in the test subject
using (var httpTest = new HttpTest()) {
// arrange
httpTest.RespondWith(200, "OK");
// act
await sut.CreatePersonAsync();
// assert
httpTest.ShouldHaveCalled("https://api.com/*")
.WithVerb(HttpMethod.Post)
.WithContentType("application/json");
}

Flurl.Http includes a set of features to easily fake and record HTTP activity. You can make a whole series of assertions about your APIs:

Flurl.Http包含一组易于伪造和记录HTTP活动的功能。 您可以对API进行一系列断言:

httpTest.ShouldHaveCalled("http://some-api.com/*")
.WithVerb(HttpMethd.Post)
.WithContentType("application/json")
.WithRequestBody("{\"a\":*,\"b\":*}") // supports wildcards
.Times(1)

All in all, it's an impressive set of tools that I hope you explore and consider for your toolbox! There's a ton of great open source like this with .NET Core and I'm thrilled to do a small part to spread the word. You should to!

总而言之,这是一套令人印象深刻的工具,希望您能为您的工具箱探索和考虑! .NET Core有大量这样的很棒的开源,我很高兴能做一小部分来传播这个词。 你应该去!

翻译自: https://www.hanselman.com/blog/using-flurl-to-easily-build-urls-and-make-testable-httpclient-calls-in-net

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值