一次开放接口从需求分析到发布sdk线上包

简介: 新年开场篇,欢迎来点赞;本篇和大家分享的是使用webapi做得接口服务验证框架,需求来源是我打算把上篇提到的图片验证码做成一种服务提供给大家,尽管我在上篇已经把代码打包开源了,但是如果有一种快速对接成功的服务,我想很多人也非常想使用吧,目前这服务已经上线并在nuget上发布有sdk客户端包(nuget包地址:Install-Package ShenNiuApi.

新年开场篇,欢迎来点赞;本篇和大家分享的是使用webapi做得接口服务验证框架,需求来源是我打算把上篇提到的图片验证码做成一种服务提供给大家,尽管我在上篇已经把代码打包开源了,但是如果有一种快速对接成功的服务,我想很多人也非常想使用吧,目前这服务已经上线并在nuget上发布有sdk客户端包(nuget包地址:Install-Package ShenNiuApi.SDK),值得庆幸的是仅上线一天就有46次的下载量(挺高兴的),兴许有感兴趣的朋友可以去nuget官网地址查看:神牛步行3的Nuget包;下面要分享的是在发布服务时候涉及到的验证调用方的架构,希望大家能够喜欢,也希望各位多多"扫码支持"和"推荐"谢谢(对了最近做了一个服装店地址:神牛衣柜3,希望需要买衣服鞋子的朋友多多捧场);

 

» 验证架构的需求分析 和 表结构的设计

» 使用webapi的ActionFilterAttribute做账号的统一验证

» ShenNiuApi.SDK客户端代码的分享

» 使用NuGet Package Explorer工具生成ShenNiuApi.SDK的nuget包并发布到nuget网站上

 

下面一步一个脚印的来分享:

» 验证架构的需求分析 和 表结构的设计

. 验证架构的需求分析

首先,对于一个接口服务来说通常会有一定的账号限制,必须要调用方使用符合规定并正确的账号传递给接口方才能调用成功接口,这里我们就以互联网行业一般接口验证的来制定我们的需求:

1. 接口验证需要:账号,密码,ip组,Token;通常密码需要加密,市面上加密方式很多如Md5,3des等加密方式;ip组顾名思义就是用来验证调用方请求的ip是否符合接口方新开账号时候绑定的指定ip,对于现今互联网行业来说分布式调用不是什么新鲜事了,所以这里需要的是ip组;Token一般都是由接口方制定的防篡改参数的保护措施,对于请求和接受双方需要有同样的Token值才能进行接口响应,通常需要有一个秘钥来促成加密;

2. 除了账号验证外有些需要接口需要按照调用次数来收取费用,因此我们这里有了次数限制的需求,但通常作为不同业务接口来说成本可能会高,尽管是同一个提供商提供的接口很有可能精细到每个接口的调用次数限制,所以我们这里设计就按照这种方式来的,真实业务具体看需求而定;

3. 通常我们对方开放接口时,会直接提供sdk客户端,方便调用方直接引用后直接可以调用方法不用再去管具体是什么请求协议啊或者调用接口方法不对等问题,这种提供sdk的方式直接只需要账号,密码,秘钥等就直接可以使用了,方便快捷而且在一定程度上避免了接口地址的暴露,可谓是好处多多;不好的第三就如同手机客户端,只要服务端更新了一些必要性的参数属性,那每次都需要调用方更新sdk包,不过这都不是事儿;

. 表结构的设计

有了上面的简要分析,咋们来看下数据库的表结构,这里主要用数据库来存储对应开通的接口账号,密码等信息和调用接口对应的次数:

表:MoApiUser(账号表) MoApiManager(接口方法表) MoApiRelation(账号与方法表关系表,其中包含有调用次数) MoLog(日志表)

表数据:

 

» 使用ActionFilterAttribute做账号的统一验证

有了上面需求和表的设计,下面我们来看下怎么使用Action的过滤器来统一做验证,在这之前我们需要了解下:为什么不弄一个父级的ApiController然后在里面做验证在来继承呢,而用Action过滤器来做呢,其实这两种方式都行,不过后者可以对那些不需要接口账号的接口做开放,容易控制;好了咋们一起看下Action过滤器里面着么做验证的,首先创建类 UserValidateAttribute 并继承 ActionFilterAttribute ,然后在给她一个属性ApiKeyId,这个属性用来传递调用方调用的接口编号(也就是对应接口的Id,这里对应数据库表MoApiManager中的ApiKeyId),这样做的目的是使用编号来方便数据库中做调用某个接口的统计,针对我们上面需求分析说的次数限制到某个接口上,而不是限制在账号上面(当然前者和必须和账号关联才行),因此我们定义一个这样的枚举方便对应接口中的数字:

 1 /// <summary>
 2         /// 接口与数据库关联编号
 3         /// </summary>
 4         public enum ApiKeyId
 5         {
 6 
 7             文字验证码 = 1,
 8             图片验证码 = 2
 9 
10         }

然后在过滤器中重新  public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext) ,在OnActionExecuting中做非空验证,账号密码是否匹配,Token的验证,ip组的匹配,次数的对比,因此有了如下整体的自定义过滤器的代码:

  1  public class UserValidateAttribute : ActionFilterAttribute
  2     {
  3 
  4         /// <summary>
  5         /// 数据库与程序关联标号 
  6         /// </summary>
  7         public MoEnumHelper.ApiKeyId ApiKeyId { get; set; }
  8 
  9         public UserValidateAttribute(MoEnumHelper.ApiKeyId apiKeyId)
 10         {
 11             this.ApiKeyId = apiKeyId;
 12         }
 13 
 14         public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
 15         {
 16 
 17             var response = new MoShenNiuBaseResponse();
 18             var sbLog = new StringBuilder(string.Empty);
 19             try
 20             {
 21 
 22                 if (this.ApiKeyId <= 0) { response.Msg = "接口暂未开通,请联系管理员"; return; }
 23                 sbLog.AppendFormat("当前服务:{0};", this.ApiKeyId);
 24 
 25                 var request = actionContext.Request;
 26 
 27                 #region 验证
 28 
 29                 #region 非空验证  
 30                 if (actionContext.ActionArguments.Count <= 0) { response.Msg = "请求格式不正确,请检查"; return; }
 31                 var moRequest = actionContext.ActionArguments["request"] as MoShenNiuBaseRequest;
 32 
 33                 dynamic httpContext = actionContext.Request.Properties["MS_HttpContext"];
 34                 var userIp = httpContext.Request.UserHostAddress;
 35                 sbLog.AppendFormat("UserName:{0};Ip:{1};Token:{2};UserPwd:{3};", moRequest.UserName, userIp, moRequest.Token, moRequest.UserPwd.ToUpper());
 36                 if (string.IsNullOrWhiteSpace(moRequest.UserName) || string.IsNullOrWhiteSpace(moRequest.UserPwd))
 37                 {
 38                     response.Msg = "接口账号或密码不能为空";
 39                     return;
 40                 }
 41                 else if (string.IsNullOrWhiteSpace(moRequest.Token))
 42                 {
 43                     response.Msg = "Token不能为空";
 44                     return;
 45                 }
 46                 #endregion
 47 
 48                 using (StageEntities db = new StageEntities())
 49                 {
 50 
 51                     #region 验证账号是否存在
 52 
 53                     var userInfo = db.MoApiUsers.Where(b => b.UserName.ToUpper() == moRequest.UserName.ToUpper() && b.UserPwd.ToUpper() == moRequest.UserPwd.ToUpper()).SingleOrDefault();
 54                     if (userInfo == null)
 55                     {
 56                         response.Msg = "接口账号或密码错误";
 57                         return;
 58                     }
 59                     #endregion
 60 
 61                     #region  获取对应账号秘钥,验证token
 62 
 63                     var newToken = Md5Extend.GetMd5Hash(string.Format("{0}_{1}_{2}",
 64                                                  moRequest.UserName.ToUpper(),
 65                                                  userInfo.TokenKey.ToUpper(),
 66                                                  moRequest.UserPwd.ToUpper()));
 67 
 68                     sbLog.AppendFormat("服务器TokenKey:{0};Token:{1};", userInfo.TokenKey.ToUpper(), newToken);
 69 
 70                     if (!moRequest.Token.Equals(newToken, StringComparison.OrdinalIgnoreCase))
 71                     {
 72                         response.Msg = "Token验证失败";
 73                         return;
 74                     }
 75                     #endregion
 76 
 77                     #region 账号可用性
 78                     if (userInfo.Status != (int)MoEnumHelper.EmStatus.启用)
 79                     {
 80                         response.Msg = "接口账号暂被停用";
 81                         return;
 82                     }
 83                     else if (!string.IsNullOrWhiteSpace(userInfo.Ips))
 84                     {
 85                         if (!userInfo.Ips.Contains(userIp))
 86                         {
 87                             response.Msg = "接口ip无效";
 88                             return;
 89                         }
 90                     }
 91 
 92                     var realationInfo = userInfo.MoApiRelations.Where(b => b.MoApiManager.ApiKeyId == (int)ApiKeyId && b.MoApiManager.Status == (int)MoEnumHelper.EmStatus.启用).SingleOrDefault();
 93                     if (realationInfo == null)
 94                     {
 95                         response.Msg = "接口暂未启用,请稍后重试";
 96                         return;
 97                     }
 98                     else if (realationInfo.MaxNum <= realationInfo.NowNum)
 99                     {
100                         response.Msg = "接口调用次数已满,请联系管理员";
101                         return;
102                     }
103                     #endregion
104 
105                     //通过验证
106                     response.Status = (int)MoEnumHelper.EmStatus.启用;
107 
108                     #region 用户通过验证就增加次数
109 
110                     realationInfo.NowNum++;
111                     var result = db.SaveChanges();
112                     sbLog.AppendFormat("最大次数:{0};当前次数:{1};增加次数:{2};", realationInfo.MaxNum, realationInfo.NowNum, result);
113                     #endregion
114                 }
115 
116                 #endregion
117 
118 
119             }
120             catch (Exception ex)
121             {
122                 response.Msg = "500接口处理请求异常,请稍后重试";
123                 sbLog.AppendFormat("异常信息:{0};", ex.Message);
124             }
125             finally
126             {
127 
128                 sbLog.AppendFormat("返回Status:{0};Msg:{1};", response.Status, response.Msg);
129                 //记录日志
130                 StageClass._WrigLog(sbLog.ToString());
131 
132                 //验证失败返回
133                 if (response.Status != (int)MoEnumHelper.EmStatus.启用 || !string.IsNullOrWhiteSpace(response.Msg))
134                 {
135                     actionContext.Response = new HttpResponseMessage()
136                     {
137 
138                         StatusCode = System.Net.HttpStatusCode.OK,
139                         Content = new StringContent(JsonConvert.SerializeObject(response))
140                     };
141                 }
142             }
143         }
144     }

