Bootstrap

【c#】如何做一个简单的WebAPI,以及调用,以及遇到相关的一些问题。

接上一次的:【c#/MVC】运用MVC模式,做一个增删查改简单数据库,以及涉及到的知识,本次将部分原本的业务逻辑层和数据访问层剥离出来,单独作为一个API,挂到IIS上,然后访问。

阅读帮助:

重点内容红色加粗标记,正文为黑色字体可以略过的解释用淡蓝色表示,自定名词粉色引用部分可以看也可以不看。

_____________________________________________________________________________

目录

前提:数据库设计

创建一个新WebAPI:

新建项目:

调用API

遇到的问题:

1、IIS的正确配置,网站的挂载,挂载时的问题:IIS没有对物理路径的读取访问权限

正确的IIS搭建:

警告:IIS没有对物理路径的读取访问权限!

2、WebAPI的接口返回类型:在调用post等方法时报错:405,方法不被允许。

3、Http协议和http请求中的8种请求方法

http报文的格式

HTTP方法(method)

HTTP请求头、相应头(首部)

4、在API发布后,调试时弹出“您正在调试XXX的发布版本。。。。调试体验会降级。。。例如不会命中断点。”

5、设置防火墙,实现局域网访问你的IIS。

6、JSON保存为字符串后,出现的斜杠问题,以及该如何处理这个斜杠.

7、WebApi的传参数问题,如何给Webapi传递参数

 

8、如何对API进行测试?如何给POST等方式进行测试?

第一:推荐使用postman工具(谷歌浏览器直接由对应的插件)

第二:使用NuGet使用大佬的程序包:【WebApiTestClient 】

9、API访问时出现httpput和httpdelete的谓词问题,该如何处理。

10、如何给APIhelp页面添加注释:

11、此请求已被阻止,因为当用在 GET 请求中时,会将敏感信息透漏给第三方网站


——————————————————————————————————————————

前提:数据库设计

这个部分因为在之前的【c#/MVC】运用MVC模式,做一个增删查改简单数据库,以及涉及到的知识中已经写过,没有任何改动,在此不表。

——————————————————————————————————————————

创建一个新WebAPI:

新建项目:

【文件】-【新建】-【项目】-【Visual C#】-【Web】-【ASP.net Web 应用程序服务】-选择【Web API】-右侧【改变身份验证】

注1:这里我们可以看到,在下方的【为以下项添加文件夹和核心引用】中的【MVC】和【web API】已经是默认勾选的,和之前创建MVC项目并不一样。

注2:身份验证这里,一般来说肯定是需要的,要根据用户的类型开放相应的权限,不过本例中就简单的设置为不进行验证,以方便学习。

注3:选择【Web API】时,右侧说明为:用于创建可以访问范围广阔的客户端(可以访问浏览器和移动设备)的RESTful HTTP服务的项目模板。

什么是RESTful风格:

基于Rest构建的API就是RESTful风格。

什么是REST:

(Representational State Transfer):表现层状态转移,一种软件架构风格,不是标准(不一定要遵循)。总结的说就是:用URL定位资源,用HTTP动词(GET,POST,PUT,DELETE)描述操作。

使用RESTful的理由:

一是基于JSP的局限性,使前后端分离逐渐成为互联网公司开发的业界标准使用方式。关于前后端分离:有篇很好的文章

二是目前Client层(客户端层)的类型越来越多,RESTful可以只通过一套接口为IOS、Web、安卓等提供服务。微博开放平台和微信开放平台都采用了RESTful风格。

设计这个风格的思路:

API地址以名词为主,且用复数。对资源的调用都用HTTP动作来进行。这个部分可以参考:

此时,一个新的API空项目就建立好了。

在控制器(Controler)中右键【新建控制器】-【包含读写操作的Web API 2控制器】

新建的右侧可以看到这个控制器会包含创建、读取、更新、删除、和列出条目的REST操作。

这个控制器我命名为:【Student3APIController】。

重点:在项目中的【App_Start】文件夹中,双击打开路由设置【WebAPIConfig】,将默认路由修改为:

//在routeTemplate处添加一个:{action}
//你也可以自由修改这个路由
config.Routes.MapHttpRoute(
                name:"ActionAPI",
                routeTemplate: "actionapi/{controller}/{action}/{id}",
                defaults: new { id = RouteParameter.Optional }
                );

