前言

声名式服务调用,己经不算是一个新鲜的话题了,毕竟都出来好些年了。

下面谈谈,最近项目中用到一个这样的组件的简单实践。

目前部分项目用到的是Refit这个组件,都是配合HttpClientFactory来使用的。

关于HttpClientFactory的一些简单介绍,可以参见官方文档,也可以看看前面的两篇比较粗略的相关介绍。

也简单介绍一下背景,目前主要有两类的API接口:

第一类是注册到Eureka中的,可以通过服务发现的方式来请求的,这里的都是新的接口。

第二类是原始的接口,不能走服务发现,只能通过直连请求的方式来调用,这里的都是些老接口。

换句话就是说,要同时兼容这两类接口。

由于用HttpClientFactory集成服务发现十分简单,所以优先选了一个本身就带有HttpClientFactory的组件--Refit。

什么是Refit

Refit是一个自动类型安全的REST库,是RESTful架构的.NET客户端实现,

它基于Attribute,提供了把REST API返回的数据转化为(Plain Ordinary C# Object,简单C#对象),POCO to JSON,网络请求(POST,GET,PUT,DELETE等)封装,内部封装使用HttpClient,前者专注于接口的封装,后者专注于网络请求的高效,二者分工协作。

我们的应用程序通过 refit请求网络,实际上是使用 refit接口层封装请求参数、Header、Url 等信息,之后由 HttpClient完成后续的请求操作,在服务端返回数据之后,HttpClient将原始的结果交给 refit,后者根据用户的需求对结果进行解析的过程。

更多细节可以参考Refit的官网

创建一个可调用的API接口

直接上控制器的代码了〜〜

// GET: api/persons
[HttpGet]
public IEnumerable<Person> Get()
{
return new List<Person>
{
new Person{Id = 1 , Name = "catcher wong", CreateTime = DateTime.Now},
new Person{Id = 2 , Name = "james li", CreateTime = DateTime.Now.AddDays(-2)}
};
} // GET api/persons/5
[HttpGet("{id}")]
public Person Get(int id)
{
return new Person { Id = id, Name = "name" };
} // POST api/persons
[HttpPost]
public Person Post([FromBody]Person person)
{
if (person == null) return new Person(); return new Person { Id = person.Id, Name = person.Name };
} // PUT api/persons/5
[HttpPut]
public string Put([FromBody]int id)
{
return $"put {id}";
} // DELETE api/persons/5
[HttpDelete("{id}")]
public string Delete(int id)
{
return $"del {id}";
}

Refit的使用

先通过Nuget安装Refit的包。

然后就是定义我们的interface了

public interface IPersonsApi
{
[Get("/api/persons")]
Task<List<Person>> GetPersonsAsync(); [Get("/api/persons/{id}")]
Task<Person> GetPersonAsync([AliasAs("id")]int personId); [Post("/api/persons")]
Task<Person> AddPersonAsync([Body]Person person); [Put("/api/persons")]
Task<string> EditPersonAsync([Body]int id); [Delete("/api/persons/{id}")]
Task<string> DeletePersonAsync(int id);
}

来看看这个interface里面涉及到的部分内容。

  1. Get,Post等特性就表明了接口的请求方式,后面的值就是请求的相对路径。
  2. 相对路径中,可以使用占位符,来动态更新参数值。
  3. 如果方法名和请求参数名不一致,需要用AliasAs指明。
  4. 通过Body特性声明一个对象作为请求体发送到服务器
  5. 返回值定义是Task或者IObservable

然后是配合HttpClientFactory

再通过Nuget安装一下Refit.HttpClientFactory

如果PersonApi是注册到Euerka的,可以再添加Steeltoe的引用。

public void ConfigureServices(IServiceCollection services)
{
services.AddRefitClient<IPersonsApi>()
.ConfigureHttpClient(options =>
{
options.BaseAddress = new Uri(Configuration.GetValue<string>("personapi_url"));
//other settings of httpclient
})
//Steeltoe discovery
//.AddHttpMessageHandler<DiscoveryHttpMessageHandler>()
; services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}

前面在定义IPersonApi的时候,我们只指定了相对路径,而请求IP并没有指定,这里是放到ConfigureHttpClient里面去指定了。

同时根据不同环境,配置不同的appsettings.{env}.json,达到切换的效果。

同样的,如果想走服务发现,只需要放开注释的AddHttpMessageHandler,同时修改BaseeAddress为服务名的形式就可以了。

说了这么多,都还只是配置阶段,下面就来看看具体怎么用。

为了演示方便,就不在建一个Service层了,直接在控制器调用一下。

用法也很简单,直接在控制器注入一下就可以使用了。

[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
private readonly IPersonsApi _api;
public ValuesController(IPersonsApi api)
{
this._api = api;
} // GET api/values
[HttpGet]
public async Task<List<Person>> GetAsync()
{
return await _api.GetPersonsAsync();
} // GET api/values/5
[HttpGet("{id}")]
public async Task<Person> Get(int id)
{
return await _api.GetPersonAsync(id);
} // POST api/values
[HttpPost]
public async Task<Person> Post([FromBody] Person value)
{
return await _api.AddPersonAsync(value);
}
}

到这里,代码层面的东西已经处理完了。

下面来看看使用Refit效果(这里只看两个Get请求的):

都是能正常拿到我们期望的结果。

最后再看看输出的日志,确认一下。

首先是访问/api/values

确确实实是向我们前面的PersonApi发起了请求。

然后是访问/api/values/5555

可见我们上面的别名(AliasAs)是起了效果的,能拼成正确的请求地址。

至于其他类型的请求,这里就不演示了,让大家自己去尝试一下吧。

总结

Refit用起来还是比较简单的,运行了一段时间也还表现正常!

当然本文介绍的也只是一些基本的用法!它还具有不错的扩展性,可以让我们根据自身需求做一些定制化的东西。

本文的示例代码RefitClientApi

Refit在ASP.NET Core中的实践的更多相关文章

  1. Refit集成consul在asp.net core中的实践

    前言 github:https://github.com/alphayu/ Refit.WebApiClient.Feign等都是支持声名式的Restful服务调用的开源组件. 这个几个组件都综合研究 ...

  2. ASP.NET Core 中文文档 第二章 指南(4.6)Controller 方法与视图

    原文:Controller methods and views 作者:Rick Anderson 翻译:谢炀(Kiler) 校对:孟帅洋(书缘) .张仁建(第二年.夏) .许登洋(Seay) .姚阿勇 ...

  3. ASP.NET Core中的OWASP Top 10 十大风险-失效的访问控制与Session管理

    不定时更新翻译系列,此系列更新毫无时间规律,文笔菜翻译菜求各位看官老爷们轻喷,如觉得我翻译有问题请挪步原博客地址 本博文翻译自: https://dotnetcoretutorials.com/201 ...

  4. Asp.Net Core中DI的知识总结

    在asp.net core中DI的概念是由这几部分组成的: IServiceCollection,保存IServiceDescriptor实例的列表 IServiceProvider,只有一个方法Ge ...

  5. 【翻译】asp.net core中使用MediatR

    这篇文章来自:https://ardalis.com/using-mediatr-in-aspnet-core-apps 本文作为翻译,有一些单词翻译成中文可能会有一些误解(对于读者)或者错误(对于作 ...

  6. ASP.Net Core 中使用Zookeeper搭建分布式环境中的配置中心系列一:使用Zookeeper.Net组件演示基本的操作

    前言:马上要过年了,祝大家新年快乐!在过年回家前分享一篇关于Zookeeper的文章,我们都知道现在微服务盛行,大数据.分布式系统中经常会使用到Zookeeper,它是微服务.分布式系统中必不可少的分 ...

  7. ASP.NET Core 中 HttpContext 详解与使用 | Microsoft.AspNetCore.Http 详解

    笔者没有学 ASP.NET,直接学 ASP.NET Core ,学完 ASP.NET Core MVC 基础后,开始学习 ASP.NET Core 的运行原理.发现应用程序有一个非常主要的 “传导体” ...

  8. 【转】.NET(C#):浅谈程序集清单资源和RESX资源 关于单元测试的思考--Asp.Net Core单元测试最佳实践 封装自己的dapper lambda扩展-设计篇 编写自己的dapper lambda扩展-使用篇 正确理解CAP定理 Quartz.NET的使用(附源码) 整理自己的.net工具库 GC的前世与今生 Visual Studio Package 插件开发之自动生

    [转].NET(C#):浅谈程序集清单资源和RESX资源   目录 程序集清单资源 RESX资源文件 使用ResourceReader和ResourceSet解析二进制资源文件 使用ResourceM ...

  9. ASP.NET Core 中的 ServiceProvider

    前言 在 ASP.NET Core 中,微软提供了一套默认的依赖注入实现,该实现对应的包为:Microsoft.Extensions.DependencyInjection,我们可以通过查看其对应的开 ...

随机推荐

  1. CentOS,crontab的学习、使用、问题解决记录

    参考:http://blog.csdn.net/luanwpp/article/details/7490871 参考: http://mp.weixin.qq.com/s?src=11&tim ...

  2. # xrdp 在linux deploy 折腾记录

    xrdp 在linux deploy 折腾记录 1. xrdp connect fail vnc 不管用tiger or vnc4server都可以正常用,但xrdp无法连接 netstat -tnl ...

  3. Fio测试工具参数

    以随机读为例:fio -ioengine=libaio -group_reporting -direct=1 -name=testsda -numjobs=1 --time_based --runti ...

  4. c#发送短息验证码

    <add key="WebReference.Service.PostUrl" value="http://106.ihuyi.cn/webservice/sms1 ...

  5. 自己封装element-ui树组件的过滤

    前言:vue开发项目时用到了element-ui的树组件,但是发现一执行过滤事件,树就全部都展开了,为了解决这个问题,只能自己先过滤数剧,再赋值给树组件的data,就避免了一上来全部展开的尴尬. 一. ...

  6. [Lyft Level 5 Challenge 2018 - Elimination Round][Codeforces 1033D. Divisors]

    题目链接:1033D - Divisors 题目大意:给定\(n\)个数\(a_i\),每个数的约数个数为3到5个,求\(\prod_{i=1}^{n}a_i\)的约数个数.其中\(1 \leq n ...

  7. 如何在mysql客户端即mysql提示符下执行操作系统命令

    环境描述: mysql版本:5.5.57-log 操作系统版本:Red Hat Enterprise Linux Server release 6.6 (Santiago) 需求描述: 在mysql的 ...

  8. verilog中timescale

    1. `timescale `timescale是Verilog中的预编译指令,指定位于它后边的module的时间单位和时间精度,直到遇到新的`timescale指令或者`resetall指令.它的语 ...

  9. UML建模工具

    UML:Unified Modeling Language (UML)又称统一建模语言或标准建模语言,是始于1997年一个OMG标准,它是一个支持模型化和软件系统开发的图形化语言,为软件开发的所有阶段 ...

  10. 基于 TensorFlow 在手机端实现文档检测

    作者:冯牮 前言 本文不是神经网络或机器学习的入门教学,而是通过一个真实的产品案例,展示了在手机客户端上运行一个神经网络的关键技术点 在卷积神经网络适用的领域里,已经出现了一些很经典的图像分类网络,比 ...