代码中已经有了验证步骤模块的说明各位可以读一下,需要注意的地方是在Action过滤器中获取post传递给接口的对象参数方式是:  var moRequest = actionContext.ActionArguments["request"] as MoShenNiuBaseRequest; 这样就能直接获取客户端传递过来的对象数据了;然后咋们再Controller代码中使用定义的过滤器,主要是在Action方法上方增加 [UserValidate(MoEnumHelper.ApiKeyId.文字验证码)]标记,通过MoEnumHelper.ApiKeyId.文字验证码来传递调用方调用的接口,这里我封装的接口是:文字验证码图片验证码的接口,至于生成验证码的代码已经在上一篇MVC伪一个12306图片验证码已经开源出来了这里不多说,直接上整个webapi接口的Controller代码:

 1 /// <summary>
 2     /// ShenNiuApi - 接口
 3     /// </summary>
 4     [RoutePrefix("shenniuapi")]
 5     public class ShenNiuController : ApiController
 6     {
 7 
 8         /// <summary>
 9         /// 文字验证码
10         /// </summary>
11         /// <param name="request">验证码Request请求</param>
12         /// <returns>文字验证码图片流</returns>
13         [Route("WenZiValidateCode")]
14         [HttpPost]
15         [UserValidate(MoEnumHelper.ApiKeyId.文字验证码)]
16         public MoValidateCodeResponse GetWenZiValidateCode(MoValidateCodeRequest request)
17         {
18 
19             var response = new MoValidateCodeResponse();
20 
21             try
22             {
23                 //返回的验证码文字
24                 var code = string.Empty;
25                 //图片流
26                 response.CodeStream = ValidateCode.GetValidateCodeStream(ref code);
27                 if (string.IsNullOrWhiteSpace(code) || response.CodeStream.Length <= 0) { response.Msg = "获取验证码失败,请稍后重试"; return response; }
28 
29                 response.Code = code;
30                 response.Status = (int)MoEnumHelper.EmApiStatus.成功;
31             }
32             catch (Exception ex)
33             {
34                 response.Msg = "获取验证码失败,请稍后重试";
35             }
36 
37             return response;
38         }
39 
40         /// <summary>
41         /// 图片验证码
42         /// </summary>
43         /// <param name="request">验证码Request请求</param>
44         /// <returns>图片验证码图片流及待验证图片坐标</returns>
45         [Route("TuPianValidateCode")]
46         [HttpPost]
47         [UserValidate(MoEnumHelper.ApiKeyId.图片验证码)]
48         public MoValidateCodeResponse GetTuPianValidateCode(MoValidateCodeRequest request)
49         {
50 
51             var response = new MoValidateCodeResponse();
52 
53             try
54             {
55                 //获取图片类型
56                 var validateCode = ValidateCode.GetInitImgCode();
57                 if (validateCode == null || string.IsNullOrWhiteSpace(validateCode.IndexType)) { response.Msg = "获取验证码失败,请稍后重试"; return response; }
58 
59                 //生成图片
60                 var imgCode = new List<Stage.Com.Extend.MoImgCode>();
61                 response.CodeStream = ValidateCode.CreateImgValidateStream(validateCode.IndexType, ref imgCode, strLen: 8);
62                 if (imgCode.Count <= 0 || response.CodeStream.Length <= 0 || imgCode.Count <= 0) { response.Msg = "获取验证码失败,请稍后重试"; return response; }
63 
64                 //得到待匹配验证码坐标
65                 foreach (var item in imgCode.Where(b=>b.IsChoice))
66                 {
67                     response.ImgCode.Add(new Stage.Model.MoImgCode()
68                     {
69                         ImgUrl = item.ImgUrl,
70                         Index = item.Index,
71                         IndexType = item.IndexType,
72                         IsChoice = item.IsChoice,
73                         Point_A = item.Point_A,
74                         Point_B = item.Point_B
75                     });
76                 }
77                 response.Code = validateCode.IndexType;
78                 response.Status = (int)MoEnumHelper.EmApiStatus.成功;
79             }
80             catch (Exception ex)
81             {
82                 response.Msg = "获取验证码失败,请稍后重试";
83             }
84 
85             return response;
86         }
87 
88     }