然后在模型(model)中右键新建一个类,取名为【Student】作为模型,这个模型是要根据数据库来设计,代码如下:

 public class Student
    {
        public int id { get; set; }
        public string name { get; set; }
        public string number { get; set; }
        public string sex { get; set; }
        public int age { get; set; }
        public string course1 { get; set; }
        public string course2 { get; set; }
    }

回到新建的控制器【Student3APIController】中,可以看到和以前的MVC项目不同,它继承的是【ApiController】,同时已经在其中自动生成了get、get(id)、post、delete、put等增删查改的几个操作。

从之前的MVC项目中将有关代码拷贝回来,进行略微的修改,其中涉及到的几个问题将在下面详述:

using部分:
using system.net;
using system.web.http;
using system.net.http;
删除using system.web.mvc;
注意:system.web.mvc;会与system.web.http;中的方法同名冲突,因此要删去对MVC的引用。
。。。。。。。。。。。。。。。。。。。。。。
API部分:
/// <summary>
    /// This Web API use to modify the message from studentDB
    /// </summary>
    public class Student3APIController : ApiController
    {
        private SqlCommandHelper sqlCommandHelper = new SqlCommandHelper();
        private String content=null;
        // GET: actionapi/Student3API/GET
        /// <summary>
        /// Get all records from test database student table.
        /// </summary>
        /// <returns>Json Array,Convert from .net List.</returns>
        [HttpGet]
        public JsonResult<List<Student>> Get()
        {
            string sqlStr = "GetAllUserDetails";
            List<Student> students = new List<Models.Student>();
            students = sqlCommandHelper.GETStudentMessage(sqlStr, -1);
            return Json<List<Student>>(students);
        }

        /// <summary>
        /// Get a records from test database student table due to ID
        /// </summary>
        /// <param name="id">Student ID</param>
        /// <returns>Json Array,Convert from .net List.</returns>
        // GET: actionapi/Student3API/GET/1
        [HttpGet]
        public JsonResult<List<Models.Student>> Get(String id)
        {
            string sqlStr = "AH_GetUserDetail";
            List<Models.Student> students = new List<Models.Student>();
            students = sqlCommandHelper.GETStudentMessage(sqlStr, Convert.ToInt16(id));
            return Json<List<Models.Student>>(students);
        }

        // POST: actionapi/Student3API/POST/[para]
        /// <summary>
        /// Add a student records.
        /// </summary>
        /// <param name="obj"> dynamic obj,include a student model{name、number、sex、age、course1、course2},post type is [string](age should is int)</param>
        /// <returns></returns>
        [HttpPost]
        public  bool Post([FromBody]dynamic obj)
        {
            //Student student = JsonConvert.DeserializeObject(obj);
            string sqlStr = "AddStudentDetails";
            SqlParameter[] para =
            {
                 new SqlParameter("@name",SqlDbType.VarChar),
                 new SqlParameter("@number",SqlDbType.VarChar),
                 new SqlParameter("@sex",SqlDbType.VarChar),
                 new SqlParameter("@age",SqlDbType.VarChar),
                 new SqlParameter("@course1",SqlDbType.NVarChar),
                 new SqlParameter("@course2",SqlDbType.NVarChar)
            };
            para[0].Value = obj.name;
            para[1].Value = obj.number;
            para[2].Value = obj.sex;
            para[3].Value = Convert.ToInt16(obj.age);
            para[4].Value = obj.course1;
            para[5].Value = obj.course2;
            //需要为空的参数可以赋值为DBNull.Value
            //If need null para value,you can assign it is [DBNull.Value].

            bool judgeWriteStudentMessage = sqlCommandHelper.WriteStudentMessage(sqlStr, para);
            return judgeWriteStudentMessage;
        }
        /// <summary>
        /// 测试,没有用处。
        /// </summary>
        /// <param name="test"></param>
        /// <returns></returns>
        public bool Post2([FromBody]dynamic test)
        {
            bool judge = false;
            if (test.name != "q") judge = true;
                return judge; 
        }

        // PUT: actionapi/Student3API/PUT/5
        /// <summary>
        /// Use to modify student message
        /// </summary>
        /// <param name="obj">dynamic obj,include a student model{id,name,number,sex,age,course1,course2},post type is [string](age should is int,ID should be exist)</param>
        [HttpPost]
        public bool Put( [FromBody]dynamic obj)
        {

            string sqlStr = "ModifyStudentDetails_Id";
            SqlParameter[] para =
           {
                new SqlParameter("@t_id",SqlDbType.Int),
                 new SqlParameter("@t_name",SqlDbType.VarChar),
                 new SqlParameter("@t_number",SqlDbType.VarChar),
                 new SqlParameter("@t_sex",SqlDbType.VarChar),
                 new SqlParameter("@t_age",SqlDbType.VarChar),
                 new SqlParameter("@t_course1",SqlDbType.NVarChar),
                 new SqlParameter("@t_course2",SqlDbType.NVarChar)
            };
            para[0].Value = Convert.ToInt16(obj.id);
            para[1].Value = obj.name;
            para[2].Value = obj.number;
            para[3].Value = obj.sex;
            para[4].Value = Convert.ToInt16(obj.age);
            para[5].Value = obj.course1;
            para[6].Value = obj.course2;
            //需要为空的参数可以赋值为DBNull.Value
            //If need null para value,you can assign it is [DBNull.Value].
            bool judgeWriteStudentMessage = sqlCommandHelper.WriteStudentMessage(sqlStr, para);
            return judgeWriteStudentMessage;
        }

        // DELETE: actionapi/Student3API/DELETE/5
        /// <summary>
        /// use to delete a student message due to ID
        /// </summary>
        /// <param name="id">ID,type is int</param>
        [HttpPost]
        public bool Delete([FromBody]int id)
        {
            string sqlStr = "DelStudentDetails";
            SqlParameter[] para = { new SqlParameter("@id", SqlDbType.Int) };
            para[0].Value =id;
            bool judgeWriteStudentMessage = sqlCommandHelper.WriteStudentMessage(sqlStr, para);
            return judgeWriteStudentMessage;

        }
    }

