第一章【API接口设计与本地调试】

本章为【WebApp全栈项目开发】实战的第一章,主要描述一个WebAPI接口是如何构建的。

在构建WebAPI接口前,我们首先要创建一个数据库,起名为APP_DBA,然后创建相应的表,分别为APP、APP_Class、APP_ClassOne、APP_ClassTwo、APP_User。

第一章【API接口设计与本地调试】_第1张图片
分类表结构.png
第一章【API接口设计与本地调试】_第2张图片
应用表.png

数据库建好之后,我们先手动添加一些测试数据,之后我们会编写一个WinForm客户端来上传真实的数据。

接着我们在VS中新建一个项目ASP.NET Web应用程序

第一章【API接口设计与本地调试】_第3张图片
1.png

然后选择空模板并勾选Web API

第一章【API接口设计与本地调试】_第4张图片
2.png

在Web.config中添加数据库连接


    

注意一定要用SQL Server身份来连接数据库,否则部署到IIS上,IIS是识别不了的。

接着我们需要构建一个SQL类用来查询数据库里的内容,在Models文件夹右键添加类,类文件源码如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;
using System.IO;
using MSScriptControl;
using System.Data.SqlClient;
using System.Configuration;

namespace AppAjaxApi.Models
{
    public class SQL
    {
        //获取连接字符串
        static string str = ConfigurationManager.ConnectionStrings["AppConnection"].ConnectionString;
        //根据ID查询用户的Token
        public DataSet GetToken(int uid)
        {
            string cmdText = "select * from APP_User where ID=@ID";
            SqlConnection con = new SqlConnection(str);
            SqlCommand com = new SqlCommand(cmdText, con);
            SqlParameter[] ps = { new SqlParameter("ID", uid) };
            com.Parameters.AddRange(ps);
            DataSet ds = new DataSet();
            SqlDataAdapter da = new SqlDataAdapter(com);
            da.Fill(ds);
            con.Close();
            return ds;

        }
        //根据Token计算密钥Key
        public int GetKey(string Token)
        {

            string js = AppDomain.CurrentDomain.BaseDirectory + "App_Data\\totp.js";
            string cjs = File.ReadAllText(js);
            string fun = string.Format(@"getCode('{0}')", Token);
            string result = ExecuteScript(fun, cjs);
            return Convert.ToInt32(result);
        }
        //根据APP名称查询APP数据
        public DataSet GetApp(string name)
        {
            string cmdText = "select Icon,Name,ClassTwoName,Score,Count,Subtitle,Describe,Url from APP,APP_ClassTwo where ClassTwoID=ClassTwo and Name=@Name";
            SqlConnection con = new SqlConnection(str);
            SqlCommand com = new SqlCommand(cmdText, con);
            SqlParameter[] ps = { new SqlParameter("Name", name) };
            com.Parameters.AddRange(ps);
            DataSet ds = new DataSet();
            SqlDataAdapter da = new SqlDataAdapter(com);
            da.Fill(ds);
            con.Close();
            return ds;
        }
        //根据APP父类查询APP数据
        public DataSet GetClassOne(int classone)
        {
            string cmdText = "select Icon,Name,Score,Count,Subtitle,Url from APP where ClassOne=@ClassOne";
            SqlConnection con = new SqlConnection(str);
            SqlCommand com = new SqlCommand(cmdText, con);
            SqlParameter[] ps = { new SqlParameter("ClassOne", classone) };
            com.Parameters.AddRange(ps);
            DataSet ds = new DataSet();
            SqlDataAdapter da = new SqlDataAdapter(com);
            da.Fill(ds);
            con.Close();
            return ds;
        }
        //获取所有APP数据
        public DataSet Get()
        {
            string cmdText = "select Icon,Name,Score,Count,Subtitle,Url from APP";
            SqlConnection con = new SqlConnection(str);
            SqlCommand com = new SqlCommand(cmdText, con);
            DataSet ds = new DataSet();
            SqlDataAdapter da = new SqlDataAdapter(com);
            da.Fill(ds);
            con.Close();
            return ds;
        }
        //C#调用javascript方法
        public string ExecuteScript(string Expression,string Code)
        {
            ScriptControl scriptControl = new ScriptControl();
            scriptControl.UseSafeSubset = true;
            scriptControl.Language = "JScript";
            scriptControl.AddCode(Code);
            try
            {
                string str = scriptControl.Eval(Expression).ToString();
                return str;
            }
            catch(Exception ex)
            {
                string str = ex.Message;
            }
            return null;
        }
    }
}
这里需要注意两个事情
1、为了防止接口被恶意盗用,本接口采用TOTP算法实现了客户端和服务端的双向认证,即客户端登录后获取用户的Token,并根据这个Token在请求接口的时候采用TOTP算法计算出一个密钥Key,包含到请求中一并发送给服务端。服务端接收请求参数的同时也会去计算密钥Key,然后和客户端传过来的Key进行比较,如果一致说明是合法请求,不一致不会返回数据。
了解更多TOTP算法知识请看下面这篇文章