感觉是不是挺简单的,其实关键点在于过滤器中验证的步骤,要明白作为一个接口需要验证哪些东西这样才能保障接口的安全;

 

» ShenNiuApi.SDK客户端代码的分享

我们需求分析的时候也说了通过SDK的nuget方式提供给调用方使用,方便快捷,有一定的安全性;下面我们先来看下客户端所使用到的实体类:

  1 namespace ShenNiuApi.SDK
  2 {
  3 
  4     /// <summary>
  5     /// 神牛步行3枚举
  6     /// </summary>
  7     public class MoEnumHelper
  8     {
  9 
 10         public enum EmStatus
 11         {
 12             禁用 = 0,
 13             启用 = 1
 14         }
 15     }
 16 
 17     /// <summary>
 18     /// 接口验证基类
 19     /// </summary>
 20     public class MoShenNiuBaseRequest
 21     {
 22         /// <summary>
 23         /// 账号
 24         /// </summary>
 25         public string UserName { get; set; }
 26 
 27         /// <summary>
 28         /// 密码
 29         /// </summary>
 30         public string UserPwd { get; set; }
 31 
 32         /// <summary>
 33         /// 加密Token(方式:Md5(账号_秘钥_密码))
 34         /// </summary>
 35         public string Token { get; set; }
 36 
 37     }
 38 
 39     /// <summary>
 40     /// 神牛接口返回基类
 41     /// </summary>
 42     public class MoShenNiuBaseResponse
 43     {
 44         /// <summary>
 45         /// 返回状态: 0:失败 1:成功
 46         /// </summary>
 47         public int Status { get; set; }
 48 
 49         /// <summary>
 50         /// 错误信息
 51         /// </summary>
 52         public string Msg { get; set; }
 53     }
 54 
 55     /// <summary>
 56     /// 验证码请求类
 57     /// </summary>
 58     public class MoValidateCodeRequest : MoShenNiuBaseRequest { }
 59 
 60     /// <summary>
 61     /// 验证码返回类
 62     /// </summary>
 63     public class MoValidateCodeResponse : MoShenNiuBaseResponse
 64     {
 65 
 66         public MoValidateCodeResponse()
 67         {
 68             this.ImgCode = new List<MoImgCode>();
 69         }
 70 
 71         /// <summary>
 72         /// 验证码类型
 73         /// </summary>
 74         public string Code { get; set; }
 75 
 76         /// <summary>
 77         /// 验证码图片流
 78         /// </summary>
 79         public byte[] CodeStream { get; set; }
 80 
 81         /// <summary>
 82         /// 图片验证坐标
 83         /// </summary>
 84         public List<MoImgCode> ImgCode;
 85     }
 86 
 87     /// <summary>
 88     /// 图片验证码坐标
 89     /// </summary>
 90     public class MoImgCode
 91     {
 92         public string Index { get; set; }
 93 
 94         public string IndexType { get; set; }
 95 
 96         public string ImgUrl { get; set; }
 97 
 98         public Point Point_A { get; set; }
 99 
100         public Point Point_B { get; set; }
101 
102         public bool IsChoice { get; set; }
103     }
104 
105 }