注:其中有一个辅助类,【SqlCommandHelper】,同样在之前的MVC项目中,点击最上方链接进行查看.

然后在右侧的解决方案资源管理器中对项目(解决方案下的父目录)右键发布,新建一个文件夹,并把内容放在其中.

在IIS(Internet信息服务管理器)中右键目录添加一个网站,网站的物理地址就是刚刚发布出的文件夹。

最后,右键浏览IIS中的网站,即可发现一个API的Helper页面。

————————————————————————————————————————————————————

调用API

首先在nuGet中添加一个包:(这个包是HTTPClient的扩展方法,不添加的话会缺少很多方法。)

PM->[Microsoft.AspNet.WebApi.Client]
这个包名,直接搜索可以搜到

在控制器中:

using System.Net.Http;
。。。。 
private HttpClient actionAPI = new HttpClient();

因为我用的是HttpClient方法,所以这是一切的开始。

以下为各个api的调用:(有关视图的部分都省略了)

得到所有信息
 [HttpGet]
        public async System.Threading.Tasks.Task<ActionResult> ShowAllDetailes()
        {
            actionAPI.BaseAddress = new Uri("http://10.194.46.210/actionapi/Student3API/GET");
            List<Models.Student> students = new List<Models.Student>();
            string content =await actionAPI.GetStringAsync(actionAPI.BaseAddress);
            students = JsonConvert.DeserializeObject<List<Models.Student>>(content);
            ViewBag.listStudents = students;
            return View("ShowAllDetailes");
        }

新增一行信息
[HttpPost]
        public async System.Threading.Tasks.Task<ActionResult> CreateNewRecord(FormCollection f)///FormCollection是MVC中表单里的一个集合,它也可以来接收前台提交过来的表单,前台提交过来的表单全都封装到这个对象中来了
        {
            actionAPI.BaseAddress = new Uri("http://10.194.46.210/actionapi/Student3API/POST");
            MVCStudent2.Models.Student2 student2 = new Models.Student2();
            student2.name = f["Name"].Trim();
            student2.number = f["Number"].Trim();
            student2.sex= f["Sex"].Trim();
            student2.age= Convert.ToInt16(f["Age"].Trim());
            student2.course1 = f["Course1"].Trim();
            student2.course2= f["Course2"].Trim();
            //string temp = JsonConvert.SerializeObject(student2);
            //OpenReadWithHttps(actionAPI.BaseAddress.ToString(), JsonConvert.SerializeObject(student2));
            var responseMessage =await  actionAPI.PostAsJsonAsync(actionAPI.BaseAddress.ToString(), student2);
            bool judgeWriteStudentMessage =responseMessage.IsSuccessStatusCode;
            if (judgeWriteStudentMessage == false)
            { return View("FalseOperation"); }
            else
            {
                return View("SuccessfulOperation");
            }
        }

