前言
本篇幅会专门记录在工作中实际碰到的问题场景,和一些比较好的实现方法作为汇总,可以供各位借鉴和参考,当然 本人入行不深,能力有限,仅供各位借鉴和参考。欢迎补充
技巧一:引入其他项目类库文件
做项目大家都知道会有远程请求API的情况,现在假设做API的项目你能接触到并且Git下来。那么继续往下看。
将API项目中用到的Dto引入自己项目。这样方便我们将请求到的json字符串直接序列化成dto,然后再转成我们自己需要的ViewModel,具体怎么转呢,往下看:
技巧二:使用Extension
使用Extension,具体怎么用,我们来用一个实际例子说一下吧。比如,我们现在要请求一个所有俱乐部的api。首先我们定义一个ViewModel用于存放俱乐部信息,Model如下:
①定义ViewModel
public class ClubBase { /// <summary> /// 主键Id /// </summary> public long Id { get; set; } /// <summary> /// 俱乐部名称 /// </summary> public string Name { get; set; } /// <summary> /// 俱乐部描述 /// </summary> public string Description { get; set; } /// <summary> /// 创始人 /// </summary> public string Creator { get; set; } /// <summary> /// 创建年份 /// </summary> public int Year { get; set; } /// <summary> /// 其他信息 /// </summary> public string Contactor { get; set; } /// <summary> /// 手机号 /// </summary> public string Phone { get; set; } /// <summary> /// 地址 例如 中国/深圳 /// </summary> public string Address { get; set; } /// <summary> /// 日期 /// </summary> public DateTime CreationDate { get; set; } }
②编写接口
/// <summary> /// 所有接口信息 /// </summary> public interface IDataServices { /// <summary> /// 获取所有俱乐部 /// </summary> /// <returns></returns> Task<IList<ClubBase>> GetClubs(); }
③实现Server接口
/// <summary> /// 接口实现类 动态请求api获取相应数据 /// </summary> public class DataServices: IDataServices { private readonly IDataHttpServers _dataHttpServers; public DataServices(IDataHttpServers dataHttpServers) { _dataHttpServers = dataHttpServers; } public async Task<IList<ClubBase>> GetClubs() { var clubsModelList = await _dataHttpServers.GetClubs(); return clubsModelList; } }
④编写Http请求接口
public interface IDataHttpServers { /// <summary> /// 获取所有俱乐部 /// </summary> /// <returns></returns> Task<IList<ClubBase>> GetClubs(); }
⑤实现此接口
/// <summary> /// 返回俱乐部列表 /// </summary> /// <returns></returns> public async Task<IList<ClubBase>> GetClubs() { return await Task.Run(() => GetClubApi()); }
/// <summary> /// 获取所有俱乐部API /// </summary> /// <returns></returns> public List<ClubBase> GetClubApi() { var list = HttpHelper.GetApi<string>("getclub"); List<ClubBase> viewClubList = new List<ClubBase>(); try { List<ClubInfoDto> apiClubList = JsonConvert.DeserializeObject<List<ClubInfoDto>>(list); foreach (var item in apiClubList) { //调用拓展方法解耦dto于ViewModel的赋值操作 var club = item.TranslateToClubBaseViewModel(); viewClubList.Add(club); } } catch (Exception e) { //请求接口api异常,异常描述 list } return viewClubList; }
重头戏也就是此方法了,其中 可以将请求api单独抽离出来写成泛型方法,此处是这样抽离的:
/// <summary> /// HTTPclient 泛型抽象类 /// </summary> public static class HttpHelper { public static T GetApi<T>(string apiName, string pragm = "") { var client = new RestSharpClient($"{SiteConfig.GetSite("Url")}"); var request = client.Execute(string.IsNullOrEmpty(pragm) ? new RestRequest($"{SiteConfig.GetSite($"{apiName}")}", Method.GET) : new RestRequest($"{SiteConfig.GetSite($"{apiName}")}/{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; } }
这里我请求API是使用的RestSharp提供的请求方法。具体可以看这儿 RestSharp ,需要NuGet安装RestSharp
这里我稍微贴一下 大概常用的一些接口方法:
1)接口
/// <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(); }
2)实现
/// <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); } }
好了,我们接着上面说,大家可以看到,当我们通过请求api获取到数据之后得到的是下面这个Json字符串如下:
为什么我们需要引入api的dto而不是直接使用ViewModel来赋值我们需要的呢,这里有两个好处,第一个,我们可以快速完成json字符串到对象的转变,第二个,我们可以使用我们下面说的一个小技巧快速过滤出我们想组装的ViewModel即可。
注意下我们的这个方法TranslateToClubBaseViewModel ,是我们用于操作dto和ViewModel的主要方法
/// <summary> /// 此方法用于将Dto类型 数据 赋值到需要操作的ViewModel上 /// </summary> /// <param name="clubInfoDto">dto数据集</param> /// <returns></returns> public static ClubBase TranslateToClubBaseViewModel(this ClubInfoDto clubInfoDto) { ClubBase club = new ClubBase() { #region 实体按需赋值 Id = clubInfoDto.Id, Address = clubInfoDto.Address, Contactor = clubInfoDto.Contactor, Creator = clubInfoDto.Creator, Description = clubInfoDto.Description, Name = clubInfoDto.Name, Phone = clubInfoDto.Phone, Year = clubInfoDto.Year #endregion }; return club; }
这样操作的好处,我们就不用维护具体的业务层,专注于ViewModel上面。达到了解耦效果。
RestSharp发送Post请求
假设我们项目中需要自定义支持所有页面的浏览记录,需要记录再数据库每个页面的详细浏览情况,而不是采用第三方的统计,我们可以这样实现。(假设此处采用的是前后端分离,API的方式读写数据库)
①我们在IDataServices接口类中新建一个接口SendBrowseRecord
/// <summary> /// 发送浏览记录 /// </summary> /// <param name="id">用户id,若无则为0</param> /// <param name="url">请求页面</param> /// <param name="alias">别名</param> /// <returns></returns> Task<string> SendBrowseRecord(int id, string url, string alias);
②在DataServices中实现此接口
public async Task<string> SendBrowseRecord(int id, string url, string alias) { return await _dataHttpServers.SendBrowseRecord(id, url, alias); }
③此处的_dataHttpServers是单独封装起来的访问API的接口,内容和IDataServices一样,但需要注意 在DataServices构造方法中需要注入进来
private readonly IDataHttpServers _dataHttpServers; public DataServices(IDataHttpServers dataHttpServers) { _dataHttpServers = dataHttpServers; }
④实现Http的访问SendBrowseRecord方法
public string SendBrowseRecordApi(int id, string url, string alias) { try { return HttpHelper.PostApi<string>(id, url, alias); } catch (Exception e) { //请求接口api异常,异常描述 list _logger.LogError(e.Message); } return ""; } public async Task<string> SendBrowseRecord(int id, string url, string alias) { return await Task.Run(() => SendBrowseRecordApi(id, url, alias)); }
因为每个页面都需要去调用这个PostApi,所以此处我将PostApi<T>抽象出一个泛型方法进来,这样不管哪个页面都是调用这个。抽象出来的Post方法如下:
public static T PostApi<T>(int id, string url, string alias) { var client = new RestClient($"{SiteConfig.GetSite("Url")}api/pageviews"); 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 }); // 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; }
此处的Body是发送一个Json对象。这样,我们就把RestSharp的Post调用实现了。这样就ok啦
未完待续。。。
- 感谢你的阅读。如果你觉得这篇文章对你有帮助或者有启发,就请推荐一下吧~你的精神支持是博主强大的写作动力。欢迎转载!
- 博主的文章没有高度、深度和广度,只是凑字数。由于博主的水平不高(其实是个菜B),不足和错误之处在所难免,希望大家能够批评指出。
- 欢迎加入.NET 从入门到精通技术讨论群→523490820 期待你的加入
- 不舍得打乱,就永远学不会复原。被人嘲笑的梦想,才更有实现的价值。
- 我的博客:http://www.cnblogs.com/zhangxiaoyong/