其中包含了账号实体,验证码请求实体和返回实体,挺简单的,因为这里接口目前只有两个嘛,当以后我不断开放接口后相信客户端的实体代码远不止于此;再来看方法,作为一个客户端肯定会有登陆账号,密码等传入的地方,我这里不是以配置文件传入的方式获取,而是直接通过客户端类构造函数来传递(构造函数上有默认参数是方便各位朋友使用接口的账号,如果有希望单独开放账号的合作伙伴可以联系我);客户端类中利用泛型T构造了一个统一的账号非空验证方法Validate和密码及Token构造的GetBaseRequest方法,对已代码:

 1  /// <summary>
 2         /// 得到基础请求格式
 3         /// </summary>
 4         /// <returns></returns>
 5         private T GetBaseRequest<T>() where T : MoShenNiuBaseRequest, new()
 6         {
 7             var baseRequest = new T();
 8 
 9             baseRequest.UserName = this.UserName;
10             baseRequest.UserPwd = Md5Extend.GetMd5Hash(this.UserPwd);
11             baseRequest.Token = Md5Extend.GetMd5Hash(string.Format("{0}_{1}_{2}",
12                                                    this.UserName.ToUpper(),
13                                                    this.TokenKey.ToUpper(),
14                                                    baseRequest.UserPwd.ToUpper()));
15 
16             return baseRequest;
17         }
18 
19         /// <summary>
20         /// 非空验证
21         /// </summary>
22         /// <typeparam name="T"></typeparam>
23         /// <param name="t"></param>
24         public void Validate<T>(T t)
25             where T : MoValidateCodeResponse
26         {
27             if (string.IsNullOrWhiteSpace(this.UserName) ||
28                 string.IsNullOrWhiteSpace(this.UserPwd)) { t.Msg = "账号或密码不能为空"; }
29             else if (string.IsNullOrWhiteSpace(this.TokenKey))
30             {
31                 t.Msg = "秘钥不能为空";
32             }
33         }

