本章节为了方便读者的理解,相关例子将使用HttpApiClient静态类来创建http接口的代理类,但在生产环境中,使用HttpApiFactory静态来创建http接口的代理类更合理,也是非常有必要的。
public interface IMyWebApi : IHttpApi
{
// GET http://www.mywebapi.com/webapi/user?account=laojiu
[HttpGet("http://www.mywebapi.com/webapi/user")]
ITask<HttpResponseMessage> GetUserByAccountAsync(string account);
}
var client = HttpApiClient.Create<IMyWebApi>();
var response = await client.GetUserByAccountAsync("laojiu");
[HttpHost("http://www.mywebapi.com/")]
public interface IMyWebApi : IHttpApi
{
// GET /webapi/user?account=laojiu
[HttpGet("webapi/user")]
ITask<HttpResponseMessage> GetUserByAccountAsync(string account);
}
如果接口IMyWebApi有多个方法且都指向同一服务器,可以将请求的域名抽出来放到HttpHost特性。
[HttpHost("http://www.mywebapi.com/")]
public interface IMyWebApi : IHttpApi
{
// GET /webapi/user?account=laojiu
[HttpGet("webapi/user")]
ITask<UserInfo> GetUserByAccountAsync(string account);
}
当方法的返回数据是UserInfo类型的json或xml文本,且响应的Content-Type为application/json或application/xml值时,方法的原有返回类型ITask(Of HttpResponseMessage)就可以声明为ITask(Of UserInfo)。
[HttpHost("http://www.mywebapi.com/")]
public interface IMyWebApi : IHttpApi
{
// GET /webapi/user?account=laojiu
[HttpGet("webapi/user")]
[JsonReturn] // 指明使用Json处理返回值为UserInfo类型
ITask<UserInfo> GetUserByAccountAsync(string account);
}
当方法的返回数据是UserInfo类型的json或xml文本,但响应的Content-Type可能不是期望的application/json或application/xml值时,就需要显式声明JsonReturn或XmlReturn特性。
无论是GET还是POST等哪种http请求方法,都遵循如下的URL格式:
{Scheme}://{UserName}:{Password}@{Host}:{Port}{Path}{Query}{Fragment}
例如:http://account:password@www.baidu.com/path1/?p1=abc#tag
public interface IMyWebApi : IHttpApi
{
// GET http://www.webapiclient.com/laojiu
[HttpGet("http://www.webapiclient.com/{account}"]
ITask<string> GetUserByAccountAsync(string account);
}
某些接口方法将路径的一个分段语意化,比如GET http://www.webapiclient.com/{account}
,这里不同的{account}代表不同账号下的个人信息,使用{参数名}声明路径,在请求前会自动从参数(或参数模型的同名属性)取值替换。
public interface IMyWebApi : IHttpApi
{
// GET {URL}
[HttpGet]
ITask<string> GetUserByAccountAsync([Url] string url);
// GET {URL}?account=laojiu
[HttpGet]
ITask<string> GetUserByAccountAsync([Url] string url, string account);
}
如果请求URL在运行时才确定,可以将请求URL作为一个参数,使用Url特性修饰这个参数并作为第一个参数。
// GET /webapi/user?account=laojiu&password=123456
[HttpGet("webapi/user")]
ITask<UserInfo> GetUserAsync(string account, string password);
public class LoginInfo
{
public string Account { get; set; }
public string Password { get; set; }
}
// GET /webapi/user?account=laojiu&password=123456
[HttpGet("webapi/user")]
ITask<UserInfo> GetUserAsync(LoginInfo loginInfo);
public class LoginInfo
{
public string Account { get; set; }
public string Password { get; set; }
}
// GET /webapi/user?account=laojiu&password=123456&role=admin
[HttpGet("webapi/user")]
ITask<UserInfo> GetUserAsync(LoginInfo loginInfo, string role);
// GET /webapi/user?account=laojiu&password=123456&role=admin
[HttpGet("webapi/user")]
ITask<UserInfo> GetUserAsync(
[PathQuery]LoginInfo loginInfo,
[PathQuery]string role);
对于没有任何特性修饰的每个参数,都默认被PathQuery修饰,表示做为请求路径或请求参数处理,PathQuery特性可以设置Encoding、IgnoreWhenNull和DateTimeFormat多个属性。
// POST webapi/user
// Body user的json文本
[HttpPost("webapi/user")]
ITask<UserInfo> AddUserWithJsonAsync([JsonContent] UserInfo user);
// PUT webapi/user
// Body user的xml文本
[HttpPut("/webapi/user")]
ITask<UserInfo> UpdateUserWithXmlAsync([XmlContent] UserInfo user);
// POST webapi/user
// Body Account=laojiu&Password=123456
[HttpPost("webapi/user")]
ITask<UserInfo> UpdateUserWithFormAsync(
[FormContent] UserInfo user);
// POST webapi/user
// Body Account=laojiu&Password=123456&fieldX=xxx
[HttpPost("webapi/user")]
ITask<UserInfo> UpdateUserWithFormAsync(
[FormContent] UserInfo user,
[FormField] string fieldX);
// POST webapi/user
[HttpPost("webapi/user")]
ITask<UserInfo> UpdateUserWithMulitpartAsync([MulitpartContent] UserInfo user);
// POST webapi/user
[HttpPost("/webapi/user")]
ITask<UserInfo> UpdateUserWithMulitpartAsync(
[MulitpartContent] UserInfo user,
[MulitpartText] string nickName,
MulitpartFile file);
// POST webapi/user
// Body Account=laojiu&Password=123456
[HttpPost("webapi/user")]
ITask<UserInfo> UpdateUserWithFormAsync(
FormUrlEncodedContent user);
// POST webapi/user
// Body Account=laojiu&Password=123456&age=18
[HttpPost("webapi/user")]
ITask<UserInfo> UpdateUserWithFormAsync(
FormUrlEncodedContent user,
[FormField] int age);
如果参数是类型是HttpContent类型的子类,如StringContent、ByteArrayContent、StreamContent、FormUrlEncodedContent等等,则可以直接做为参数,但是必须放在其它参数的前面:
json patch是为客户端能够局部更新服务端已存在的资源而设计的一种标准交互,在RFC6902里有详细的介绍json patch,通俗来讲有以下几个要点: 1. 使用HTTP PATCH请求方法; 2. 请求body为描述多个opration的数据json内容; 3. 请求的Content-Type为application/json-patch+json;
WebApiClient例子
public interface IMyWebApi : IHttpApi
{
[HttpPatch("http://www.mywebapi.com/webapi/user")]
Task<string> PatchAsync(JsonPatchDocument<UserInfo> doc);
}
var doc = new JsonPatchDocument<UserInfo>();
doc.Replace(item => item.Account, "laojiu");
doc.Replace(item => item.Email, "laojiu@qq.com");
var client = HttpApiClient.Create<IMyWebApi>();
await client.PatchAsync(doc);
Asp.net 服务端例子
[HttpPatch]
public UserInfo Patch([FromBody] JsonPatchDocument<UserInfo> doc)
{
// 此处user是从db查询获得
var user = new UserInfo
{
Account = "_Account",
Password = "_Password",
Email = "_Email"
};
doc.ApplyTo(user);
return user;
}
这些注解特性的命名空间在
WebApiClient.DataAnnotations
,用于影响参数的序列化行为。
public interface IMyWebApi : IHttpApi
{
// GET http://www.mywebapi.com/webapi/user?_name=laojiu
[HttpGet("http://www.mywebapi.com/webapi/user")]
ITask<string> GetUserByAccountAsync(
[AliasAs("_name")] string account);
}
public class UserInfo
{
public string Account { get; set; }
// 别名
[AliasAs("a_password")]
public string Password { get; set; }
// 时间格式,优先级最高
[DateTimeFormat("yyyy-MM-dd")]
[IgnoreWhenNull] // 值为null则忽略序列化
public DateTime? BirthDay { get; set; }
// 忽略序列化
[IgnoreSerialized]
public string Email { get; set; }
// 时间格式
[DateTimeFormat("yyyy-MM-dd HH:mm:ss")]
public DateTime CreateTime { get; set; }
}
这些验证特性都有相同的基类
ValidationAttribute
,命名空间为System.ComponentModel.DataAnnotations
,由netfx或corefx提供。
[HttpGet("webapi/user/GetById/{id}")]
ITask<HttpResponseMessage> GetByIdAsync(
[Required, StringLength(10)] string id);
id的参数要求必填且最大长度为10的字符串,否则抛出ValidationException的异常。
public class UserInfo
{
[Required]
[StringLength(10, MinimumLength = 1)]
public string Account { get; set; }
[Required]
[StringLength(10, MinimumLength = 6)]
public string Password { get; set; }
}
[HttpPut("webapi/user/UpdateWithJson")]
ITask<UserInfo> UpdateWithJsonAsync(
[JsonContent] UserInfo user);
当user参数不为null的情况,就会验证它的Account和Password两个属性,HttpApiConfig有个UseParameterPropertyValidate属性,设置为false就禁用验证参数的属性值。
对于上节的例子,如果我们希望user参数值也不能为null,可以如下声明方法:
[HttpPut("webapi/user/UpdateWithJson")]
ITask<UserInfo> UpdateWithJsonAsync(
[Required, JsonContent] UserInfo user);
有些特性比如Header,可以修饰于接口、方法和参数,使用不同的构造器和修饰于不同的地方产生的含义和结果是有点差别的:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。