.NET Core 下调用WebAPI
前言
今天我们介绍多种客户端调用WebApi的方式,可以是原生写的,也可以借助.NET 框架下的其他HTTP库。我们一起来看看它们之间的一些异同吧~
RestSharp
首先要介绍的就是这款REST 客户端,我们先来一起看看它的简介:
RestSharp 是一个基于 .NET 框架的 REST 客户端,RestSharp 是一个轻量的,不依赖任何第三方的组件或者类库的 HTTP 组件,RestSharp具有以下的优点:
01、支持.NET4.5.2+ 和 .NET Standard 2.0 平台
02、使用NuGet轻松安装开发包
03、自动 XML 和 JSON 反序列化
04、通过 ISerializer 和 IDeserializer 自定义序列化和反序列化为
05、模糊匹配元素名称 (例如:XML或JSON中的product_id将匹配名为ProductId的C#属性)
06、自动检测返回内容的类型
07、指出 GET, POST, PUT, PATCH, HEAD, OPTIONS, DELETE 和 COPY 请求,支持其它非标准 HTTP 方法
08、OAuth 1.0、OAuth 2.0、Basic、NTLM 和基于参数的身份认证
09、通过 IAuthenticator 接口自定义身份验证方案
10、支持异步操作
官方示例:
var client = new RestClient("https://www.xcode.me"); // client.Authenticator = new HttpBasicAuthenticator(username, password); var request = new RestRequest("resource/{id}", Method.POST); request.AddParameter("name", "value"); // adds to POST or URL querystring based on Method request.AddUrlSegment("id", "123"); // replaces matching token in request.Resource // add parameters for all properties on an object request.AddObject(object); // or just whitelisted properties request.AddObject(object, "PersonId", "Name", ...); // easily add HTTP Headers request.AddHeader("header", "value"); // add files to upload (works with compatible verbs) request.AddFile("file", path); // execute the request IRestResponse response = client.Execute(request); var content = response.Content; // raw content as string // or automatically deserialize result // return content type is sniffed but can be explicitly set via RestClient.AddHandler(); IRestResponse<Person> response2 = client.Execute<Person>(request); var name = response2.Data.Name; // or download and save file to disk client.DownloadData(request).SaveAs(path); // easy async support await client.ExecuteAsync(request); // async with deserialization var asyncHandle = client.ExecuteAsync<Person>(request, response => { Console.WriteLine(response.Data.Name); }); // abort the request on demand asyncHandle.Abort();
使用案例:
Setp 1
引入RestSharp包
Setp 2
新建一个API请求执行者的接口IRestSharp:
/// <summary> /// API请求执行者接口 /// </summary> public interface IRestSharp { /// <summary> /// 同步执行方法 /// </summary> /// <param name="request"></param> /// <returns></returns> IRestResponse Execute(IRestRequest request); /// <summary> /// 同步执行方法 /// </summary> /// <typeparam name="T">返回值</typeparam> /// <param name="request">请求参数</param> /// <returns></returns> T Execute<T>(IRestRequest request) where T : new(); /// <summary> /// 异步执行方法 /// </summary> /// <param name="request">请求参数</param> /// <param name="callback"></param> /// <returns></returns> RestRequestAsyncHandle ExecuteAsync(IRestRequest request, Action<IRestResponse> callback); /// <summary> /// 异步执行方法 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="request"></param> /// <param name="callback"></param> /// <returns></returns> RestRequestAsyncHandle ExecuteAsync<T>(IRestRequest request, Action<IRestResponse<T>> callback) where T : new(); }
Setp 3
新建一个实现类RestSharpClient,实现上述接口
/// <summary> /// Rest接口执行者 /// </summary> public class RestSharpClient : IRestSharp { /// <summary> /// 请求客户端 /// </summary> private RestClient client; /// <summary> /// 接口基地址 格式:http://www.xxx.com/ /// </summary> private string BaseUrl { get; set; } /// <summary> /// 默认的时间参数格式 /// </summary> private string DefaultDateParameterFormat { get; set; } /// <summary> /// 默认验证器 /// </summary> private IAuthenticator DefaultAuthenticator { get; set; } /// <summary> /// 构造函数 /// </summary> /// <param name="baseUrl"></param> /// <param name="authenticator"></param> public RestSharpClient(string baseUrl, IAuthenticator authenticator = null) { BaseUrl = baseUrl; client = new RestClient(BaseUrl); DefaultAuthenticator = authenticator; //默认时间显示格式 DefaultDateParameterFormat = "yyyy-MM-dd HH:mm:ss"; //默认校验器 if (DefaultAuthenticator != null) { client.Authenticator = DefaultAuthenticator; } } /// <summary> /// 通用执行方法 /// </summary> /// <param name="request">请求参数</param> /// <remarks> /// 调用实例: /// var client = new RestSharpClient("http://localhost:82/"); /// var result = client.Execute(new RestRequest("api/values", Method.GET)); /// var content = result.Content;//返回的字符串数据 /// </remarks> /// <returns></returns> public IRestResponse Execute(IRestRequest request) { request.DateFormat = string.IsNullOrEmpty(request.DateFormat) ? DefaultDateParameterFormat : request.DateFormat; var response = client.Execute(request); return response; } /// <summary> /// 同步执行方法 /// </summary> /// <typeparam name="T">返回的泛型对象</typeparam> /// <param name="request">请求参数</param> /// <remarks> /// var client = new RestSharpClient("http://localhost:82/"); /// var result = client.Execute<List<string>>(new RestRequest("api/values", Method.GET)); /// </remarks> /// <returns></returns> public T Execute<T>(IRestRequest request) where T : new() { request.DateFormat = string.IsNullOrEmpty(request.DateFormat) ? DefaultDateParameterFormat : request.DateFormat; var response = client.Execute<T>(request); return response.Data; } /// <summary> /// 异步执行方法 /// </summary> /// <param name="request">请求参数</param> /// <param name="callback">回调函数</param> /// <remarks> /// 调用实例: /// var client = new RestSharpClient("http://localhost:62981/"); /// client.ExecuteAsync<List<string>>(new RestRequest("api/values", Method.GET), result => /// { /// var content = result.Content;//返回的字符串数据 /// }); /// </remarks> /// <returns></returns> public RestRequestAsyncHandle ExecuteAsync(IRestRequest request, Action<IRestResponse> callback) { request.DateFormat = string.IsNullOrEmpty(request.DateFormat) ? DefaultDateParameterFormat : request.DateFormat; return client.ExecuteAsync(request, callback); } /// <summary> /// 异步执行方法 /// </summary> /// <typeparam name="T">返回的泛型对象</typeparam> /// <param name="request">请求参数</param> /// <param name="callback">回调函数</param> /// <remarks> /// 调用实例: /// var client = new RestSharpClient("http://localhost:62981/"); /// client.ExecuteAsync<List<string>>(new RestRequest("api/values", Method.GET), result => /// { /// if (result.StatusCode != HttpStatusCode.OK) /// { /// return; /// } /// var data = result.Data;//返回数据 /// }); /// </remarks> /// <returns></returns> public RestRequestAsyncHandle ExecuteAsync<T>(IRestRequest request, Action<IRestResponse<T>> callback) where T : new() { request.DateFormat = string.IsNullOrEmpty(request.DateFormat) ? DefaultDateParameterFormat : request.DateFormat; return client.ExecuteAsync<T>(request, callback); } }
Setp 4
新建一个HttpHelper帮助类
public static class HttpHelper { public static T GetApi<T>(int regattaId, string apiName, string pragm = "") { var client = new RestSharpClient($"{SiteConfig.GetSite("Url")}"); var apiNameStr = string.Format($"{SiteConfig.GetSite($"{apiName}")}", regattaId); var request = client.Execute(string.IsNullOrEmpty(pragm) ? new RestRequest(apiNameStr, Method.GET) : new RestRequest($"{apiNameStr}/{pragm}", Method.GET)); if (request.StatusCode != HttpStatusCode.OK) { return (T)Convert.ChangeType(request.ErrorMessage, typeof(T)); } T result = (T)Convert.ChangeType(request.Content, typeof(T)); return result; } public static T PostApi<T>(int regattaId, int id, string url, string alias) {var client = new RestClient($"{url}"); IRestRequest queest = new RestRequest(); queest.Method = Method.POST; queest.AddHeader("Accept", "application/json"); queest.RequestFormat = DataFormat.Json; queest.AddBody(new { userid = id, Url = url, alias = alias, count = 1 }); // uses JsonSerializer var result = client.Execute(queest); if (result.StatusCode != HttpStatusCode.OK) { return (T)Convert.ChangeType(result.ErrorMessage, typeof(T)); } T request = (T)Convert.ChangeType(result.Content, typeof(T)); return request; } }
Setp 5
调用
//Get var notificationlist = HttpHelper.GetApi<string>(regattaId, "notification");//第二个参数是配置文件中的API地址 //Post Task.FromResult(HttpHelper.PostApi<string>(regattaId, id, url, alias))
在API端接收上述两个请求:
[Route("{regattaId}/[controller]")] [HttpGet] public async Task<IList<NotificationDto>> GetNotifications(int regattaId) { return await _notificationServices.GetNotifications(regattaId); } [Route("{regattaId}/pageviews")] [HttpPost] // GET: /<controller>/ public async Task PostInfo(int regattaId, [FromBody]PageViewsDto pageViewsDto) { await _pageviewServices.InsertPostInfo(regattaId, pageViewsDto); }
伤处PageViewDto的定义如下:
public class PageViewsDto { public int Id { get; set; } public string Url { get; set; } public string Alias { get; set; } public string UserId { get; set; } public int Count { get; set; } public PageViewsDto() { Id = 0; Count = 1; } }
更多详情可访问github:https://github.com/restsharp/RestSharp
携带实体参数发送Post请求
假设现在我们需要修改用户的一些基本信息,这些信息需要通过前端 发送到API端,那么该如何实现呢?
public async Task<int> UpdateUser(PersonModel model) { var url = $"{SiteConfig.GetSite("Url")}{SiteConfig.GetSite("updateUserByAccount")}"; var resultDetil = await HttpUtil.PostResultAsync<int>(model, url); return resultDetil; }
前端请求大概如上,地址URL和API名称都再配置文件中获取,下面我们看看PostResultAsync中是如何实现Post请求携带Post参数的吧
/// <summary> /// 发起POST请求,并获取请求返回值 /// </summary> /// <typeparam name="T">返回值类型</typeparam> /// <param name="obj">数据实体</param> /// <param name="url">接口地址</param> public static async Task<T> PostResultAsync<T>(object obj, string url) { //序列化设置 var setting = new JsonSerializerSettings(); //解决枚举类型序列化时,被转换成数字的问题 setting.Converters.Add(new StringEnumConverter()); setting.NullValueHandling = NullValueHandling.Ignore; var retdata = await HttpPostAsync(url, JsonConvert.SerializeObject(obj, setting)); return JsonConvert.DeserializeObject<T>(retdata); }
从上面我们可以看出,首先定义了一个泛型方法,其中接收一个参数类型是Object。另一个是url,在这个异步方法体重,我们去call了另一个请求方法
public static async Task<string> HttpPostAsync(string url, string postData, string certPath = "", string certPwd = "") { var request = CreateJsonRequest(url, HttpMethod.POST, postData, certPath, certPwd); return await GetResponseStringAsync(request); }
private static HttpWebRequest CreateJsonRequest(string url, HttpMethod method, string postData = "", string certpath = "", string certpwd = "") { var request = (HttpWebRequest)WebRequest.Create(url); request.Method = method.ToString(); request.ContentType = "application/json; charset=utf-8"; request.Accept = "*/*"; request.Timeout = 15000; request.AllowAutoRedirect = false; ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback((a, b, c, d) => true); if (!string.IsNullOrEmpty(certpath) && !string.IsNullOrEmpty(certpwd)) { X509Certificate2 cer = new X509Certificate2(certpath, certpwd, X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.MachineKeySet); request.ClientCertificates.Add(cer); } if (method == HttpMethod.POST) { using (var sw = new StreamWriter(request.GetRequestStream())) { sw.Write(postData); } } return request; } private static async Task<string> GetResponseStringAsync(HttpWebRequest request) { using (var response = await request.GetResponseAsync() as HttpWebResponse) { using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8)) { return reader.ReadToEnd();//获取响应 } } }
上述中的HttpMethod.post为枚举,此枚举中列举了http请求常用格式
public enum HttpMethod { GET, POST }
让我们看看上面提到的在Api端是如何接收的吧
[Route("[controller]/UpdateUserByAccount")] [HttpPost] public async Task<int> UpdateUserByAccount([FromBody]PersonDto model) { return await _authenticationService.UpdateUserByAccount(model); }
这样,我们就实现了Post请求API时携带实体参数
- 感谢你的阅读。如果你觉得这篇文章对你有帮助或者有启发,就请推荐一下吧~你的精神支持是博主强大的写作动力。欢迎转载!
- 博主的文章没有高度、深度和广度,只是凑字数。由于博主的水平不高(其实是个菜B),不足和错误之处在所难免,希望大家能够批评指出。
- 欢迎加入.NET 从入门到精通技术讨论群→523490820 期待你的加入
- 不舍得打乱,就永远学不会复原。被人嘲笑的梦想,才更有实现的价值。
- 我的博客:http://www.cnblogs.com/zhangxiaoyong/