好了下面直接贴出对应的客户端中调用文字验证码图片验证码的代码:

  1 namespace ShenNiuApi.SDK
  2 {
  3     public class ShenNiuApiClient
  4     {
  5         #region 属性
  6 
  7         public string ApiUrl { get; set; }
  8 
  9         /// <summary>
 10         /// 账号
 11         /// </summary>
 12         public string UserName { get; set; }
 13 
 14         /// <summary>
 15         /// 密码
 16         /// </summary>
 17         public string UserPwd { get; set; }
 18 
 19         /// <summary>
 20         /// 秘钥
 21         /// </summary>
 22         public string TokenKey { get; set; }
 23         #endregion
 24 
 25         public ShenNiuApiClient() { }
 26         public ShenNiuApiClient(string userName = "神牛步行3", string userPwd = "123123", string tokenKey="代码改变世界,需求决定一切", string apiUrl = "http://www.lovexins.com:1001/shenniuapi")
 27         {
 28 
 29             this.UserName = userName;
 30             this.UserPwd = userPwd;
 31             this.TokenKey = tokenKey;
 32             this.ApiUrl = apiUrl;
 33         }
 34 
 35         /// <summary>
 36         /// 得到基础请求格式
 37         /// </summary>
 38         /// <returns></returns>
 39         private T GetBaseRequest<T>() where T : MoShenNiuBaseRequest, new()
 40         {
 41             var baseRequest = new T();
 42 
 43             baseRequest.UserName = this.UserName;
 44             baseRequest.UserPwd = Md5Extend.GetMd5Hash(this.UserPwd);
 45             baseRequest.Token = Md5Extend.GetMd5Hash(string.Format("{0}_{1}_{2}",
 46                                                    this.UserName.ToUpper(),
 47                                                    this.TokenKey.ToUpper(),
 48                                                    baseRequest.UserPwd.ToUpper()));
 49 
 50             return baseRequest;
 51         }
 52 
 53         /// <summary>
 54         /// 非空验证
 55         /// </summary>
 56         /// <typeparam name="T"></typeparam>
 57         /// <param name="t"></param>
 58         public void Validate<T>(T t)
 59             where T : MoValidateCodeResponse
 60         {
 61             if (string.IsNullOrWhiteSpace(this.UserName) ||
 62                 string.IsNullOrWhiteSpace(this.UserPwd)) { t.Msg = "账号或密码不能为空"; }
 63             else if (string.IsNullOrWhiteSpace(this.TokenKey))
 64             {
 65                 t.Msg = "秘钥不能为空";
 66             }
 67         }
 68 
 69         /// <summary>
 70         /// 获取文字验证码
 71         /// </summary>
 72         /// <returns></returns>
 73         public async Task<MoValidateCodeResponse> GetWenZiValidateCodeAsync()
 74         {
 75 
 76             var response = new MoValidateCodeResponse();
 77             try
 78             {
 79                 //非空验证
 80                 Validate(response);
 81                 if (!string.IsNullOrWhiteSpace(response.Msg)) { return response; }
 82 
 83                 //获取基础请求设置
 84                 var request = this.GetBaseRequest<MoValidateCodeRequest>();
 85 
 86                 //json化
 87                 var requestStr = JsonConvert.SerializeObject(request);
 88                 //发送请求
 89                 var returnStr = string.Empty;
 90                 using (HttpClient client = new HttpClient())
 91                 {
 92                     client.Timeout = TimeSpan.FromSeconds(60);
 93                     var stringContent = new StringContent(requestStr, Encoding.UTF8, "application/x-www-form-urlencoded");
 94                     stringContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
 95 
 96                     var httpResponseMessage = client.PostAsync(this.ApiUrl + "/WenZiValidateCode", stringContent).Result;
 97                     var stream = await httpResponseMessage.Content.ReadAsStreamAsync();
 98                     using (StreamReader reader = new StreamReader(stream))
 99                     {
100                         returnStr = await reader.ReadToEndAsync();
101                     }
102                 }
103                 if (string.IsNullOrWhiteSpace(returnStr))
104                 {
105 
106                     return response;
107                 }
108                 //解析
109                 response = JsonConvert.DeserializeObject<MoValidateCodeResponse>(returnStr);
110             }
111             catch (Exception ex)
112             {
113                 response.Msg = ex.Message;
114             }
115             return response;
116         }
117 
118        
119         /// <summary>
120         /// 获取图片验证码
121         /// </summary>
122         /// <returns></returns>
123         public async Task<MoValidateCodeResponse> GetTuPianValidateCodeAsync()
124         {
125 
126             var response = new MoValidateCodeResponse();
127             try
128             {
129                 //非空验证
130                 Validate(response);
131                 if (!string.IsNullOrWhiteSpace(response.Msg)) { return response; }
132 
133                 //获取基础请求设置
134                 var request = this.GetBaseRequest<MoValidateCodeRequest>();
135 
136                 //json化
137                 var requestStr = JsonConvert.SerializeObject(request);
138                 //发送请求
139                 var returnStr = string.Empty;
140                 using (HttpClient client = new HttpClient())
141                 {
142                     client.Timeout = TimeSpan.FromSeconds(60);
143                     var stringContent = new StringContent(requestStr, Encoding.UTF8, "application/x-www-form-urlencoded");
144                     stringContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
145 
146                     var httpResponseMessage = client.PostAsync(this.ApiUrl + "/TuPianValidateCode", stringContent).Result;
147                     var stream = await httpResponseMessage.Content.ReadAsStreamAsync();
148                     using (StreamReader reader = new StreamReader(stream))
149                     {
150                         returnStr = await reader.ReadToEndAsync();
151                     }
152                 }
153                 if (string.IsNullOrWhiteSpace(returnStr))
154                 {
155 
156                     return response;
157                 }
158                 //解析
159                 response = JsonConvert.DeserializeObject<MoValidateCodeResponse>(returnStr);
160             }
161             catch (Exception ex)
162             {
163                 response.Msg = ex.Message;
164             }
165             return response;
166         }
167  
168     }
169 }
View Code

 