根据ID得到一条信息
[HttpGet]
        public async Task<JsonResult> UpdateAjax_test(string studentID)
        {
            string uriTemp = "http://10.194.46.210/actionapi/Student3API/GET/" + Convert.ToInt16(studentID);
            actionAPI.BaseAddress = new Uri(uriTemp);
            List<Models.Student> students = new List<Models.Student>();
            string content = await actionAPI.GetStringAsync(actionAPI.BaseAddress);
            students = JsonConvert.DeserializeObject<List<Models.Student>>(content);
            MVCStudent2.Models.Student student = null;
            if (students != null)
            {
               student= students[0];
            }
            else
            {
                return null;
            }
                return new JsonResult() {
                    Data=student,
                    JsonRequestBehavior = JsonRequestBehavior.AllowGet
                };
        }

————————————————————————————————————————————————————

遇到的问题:

1、IIS的正确配置,网站的挂载,挂载时的问题:IIS没有对物理路径的读取访问权限

IIS:全称为Internet Information Services,即互联网信息服务,里面包含了Web服务器、FTP服务器、NNTP服务器、SMTP服务器,分别可以在网络上网页浏览、文件传输、新闻服务和邮件发送。

现在就需要使用到Web服务,因此我们最先需要完成的就是对IIS的正确配置:搭建一个本地的ASP的IIS测试环境。

正确的IIS搭建:

【控制面板】-【程序】-【程序和功能】-【打开和关闭Windows功能】-【internet信息服务】,这里展开,有多个折叠页。

对【安全性】、【常见HTTP功能】、【性能功能】三个折叠页进行全选操作(注意选中的对勾分为两种,高亮的才是全选,黯淡的并非)

对【应用程序开发功能】展开,将【ASP】和【ISAPI扩展】进行全选。

对【运行状况和诊断】展开,将【HTTP日志】【请求监视器】全选。

确定后系统会进行安装,安装后不用重启电脑。

完成上述操作后,在开始菜单的搜索框就可以搜索到IIS(internet信息服务管理器,不是IIS6.0管理器)了。

打开IIS,在左侧添加网站,添加时【网站名称】自定,【应用程序池】可以自定也可以采用IIS中已有的应用程序池,【物理路径】是你程序发布的那个文件夹,【IP地址】需要绑定,【端口】要记住你的端口号,【主机名】在没有域名的情况下不需要绑定。

网站添加之后,双击网站,然后双击中间缩略图中的【ASP】,将其中的启用父路径修改为TRUE(默认FALSE)

最后在【默认文档】中看看是否含有default.html这个选项。

此时你的IIS网站就挂载好了。

警告:IIS没有对物理路径的读取访问权限!

在添加地址时,有一个【测试设置】的按钮,点击后会有个【IIS没有对物理路径的读取访问权限】的错误,这个错误其实不影响你的网站的使用,如果想要将这个警告取消的话,在【连接为】处绑定一个你的计算机帐户密码即可。


2、WebAPI的接口返回类型:在调用post等方法时报错:405,方法不被允许。

这个问题其实是关于HTTP请求的问题。

在API处用HTTP添加相应的标记,例如【HttpPost】【HttpGet】等等,这个标记可以规定只用相应的请求方式才可以访问到对应的Action,同时也会给调用API的用户提示,该用什么方式来调用。

同时在调用API的地方,也要用相应请求方式,调用POST的api就用POST方式,注意不能用post去get一个请求。


3、Http协议和http请求中的8种请求方法

http报文的格式

上个问题说到了HTTP请求,这里就干脆将HTTP请求报文和响应报文学习一下。

请求报文是由客户端向服务端发送的报文,而响应报文则是由服务端向客户端发送的报文。

首先,HTTP的HTTP报文由:起始行(请求报文为请求行、响应报文为响应行)(start line)、首部header)、主体body)3个部分组成。

其中请求报文的格式:

请求行:<method><requestURL><version>
首部:<headers>
这里是空行
请求主体:<entiy-body>

响应报文的格式:

响应行:<version><status><reason-phrase>
首部:<headers>
这里是空行
响应主体:<entity-body>

