HTTP请求组件 BrokerClient
BrokerClient主要用于支持各类Http请求
如何引入
功能包含在Aegis.Net.Broker
的Nuget包中,当前最新版本是1.0.7-preview1
。
BrokerClient
不需要使用任何配置
快速使用
使用BrokerClient前,首先需要定义调用Http服务的契约接口
比如这个例子,定义了HIS下调用医生站的契约接口
public interface IDoctorContract
{
[Post("/api/his-api/receiveHisUpdate")]
public Task<BaseDto<string>> ReceiveHisUpdateAsync([Body] QuerWardBedTotalRequest request);
[Post("/api/emr/get-patient-emr-pdf")]
public Task<BaseDto<List<GetPatientEmrPdfDto>>> GetPatientEmrPdfAsync([Body] GetPatientEmrPdfRequest request);
}
定义好接口好,在具体需要调用的类中直接使用BrokerClient.Get
就可以直接获取对应接口,在调用的时候直接使用契约接口调用方法即可。
public class OpDoctorService : IBusinessService
{
IDoctorContract _doctorContract;
public OpDoctorService(ILogger<OpDoctorService> _logger, IApiLogsService apiLogsService)
{
_doctorContract = BrokerClient.Get<IDoctorContract>(ConfigManager.Get("OpDoctorURL"));
}
public async Task CallUpdate(QuerWardBedTotalRequest request)
{
var result = await _doctorContract.ReceiveHisUpdateAsync(request);
...
}
}
请求相关
在定义具体契约接口时,可以使用各种Attribute来定义该接口的HTTP相关地址和方法信息。
路径
https://api.example.com/api/v1/users/getuser
,这个路径可以拆分为三部分
- Base Address 基础地址,常用于域名,IP地址等。一般使用配置读取,在这里是
https://api.example.com
- Base Path 基础路径,用于相对固定路由路径。这里是
api/v1/users
- Method Path 方法路径,标注具体方法。这里是
getuser
Base Address 基础地址
设置接口的基础地址有两种方案
- 在接口最上方使用
[BaseAddress(...)]
,不推荐该方案,一般基础地址都是从配置或数据中读取的 - 使用
BrokerClient.Get<T>(...)
或new BrokerClient(...)
,推荐使用这种方式,就像快速使用的例子,BrokerClient.Get<IDoctorContract>(ConfigManager.Get("OpDoctorURL"))
一样。
Base Path 基础路径
可以设置在接口上标注某个领域或者固定的基础路径,如下面的例子
[BasePath("api/v1/users")]
public interface IUserContract
Method Path 方法路径
用于设置具体的方法路径
[BasePath("api/v1/users")]
public interface IUserContract
{
[Post("getuser")]
public Task<List<User>> GetUsers([Body]UserRequest request);
}
可以在接口上直接定义该接口的请求,支持各类HTTP方法,比如 [Get("path")]
、 [Post("path")]
等。
返回类型
目前契约接口只支持异步调用,所以所有的返回类型都带有Task
返回的数据类型,一共有以下几种类型:
Task
无返回值结果Task<T>
指定泛型返回值Task<string>
返回string类型的结果消息Task<HttpResponseMessage>
返回HttpResponseMessage,具体参考微软文档Task<Response<T>>
返回包含返回HttpResponseMessage和指定泛型返回值的结果Task<Stream>
返回包含流的结果,主要用于下载文件
指定泛型返回值的结果会默认使用Json序列化器返回。
[BasePath("api/v1/users")]
public interface IUserContract
{
//添加用户,不需要验证是否成功
[Post("adduser")]
public Task AddUser([Body]AddUserRequest request); //无返回值
//获取用户列表
[Post("getuser")]
public Task<List<User>> GetUsers([Body]UserRequest request); //指定泛型返回值
//获取用户说明的XML对象,使用字符串查询后续用XML序列器序列化
[Get("getuserdescription")]
public Task<string> GetUserDescription([Query]UserRequest request);
//更新用户信息,因为调了第三方接口可能会失败,所以获取HttpResponseMessage的原始内容来判断是否异常
[Post("changeuserstate")]
public Task<HttpResponseMessage> ChangeUserState([Body]UserRequest request);
//更新用户,可以用结果直接GetContent()来获取泛型结果,也可以用Response里的message来验证是否异常
[Post("updateuser")]
public Task<Response<User>> UpdateUser([Body]UserRequest request);
//下载文件
[Post("download")]
public Task<Stream> Download([Body]UserFilterRequest request);
}
Header
在日常请求中,经常需要带各种类型的Header,无论是固定的header,还是用于验证的header,Broker为header设置提供了较为便利的方式。
固定Header设置
定义在接口上
[Header("X-Source", "His")]
[Header("Cache-Control", "no-cache")]
public interface IUserContract
{
[Get("users")]
Task<List<User>> GetUsersAsync();
}
定义在方法上
[Header("Cache-Control", "no-cache")]
public interface IUserContract
{
[Header("X-Source", "His")]
[Get("users")]
Task<List<User>> GetUsersAsync();
}
可变Header设置
一般用于传Authorization
和Token
之类的可变Header头
定义在接口属性上,所有该接口下的方法请求出去时都会将该属性带在header上。
public interface IUserContract
{
[Header("Authorization")]
string Authorization { get; set; }
[Get("users")]
Task<List<User>> GetUsersAsync();
}
定义在方法参数上,在调用该方法时传入具体数据
public interface IUserContract
{
[Get("users")]
Task<List<User>> GetUsersAsync([Header("Authorization")] string authorization);
}
Header优先级
当接口Attribute、属性和方法参数上都包含同名Header时,并都设置了值。这时候的Header优先级是 方法参数 > 接口属性 > 接口Attribute,最终会使用方法参数的值请求出去。
[Header("Authorization","1")]
public interface IUserContract
{
[Header("Authorization")]
string Authorization { get; set; }
[Get("users")]
Task<List<User>> GetUsersAsync([Header("Authorization")] string authorization);
}
方法参数设置
支持所有类型的参数设置,参照下列代码:
public interface IUserContract
{
//GetUser?userId=xx&age=18
[Get("user")]
Task<List<User>> GetUserAsync([Query]string userId,[Query]string age);
//GetUsers,参数带在raw body中的json
[Post("getusers")]
Task<List<User>> GetUsers([Body]UserRequest request);
//添加用户的表单式提交,(也就是类型为application/x-www-form-urlencoded的请求)
[Post("adduser")]
Task<List<User>> AddUser([Body(BodySerializationMethod.UrlEncoded)]Dictionary<string,object> request);
//Url重写类型的请求,把参数定义在Path中
[Get("users/{userId}")]
Task<User> GetUserAsync([Path] string userId);
//上传文件,使用流作为Body即可
[Header("Content-Disposition", "form-data; filename=\"somefile.txt\"")] //这里填文件名
[Header("Content-Type", "text/plain")] //定义具体的媒体类型
[Post("upload")]
Task UploadFile([Body] Stream file);
}
需要注意的是
BodySerializationMethod.UrlEncoded
的表单式提交只支持使用IDictionary
或Dictionary
提交数据。