» 使用NuGet Package Explorer工具生成ShenNiuApi.SDK的nuget包并发布到nuget网站上

因为我们要发布Sdk的nuget包,所以需要打包才行,这里就不用nuget命令了而是使用NuGet Package Explorer工具来打包,首先安装好工具后,我们打开有这样的画面:

我们选中如上图所示的选项,然后选中"编辑选项":

然后录入如下信息即可,您也可以录入更多的依赖等选项的信息:

这些信息是我发布的sdk,您们自己的可以不用填写这么详细哈哈,记得填完后再点击刚才位置的绿色钩钩(保存),好了接下来重点是在工具的右边的"Package Contents"区域=》右键鼠标=》选中如下图所示选项:

这里选项的意思添加类库dll,点击完后会有一个"Lib"出现,再右键Lib选中"Add .Net Folder"=》"V4.5"后面这个4.5是您打包项目的版本,我的是适用于4.5的,如下图:

然后再直接把您项目bin下面生成的dll(我这里是ShenNiuApi.SDK.dll)直接拖到"Package Contents"区域并且是在"V4.5"的下级,效果如下:

最后一步"保存"我们的nuget文件,先点击工具左上角的"File"=》"Save",有提示包文件保存在哪里,确定后就可以在您保存的文件夹下面看到您的nuget包了:

