-
Notifications
You must be signed in to change notification settings - Fork 445
WebApiClient基础
public interface IMyWebApi : IHttpApiClient
{
// GET http://www.mywebapi.com/webapi/user?account=laojiu
[HttpGet("http://www.mywebapi.com/webapi/user")]
ITask<string> GetUserByAccountAsync(string account);
}
var client = HttpApiClient.Create<IMyWebApi>();
var userStr = await client.GetUserByAccountAsync("laojiu");
client.Dispose();
如果你有多个接口,而且都指向同一服务器,可以将请求的域名抽出来放到HttpHost特性,接口的代码如下:
[HttpHost("http://www.mywebapi.com")]
public interface IMyWebApi : IHttpApiClient
{
// GET /webapi/user?account=laojiu
[HttpGet("/webapi/user")]
ITask<string> GetUserByAccountAsync(string account);
}
如果接口的返回内容是xml或json,你希望将它自动映射为强类型的模型,需要给接口打上对应的[XmlReturn]或[JsonResult]。实际上有一个[AutoReturn],它会根据回复头标识,自动选择不同的转换器转换为TResult类型的结果,默认的,每个接口都使用了[AutoReturn],除非给接口显性地给方法配置了[XmlReturn]或[JsonResult]。如果以上返回的userStr是UserInfo类型的xml或json文本,那么强类型的代码声明如下:
[HttpHost("http://www.mywebapi.com")]
public interface IMyWebApi : IHttpApiClient
{
// GET /webapi/user?account=laojiu
[HttpGet("/webapi/user")]
ITask<UserInfo> GetUserByAccountAsync(string account);
}
[HttpHost("http://www.mywebapi.com")]
[JsonReturn] // 指明使用Json处理返回值为UserInfo类型
public interface IMyWebApi : IHttpApiClient
{
// GET /webapi/user?account=laojiu
[HttpGet("/webapi/user")]
ITask<UserInfo> GetUserByAccountAsync(string account);
}
你可以将多个参数一一设计为接口的参数,类似于:
// GET /webapi/user?account=laojiu&password=123456
[HttpGet("/webapi/user")]
ITask<UserInfo> GetUserAsync(string account, string password);
也可以将所有参数合到一个简单的多属性模型对象:
public class MyParameters
{
public string Account { get; set; }
public string Password { get; set; }
}
// GET /webapi/user?account=laojiu&password=123456
[HttpGet("/webapi/user")]
ITask<UserInfo> GetUserAsync(MyParameters parameters);
在一些场景中,除了提交多属性模型对象之外,可能还需要一个简单类型的额外参数,你可以如下编写接口:
// GET /webapi/user?account=laojiu&password=123456&birthDay=2010-01-01 01:01:01
[HttpGet("/webapi/user")]
ITask<UserInfo> GetUserAsync(MyParameters parameters,DateTime birthDay);
上面这里,你可能会遇到一个问题,birthDay会简单的ToString()值做为参数值,如果你希望只需要日期而不包含时间,你可以给birthDay指定格式:
// GET /webapi/user?account=laojiu&password=123456&birthDay=2010-01-01
[HttpGet("/webapi/user")]
ITask<UserInfo> GetUserAsync(
MyParameters parameters,
[PathQuery("yyyy-MM-dd")] DateTime birthDay);
实际上,对于没有任何特性修饰的每个参数,都默认被[PathQuery]修饰,表示做为请求路径或请求参数处理,[PathQuery]的构造器重载方法可以指定日期时间格式。
// POST webapi/user
// Body Account=laojiu&Password=123456
[HttpPost("/webapi/user")]
ITask<UserInfo> UpdateUserWithFormAsync([FormContent] UserInfo user);
设计风格和Get请求是差不多的,你应该发现,接口参数被[FormContent]修饰了,[FormContent]的作用是将模型参数user以key1=value1&key2=value2的方式写入到请求内容中。如果你还需要提供一个额外的简单类型参数,需要使用[FormField]修饰这个参数,可以这样设计接口:
// 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);
需要了解的是,[MulitpartText]表示是一个文本项,而MulitpartFile表示一个文件项,MulitpartFile实现了IApiParameterable接口,它不需要任何特性的修饰,它能提供自我解释和处理。
对于json和xml,只能一次性提交一个参数,不支持额外参数之说
// POST webapi/user
// Body user的json文本
[HttpPost("/webapi/user")]
ITask<UserInfo> UpdateUserWithJsonAsync([JsonContent] UserInfo user);
// POST webapi/user
// Body user的xml文本
[HttpPost("/webapi/user")]
ITask<UserInfo> UpdateUserWithXmlAsync([XmlContent] UserInfo user);
如果你的UserInfo有DateTime类型的属性,你可以使用[JsonContent("时间格式")]来修饰接口参数,否则时间格式使用HttpApiConfig.FormatOptions.DateTimeFormate。
// 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(
[HttpContent] FormUrlEncodedContent user,
[FormField] int age);
默认的,所有System.Net.Http.HttpContent类型的参数,都会被[HttpContent]特性修饰,而且可以与表单字段特性等混合使用。值得说明的话,传统的System.Net.Http.HttpContent类型参数必须放到其它表单字段参数的前面。
以上的例子,请求的根路径都是硬编码,而在不少场景中是放在配置文件中的,可以在创建接口实例时创建配置项:
// 请求的域名,会覆盖[HttpHost]特性
var client = HttpApiClient.Create<IMyWebApi>("http://www.webapiclient.com");
var userStr = await client.GetUserByAccountAsync("laojiu");
有时,多个接口方法的全部URL都是运行时才确定的,这时,需要给每个接口做如下的调整,注意[Url]特性表示参数是请求的URL,要求必须放在第一个参数。:
public interface IMyWebApi : IHttpApiClient
{
// GET {URL}?account=laojiu
[HttpGet]
ITask<string> GetUserByAccountAsync([Url] string url, string account);
}
有时,有些接口会将某个参数做路径的一个分段,比如GET http://www.webapiclient.com/{account}
,这里的{account}是动态的,获取哪个账号的资料就填写哪个账号,可以如下设计接口
public interface IMyWebApi : IHttpApiClient
{
// GET http://www.webapiclient.com/laojiu
[HttpGet("http://www.webapiclient.com/{account}"]
ITask<string> GetUserByAccountAsync(string account);
}
有些服务端接口要求的键名与你的编程风格不一致,或者使用了特殊的键名为.net语言不允许的参数名,你可以使用[AliasAs("name")]来给参数或模型的属性别名。
public interface IMyWebApi : IHttpApiClient
{
// 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
{
[AliasAs("loginAccount")]
public string Account { get; set; }
public string Password { get; set; }
}
有些特性比如[Header],可以修饰于接口、方法和参数,使用不同的构造器和修饰于不同的地方产生的含义和结果是有点差别的:
- 修饰接口时,表示接口下的所有方法在请求前都会添加这个请求头;
- 修饰方法时,表示此方法在请求前添加这个请求头;
- 修饰参数时,表示参数的值将做为请求头的值,由调用者动态传入;
有些特性比如[AutoReturn]和[JsonReturn],可以修饰于接口和方法,但特性的AllowMultiple为false,如果在接口级生明方法级[AutoReturn],在方法级上声明[JsonReturn],此方法实际生效的是[JsonReturn];再比如[Timeout]特性,如果在接口级声明[Timeout(5000)]在方法级声明[Timeout(10000)],实际生效的是[Timeout(10000)],总结如下:
- AllowMultiple为false的同一个特性,方法级比接口级优先级高
- AllowMultiple为false的不同类型的[ReturnAttribute],方法级比接口级优先级高