http://www.cnblogs.com/wangxin201492/p/5030943.html

2、由于TOTP算法的源码多数为Javascript和Python版本,没有找到C#版的,所以就添加微软的Microsoft Script Control 1.0这个引用,用C#去调用Javascript脚本

专门为伸手党提供totp.js源码 https://pan.baidu.com/s/1kUZViab

第一章【API接口设计与本地调试】_第5张图片
js.png

SQL类创建完成后我们还需要创建一个控制器。在右侧的Controllers文件夹上右键添加控制器,这里取名为APPControllers。代码如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Data;
using System.Web.Http;
using AppAjaxApi.Models;

namespace AppAjaxApi.Controllers
{
    public class APPController : ApiController
    {
        public SQL sql = new SQL();
        //根据APP名称返回APP数据
        public DataTable GetApp(string name, int key, int uid)
        {
            string Token = sql.GetToken(uid).Tables[0].Rows[0]["Token"].ToString();
            int Key = sql.GetKey(Token);
            if (Key == key)
            {
                return sql.GetApp(name).Tables[0];
            }
            return GetMsg();
        }
        //根据父类返回APP数据
        public DataTable GetAjaxByClassOne(int classone, int key, int uid)
        {
            string Token = sql.GetToken(uid).Tables[0].Rows[0]["Token"].ToString();
            int Key = sql.GetKey(Token);
            if (Key == key)
            {
                return sql.GetClassOne(classone).Tables[0];
            }
            return GetMsg();
        }
        //返回所有APP数据
        public DataTable GetAjax(int key,int uid)
        {
            string Token = sql.GetToken(uid).Tables[0].Rows[0]["Token"].ToString();
            int Key = sql.GetKey(Token);
            if (Key == key)
            {
                return sql.Get().Tables[0];
            }
            return GetMsg();
        }
        //非法调用接口返回数据
        public DataTable GetMsg()
        {
            DataTable dt = new DataTable();
            DataColumn dc = new DataColumn("msg", Type.GetType("System.String"));
            dt.Columns.Add(dc);
            DataRow dr = dt.NewRow();
            dr["msg"] = "非法调用接口";
            dt.Rows.Add(dr);
            return dt;
        }

    }
}

第一章【API接口设计与本地调试】_第6张图片
Controller.png

最后修改App_Start文件夹下的接口配置文件,使返回的数据为JSON格式
在Register方法内添加如下代码

// Web API 配置和服务
config.Formatters.Remove(config.Formatters.XmlFormatter);
var jsonFormatter = config.Formatters.JsonFormatter;
jsonFormatter.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented;
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
第一章【API接口设计与本地调试】_第7张图片
json.png

这样一个WebAPI接口就编写完成了,接下来就是发布。

在你的项目上右键选择发布,目标选择IIS、FTP等

第一章【API接口设计与本地调试】_第8张图片
iis.png

发布方法选择【文件系统】然后指定输出的路径

第一章【API接口设计与本地调试】_第9张图片
is.png

将输出的文件上传到服务器,并部署到IIS上就可以通过外网来访问了。具体操作放到下一章《服务器部署》中讲述。

我们先在本地测试一下这个接口,假定某一个用户的Token我们已知为LFLFMU2SGVCUIUCZKBMEKRKLIQ,然后我们可以通过nodejs或者构建一个静态页面来调用totp.js从而计算出我们的密钥Key

我这里计算出来的结果是006156,带入到接口请求参数中得到
http://localhost:51230/ajax/app/GetAjax?key=006156&uid=1

第一章【API接口设计与本地调试】_第10张图片
json.png

接口项目源码 https://pan.baidu.com/s/1qYtxNhM

本章介绍完毕请看下一章《服务器部署》

你可能感兴趣的:(第一章【API接口设计与本地调试】)