怎么样使用工具是不是很简单,您成功生成自己的nuget包了么;如果您想包您的包发布到nuget共全世界.net程序猿使用那么还是使用此工具“File”=》“publish”=》如图:

不错意外您的nuget包就发布上去了,并且在vs中通过搜索包也能看到,例如我这里的包:

如果能收到您自己的nuget包是不是感觉很兴奋呢哈哈,我也是当截图此刻发布两天的sdk已经有51次下载量了,不错啦;网站上的描述:

到此本章的内容就结束了,希望给您带来了学习的帮助,如果感谢我的话并且考虑要买双鞋子和衣服,不妨来小弟衣服店看看:神牛衣柜3非常感谢您的支持也感谢多多点赞。

代码资源包:使用ShenNiuApi.SDK的nuget包

目录
相关文章
|
6月前
|
物联网 开发工具 Android开发
UniApp调用SDK原生接口
UniApp调用SDK原生接口
421 0
UniApp调用SDK原生接口
|
8月前
|
机器学习/深度学习 人工智能 PHP
百度AI开发平台图像增强与特效API-SDK接口PHP实战记录
百度AI开发平台图像增强与特效API-SDK接口PHP实战记录
85 0
百度AI开发平台图像增强与特效API-SDK接口PHP实战记录
|
8月前
|
网络协议 Java 应用服务中间件
SDK接口远程调试【内网穿透】
SDK接口远程调试【内网穿透】
166 1
|
24天前
|
Web App开发 前端开发 JavaScript
如何快速与呼叫中心系统CTI/API/SDK接口集成
由于呼叫中心系统涉及通信、CTI、终端设备、中继线路等技术与概念,从事信息管理系统、ERP、CRM、工单系统等的研发人员一般不是非常熟悉这部分技术,当需要提供具备呼叫中心能力的解决方案时,往往要用较多的时间来研究这些相对复杂的技术,对接过程比较长,开发调试有一定的阻力,基于此,我们提出一种更加简便高效的集成方法,可以零代码集成呼叫中心平台,实现项目快速上线。
如何快速与呼叫中心系统CTI/API/SDK接口集成
|
5月前
|
安全 API 开发工具
获取仓库列表接口可以通过SDK或者REST API两种方式调用
获取仓库列表接口可以通过SDK或者REST API两种方式调用
47 2
|
3月前
|
JSON JavaScript 前端开发
全面的.NET微信网页开发之JS-SDK使用步骤、配置信息和接口请求签名生成详解
全面的.NET微信网页开发之JS-SDK使用步骤、配置信息和接口请求签名生成详解
|
3月前
|
供应链 安全 开发工具
供应链安全情报 | 恶意py包伪装代理SDK进行后门攻击,目标锁定python开发者
2023年11月28号,悬镜供应链安全实验室在Pypi官方仓库(https://pypi.org)监测到两起伪装成http和socks5代理SDK的开源组件投毒事件。python开发者一旦下载安装这些投毒Py包(libproxy、libsocks5),会触发执行Py包中的恶意代码,最终将导致开发者系统被投毒者植入恶意后门。
35 0
|
8月前
|
API PHP 开发工具
漏刻有时API接口实战开发系列(11):腾讯云短信3.0sms开发SDK环境部署及配置的实战总结
漏刻有时API接口实战开发系列(11):腾讯云短信3.0sms开发SDK环境部署及配置的实战总结
168 0
|
8月前
|
IDE 开发工具 C++
如何安装0·PIE-SDK二次开发包?
如何安装0·PIE-SDK二次开发包?
109 0
|
9月前
|
网络协议 Java 应用服务中间件
支付宝SDK接口调试- cpolar内网穿透工具实现公网地址调试
支付宝SDK接口调试- cpolar内网穿透工具实现公网地址调试
99 0

相关产品

  • 云迁移中心