黑色二者兼具的解释,蓝色请求报文的格式解释,紫色响应报文解释:

method(http方式):客户端希望服务器对资源执行的操作。如get,head,post

request-URL(请求地址):所请求的资源地址

version(版本):报文所使用的HTTP版本

status-code(状态码):三个数字描述请求中所发生的情况。如404

reason-phrase(原因短语):数字状态码的可读版本,对状态码的一个简单解释。

headers(首部)可以有零个或多个首部,每个首部都包含一个名字,后面跟着一个冒号:

entiy-body(实体的主体部分):即要传输的内容,图片、视频、文字这些。

HTTP方法(method)

安全方法】:特指GET方法和HEAD方法,这两种方法除了请求资源外不会有什么动作,也就不会对服务器产生什么结果。

Get】:

最常见的请求方式,当用户需要从服务器读取文档时使用,请求服务器发送某个资源

get方法要求 服务器 将URL定位的资源放到 响应报文 的数据部分,回传给客户端,请求过程中的请求数据(向服务端发送的数据)会以地址的形式表现在请求行参数以【】附在URL之后,并且各个参数之间要用【&】间隔。

值得注意,参数中包含空格会转换为【+】号,如何是英文字符和数字以外的字符,例如汉字,则将字符串用BACE64加密,得到%E4%BD%A0%E5%A5%BD这样的字符串,其中%XX中的XX是该符号以16进制表示的ASCLL。

特点:

  1. Get方法速度相对Post要(因为:1、Get方式会少几个首部Headers的描述字段,2、post会多一个向服务器确认请求头的过程3、get会缓存静态资源,而post不会,注意如果是数据get一般也不缓存,但是浏览器是IE就会……4、涉及一个管道化链接的问题:一种持久化的TCP连接方式,get可以而post非主动开启则不可以)
  2. Get方法请求的数据是明文,不适合传送私密数据
  3. 受限于浏览器对地址栏的字符识别,也不适合传递大量数据
  • 附注:postget请求的过程:
    SYN:同步序列编号(Synchronize Sequence Numbers)
  • get请求过程:(将三次握手一并写出)
  1. 浏览器请求tcp连接(第一次握手):客户端发送syn(syn=j)包到服务器,进入syn_send状态
  2. 服务器应答进行tcp连接(第二次握手):确认客户的SYN(即ACK=J+1),加上自己发送的一个syn(syn=k)包,一起发到客户端(即SYN+ACK包),此时的服务器就变成了SYN_RECV状态;
  3. 浏览器确认,发送get请求头和数据(第三次握手):客户端收到了服务端发来的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),发送完毕后客户端和服务端同时进入Establishid状态,完成三次握手。开始发送数据。
  4. 服务器发送200,响应ok
  • post请求过程:对比get发现数据发送的不同,get是在请求头发送时将数据附带在协议头<request-line>发送,而post的数据则是单另发送。
  1. 浏览器请求tcp连接(第一次握手):
  2. 服务器应答进行tcp连接(第二次握手):
  3. 浏览器确认,发送post请求头
  4. 服务器返回100,continue响应
  5. 浏览器开始发送数据
  6. 服务器返回200,响应ok。

post】:

最常见的请求方式,允许客户端给服务端提供较多信息。POST方法将请求参数封装在HTTP请求数据中,相对get有一定安全性;以【名称/值】的形式出现,可以传输大量数据。

POST的数据放置在HTTP包的包体<entiy-body>中。

注意其实get的功能都可以由post方式来完成,因此往往各种表单提交时都会使用post,这一点就好还是根据情形来选择,可以有效提高效率。

Head】:

这是继上面两个后常用的方法。

这是很类似于get的一个方法,安全,高效,只不过不同于get的是,服务端接受了Head请求仅仅会返回响应头,而不会返回响应内容,因此当我们需要查看某个页面的状态时,使用HEAD会非常高效,因为这个过程省略了页面内容。

PUT】:
注:以下几个都没有用过,这里罗列资料,未来使用时将对此进行补充修改

PUT方法的语意就是让服务器用请求的主体部分,来创建一个由请求的URL命名的新文档,或者,如果那个URL已经存在的话,就用这个新主体代替它。

因为PUT允许用户对内容进行修改,所以很多WEB服务器要求执行PUT方法之前,用密码登陆。

DELETE】:

DELETE方法所做的事情就是请服务器删除请求URL所指定的资源;但是客户端无法确保删除操作一定会被执行。

因为HTTP规范允许服务器在不通知客户端的情况下撤销请求。

TRACE】:

客户端发起一个请求时,这个请求可能要穿过防火墙、代理、网关或其他一些应用程序。没个中间节点可能会修改原始的HTTP请求。TRACE方法允许客户端在最终将请求发送给服务器时,看看它变成了什么样子。

TRACE请求会在目的服务器端发起一个“环回”诊断。行程最后一站的服务器会弹会一条TRACE响应,并在响应主体中携带它收到的原始请求报文。

TRACE方法主要用于诊断;也就是说用于验证是否如愿穿过了请求/响应链。

TRACE请求中不能带有实体的主体部分(应该是不能带有请求主体的意思?)。

OPTIONS】:

OPTIONS方法请求Web服务器告知其支持的各种功能。他可以访问服务器通常支持哪些方法,或者针对某些特定的资源支持哪些特定的操作。

这为客户端应用程序提供了一种手段,使其不用实际访问那些资源就可以判定访问这些资源的最优方式。

(意思是可以借助这个知道要访问的API可以使用的HTTP方法类型?)

扩展方法】:

HTTP被设计成字段可扩展的,这样新的特性就不会使老的软件失效了。扩展方法指的是没有在HTTP/1.1规范中定义的方法,服务器会为他所管理的资源实现一些HTTP服务,这些方法为开发者提供了一些扩展HTTP服务能力的手段。

常见的扩展方法示例:(当前还没用过)

[LOCK]:允许用户锁定资源,可以在编辑某个资源的时候让资源锁定,使其他人无法修改

[MKCOL]:允许用户创建资源

[COPY]:便于在服务器上复制资源

[MOVE]:在服务器上复制资源

HTTP请求头、相应头(首部)

首先看一下首部的结构

<headers>{
请求/响应首部字段
通用首部字段
实体首部字段
}

HTTP报文首部作用

在客户端和服务端以HTTP协议进行通信的时候,无论是请求还是响应都会使用首部字段,起到传递额外信息的作用,包括报文主体大小,所使用语言,认证信息内容等等。

HTTP报文首段字段结构

首部字段由字段名和字段值构成,格式:【首部字段名字段值

另外单个HTTP首部字段可以有多个值,值之间用逗号(,)间隔:

Keep-Alive:timeout=15,max=100

HTTP首部结构详解:

参见这篇博客


4、在API发布后,调试时弹出“您正在调试XXX的发布版本。。。。调试体验会降级。。。例如不会命中断点。”

这是一个很简单的问题。

在你把程序发布后,程序会自动把调试处的解决方案配置自动由【Debug】变更为【Release】,改回来就好了。


5、设置防火墙,实现局域网访问你的IIS。

首先要看清自己的IIS使用的是什么端口。

查看方式:打开IIS,点击对应的网站,点击高级设置,看【绑定】一栏,里面会有IP和端口的绑定,端口默认为80,这个绑定在新建网站时可以改变。

然后打开【网络和共享中心】-左下角【windows防火墙】-左侧【高级设置】,在【入站规则】和【出站规则】处新建一个对【80端口】(你设定的端口号)放行的规则即可。即可。


6、JSON保存为字符串后,出现的斜杠问题,以及该如何处理这个斜杠.

因为JSON传回来时,其中的【"】是通过转义字符【//】来处理的,如果直接将JSON字符串打印出来会有很多的斜杠,类似于:

string s1 ="[{\"ID\":\"99d2a341-ea2e-4f04-b4f4-623153d64336\",\"Name\":\"王五\",\"TotalScores\":80,\"工作效率\":\"B\".........}

这个时候固然可以直接进行反斜杠处理从而去除斜杠,但这样很费事且容易将本来具有的斜杠字符一起去除。

所以比较好的解决办法是直接反序列化处理。

比如这里在做WebAPI,比如这个方法:

 // GET  APITest1/Test1/Action/5
        public string Get(int id)
        {
            string a=某个JSON字符串;
            return a;
        }

它的返回类型是string字符串,在调用时会自动的以xml来展示。

因此我们会看到带有斜杠的JSON文本以XML的文本形式出现。

<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">
"[{\"ID\":\"99d2a341-ea2e-4f04-b4f4-623153d64336\",\"Name\":\"王五\",\"TotalScores\":80,\"工作效率\":\"B\".........}
</string>

如果我们让Webapi直接用JSONResult来返回数据就是正常的JSON文本了,也不会嵌套在XML中。

[HttpGet]
        public JsonResult<List<Student>> Get()
        {
            string sqlStr = "GetAllUserDetails";
            List<Student> students = new List<Models.Student>();
            students = sqlCommandHelper.GETStudentMessage(sqlStr, -1);
            return Json<List<Student>>(students);
        }

7、WebApi的传参数问题,如何给Webapi传递参数

首先确定的一件事:Webapi接受的参数也好,传出的数据也好,最好是JSON格式。

其次,是在api中设置好参数类型,因为我在调用时使用的是HttpClient(里面的多数请求方法要求只有一个参数),因此api只能一个参数来接收传递过来的数据。

这个时候JSON的好处就体现了,因为可以用一串JSON字符串来传递多个键值对。当然,你也可以直接传递一个类,不过这样一来API感觉就没有那么灵活。

json数据当然可以直接用【string】,也可以用【dynamic】,它可以在你运行时解析你的对象,即动态解析。

例如:

 public bool Post2([FromBody]dynamic test)
 {
    bool judge = false;
    if (test.name != "q") judge = true;
    return judge; 
}

这里test会被动态解析,直接读出它的属性"name"。

上面这些是API中的参数类型设置,下面将说我在调用API时的参数传递。

例:

[HttpPost]
public async System.Threading.Tasks.Task<ActionResult> DelDetaile(FormCollection f)
{
   actionAPI.BaseAddress = new Uri("http://10.194.46.210/actionapi/Student3API/Delete");
   var responseMessage = await actionAPI.PostAsJsonAsync(actionAPI.BaseAddress.ToString(),Convert.ToInt16(f["Id"]));
   bool judgeWriteStudentMessage = responseMessage.IsSuccessStatusCode;
   if (judgeWriteStudentMessage == false)
       { return View("FalseOperation"); }
   else
       { return View("SuccessfulOperation"); }

调用时我使用了HttpClient,它有个好处是所有的方法都是异步的,且它所有传递的参数都会自动转换为JSON类型。

单独将这句摘出来。

actionAPI.PostAsJsonAsync(actionAPI.BaseAddress.ToString(),Convert.ToInt16(f["Id"]));

除了使用HttpClient外,还有一种方法,就是借助HttpWebRequestHttpWebResponse

用到时如下调用,URL是api地址,strpostdata是你要传递的数据,会在这里自动转换为JSON。

 public string OpenReadWithHttps(string URL, string strPostdata)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
            request.CookieContainer = new CookieContainer();
            request.Method = "POST";
            request.ContentType = "application/json";
            byte[] buffer = Encoding.Default.GetBytes(strPostdata);
            request.ContentLength = buffer.Length;
            request.GetRequestStream().Write(buffer, 0, buffer.Length);
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.Default);
            var end = reader.ReadToEnd();

            return end.ToString();
        }

 


8、如何对API进行测试?如何给POST等方式进行测试?

第一:推荐使用postman工具(谷歌浏览器直接由对应的插件)

这个小工具可以对任何api进行访问测试,具体的使用方法下载后一眼就能看明白,注意不需要注册。

第二:使用NuGet使用大佬的程序包:【WebApiTestClient 

使用教程


9、API访问时出现httpput和httpdelete的谓词问题,该如何处理。

这个问题往往是出现在需要调用httpdeletehttpput请求。

首先要知道的是,如果你用form表单传递这两种请求,默认会变成get的请求方式,这是因为老的html不支持get和post以外的请求方式,html5后才支持。目前我没找到办法,似乎添加请求头可以????

使用ajax传递这两种请求倒是可以通过。

总之,如果出现这个问题……推荐使用post方式……

如果特别想解决这个问题……看论坛似乎在IIS和api的web.config中进行修改也可以实现……参考这个


10、如何给APIhelp页面添加注释:

这个暂时先空着,遇到了问题没有解决。


11、此请求已被阻止,因为当用在 GET 请求中时,会将敏感信息透漏给第三方网站

这个问题主要出现在给前台ajax返回JsonResult时。

解决方法:返回时加上对客户端get方式的允许即可。

return new JsonResult() {
                Data=student,
                JsonRequestBehavior = JsonRequestBehavior.AllowGet
            };

 

;