Web Api
API问题集:
1.序列化错误

系统NotSupportedException:系统的序列化和反序列化。“类型”实例不受支持,应避免使用,因为它们可能会导致安全问题。路径:$。数据柱。数据类型。
--->系统。NotSupportedException:系统的序列化和反序列化。“类型”实例不受支持,应避免使用,因为它们可能会导致安全问题。
解决方法:
使用NuGet下载Microsoft.AspNetCore.Mvc.NewtonsoftJson(3.1.5.0),在startup.cs文件中配置:
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { //json序列化 services.AddControllers() .AddNewtonsoftJson(op => { //Newtonsoft.Json // op.SerializerSettings.DateFormatString = "yy-MM-dd HH:mm"; op.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented; });
注意:AddNewtonsoftJson在3.1.5.0版本中才有,其他版本没有;
一:Web API介绍
前言
1.http是一种基于应用层的一种超文本传输协议(HyperText Transfer Protocol);
2.HTTP的特点:简单快速、B/S模式、无连接、无状态、多数据传输格式;
(1).简单快速:http协议简单,客户端向服务器发送请求时,只需传送请求方法和路径即可,传送的内容简单轻量级,减少传输带宽,速度快;
(2).B/S模式:B/S模式(Browse/Server模式),也叫客户端(Google,firefox,ie)/服务器模式,在Web开发中,基本都是基于B/S模式;
(3)无连接:http协议本身是无连接的,虽然http使用了tcp连接,但通信双方在交换http保温之前不需要先建立http连接;
(4)无状态:无状态是指协议对于事务处理没有记忆能力,也就是说,同一个客户第二次访问同一个服务器上的页面时,服务器的响应与第一次被访问的相同;
3.三次握手
每一次TCP连接都需要三个阶段:建立连接、传送数据和释放连接。三次握手就发生在建立连接阶段;
(1) 第一次握手:客户端请求连接。客户端向服务器发出请求连接(client向server发送sys=j的包),进入发送请求状态(syn_sent状态),并等待服务器确认。
(2) 第二次握手:服务器接受请求并向客户端发出确认信息。当服务器收到syn包后,先确认客户的syn(ack=j+1),同时也需要发布一个syn包(syn=k),即syn+ack包,此时服务器进入syn_recv状态。
(3) 第三次握手:建立连接。客户端收服务器的syn+ack包后,向服务器发棕确认包ack(ack=k+1),当此包发送完毕后,客户端和服务器就进入了连接状态(连接成功),完成三次握手;
4.四次挥手
TCP连接是全双工的,因此每个方向都必须单独进行关闭。当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接,收到一个 FIN只意味着这一方向上没有数据流动,
一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
(1).TCP客户端发送一个FIN,用来关闭客户到服务器的数据传送。
(2)服务器收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号。
(3)服务器关闭客户端的连接,发送一个FIN给客户端。
(4)客户端发回ACK报文确认,并将确认序号设置为收到序号加1。
1. 什么是Web API
既可以对接各种客户端(浏览器、移动设备),构建http服务的框架。
Web API是一个比较 宽泛的概念。这里我们提到Web API特指ASP.NET Core Web API。
Web API在ASP.NET完整框架中地位如下图,与SignalR一起同为构建Service的框架。Web API负责构建http常规服务,而SingalR主要负责的是构建实时服务,例如股票,聊天室,在线游戏等实时性要求比较高的服务。

2. 为什么要用Web API?
Web API最重要的是可以构建面向各种客户端的服务。另外与WCF REST Service不同在于,Web API利用Http协议的各个方面来表达服务(例如 URI/request response header/caching/versioning/content format),因此就省掉很多配置。
当遇到一下情况,就需要考虑使用Web API了:
- 需要Web Service但是不需要SOAP.
- 需要在已有的WCF服务基础上建立non-soap-based http服务。
- 只想发布一些简单的http服务,不想使用相对复杂的WCF配置。
- 发布的服务可能带来宽受限的设备访问。
- 希望使用开源框架,关键时候可以自己调试或自定义一下框架。
3. 功能简介
1. 支持基于Http verb (GET, POST, PUT, DELETE)的CRUD (create, retrieve, update, delete)操作
通过不同的http动作表达不同的含义,这样就不需要暴露多个API来支持这些基本操作。
2. 请求的回复通过Http Status Code表达不同含义,并且客户端可以通过Accept header来与服务器协商格式,例如你希望服务器返回JSON格式还是XML格式。
3. 请求的回复格式支持 JSON,XML,并且可以扩展添加其他格式。
4. 原生支持OData。
5. 支持Self-host或者IIS host。
6. 支持大多数MVC功能,例如Routing/Controller/Action Result/Filter/Model Builder/IOC Container/Dependency Injection。
4. WCF 、WebService和WebAPI区别
WCF
- 基于SOAP协议,数据格式是XML
- web service 进化版,支持HTTP,HTTPS, TCP ,Named Pipes,MSMQ
- 配置繁琐
- 部署在应用程序,IIS,windows 服务中。
Web service
- 基于SOAP协议,数据格式是XML
- 支持HTTP协议
- 不是开源的,可以被任何了解XML的人使用
- 只能部署在IIS上
Web API
- 简单的HTTP服务的新框架
- 在.net平台上可以Web API 是一个开源的,理想的可以构建Rest-ful服务的技术
- 可以使用HTTP的全部特点
- 也支持MVC特征(路由,控制器,Filter,模型绑定,控制反转IOC ,依赖注入DI,单元测试),这些使程序更简单,更健壮
- 可以部署在应用程序和IIS上
- 轻量级框架,支持限制宽带的设备(智能手机)支持较好
- Response可以被Web API的MediaTypeFormatter转换成Json、XML 或者任何你想转换的格式。
5.Web API与MVC的区别

(1) MVC主要是构建网站,既关心数据也关心页面展示,而Web API只关心数据;
(2) Web API支持格式协商,客户端可以通过Accept header通知服务器期望的格式;
(3) Web API支持Self Host,MVC目前不支持;Web API通过不同的http verb表达不同的动作(CRUD),MVC则通过Action名字表达动作
(4) Web API内建于ASP.NET System.Web.Http命名空间下,MVC位于System.Web.Mvc命名空间下,因此model binding/filter/routing等功能有所不同
(5) 最后,Web API非常适合构建移动客户端服务
二:创建Web Api项目
2.1.创建Web Api(1)
2.1.1.创建项目
第一步:

第二步:


注意:这里目标框架为.NET 5.0才能支持OpenAPI(集成),不然无法启用!
OpenAP集成:

2.1.2.项目结构
Progranm.cs
Program类下的Main方法就是整个程序的入口,Main方法负责配置和运行整个Web程序。
由于这是一个Web项目,所以我们还需要一个宿主(Host),这个宿主就是由下面的CreateHostBuilder方法来负责创建的。该方法首先会创建出一个实现了IHostBuilder接口的类(HostBuilder)的实例,然后调用它的Build方法来创建宿主(类型为Host,实现了IHost接口),最后调用宿主上面的Run方法来运行程序。
Startup.cs
我们看到IConfiguration被注入了,这样就允许我们使用配置信息了,例如appsettings.json里面的配置信息。
ConfigureServices方法
这个方法负责向服务容器里面注册服务,已注册的服务可以通过依赖注入的方式在整个应用程序的其它地方进行使用。这里的服务是一个比较广义的概念,它就是一个在整个程序中做一些通用性操作的组件。
Configure方法
这个方法使用到了在ConfigureServices方法里面注册和配置的服务,所以这个方法是在ConfigureServices方法之后被调用的。
Configure方法是用来指定ASP.NET Core Web程序是如何响应每一个HTTP请求的。换句话说,也就是我们在这里配置请求的管道,配置的方法就是在这里添加很多中间件(Configure方法里面每一个app.UseXxx就是添加一个中间件,可以查看中间件的官方文档来了解更多)。
2.1.3.获取配置文件信息
1.配置信息

2.实体类
/// <summary> /// 获取配置文件内容 /// </summary> public class GetConfigData { public static string name = string.Empty; public static string age = string.Empty; public static string wight = string.Empty; public static string higt = string.Empty; public static void SetConfig(IConfiguration configuration) { name = configuration.GetSection("name").Value; age = configuration.GetSection("age").Value; wight = configuration.GetSection("data").GetSection("wight").Value; higt = configuration.GetSection("data").GetSection("higt").Value; } }
3.修改Startup.cs文件

4.测试


2.2.创建Web Api(2)
2.2.1项目搭建

选择API模式,把底部的https去掉勾选,点击确定

整体文档结构非常简洁:

直接运行项目,浏览器出现一下情况则搭建成功:

2.2.2.编写代码
1.修改Controller中的ValuesController.cs
namespace TESTAPI.Controllers { [Route("api/[controller]/[action]")] //一级路由 [ApiController] public class ValuesController : ControllerBase { //示例代码1 [HttpGet("{name}")] //通过get请求的子路由,如果这里不写入()里面的话,则URL采用api/values/SignIn?name=value的方式传值 //如果写在()里面,则采用api/values/SignIn/value的方式传值 public string SignIn(string name) { return name + "已成功签到!"; } //示例代码2 [HttpGet("{className}/{userName}/{userCode}")] public string SignIn(string className, string userName, string userCode) { return "班级为:" + className + "的" + userName + "已完成签到!学号是:" + userCode; } } }
2.2.3.效果
直接运行启动,默认路径是没有内容的:



2.2.4.调整ip
1.通过命令:ipconfig 查找自己的IP地址;---10.222.216.60
2.右击项目——在资源管理器中打开文件夹:

找到该文件,并打开(注意这里一开始是没有这个vs文件夹的,需要项目用过IIS调试后才会生成。)
3.搜索IIS的默认端口号:10473,并修改成下面代码:

4.如果出现一下错误,但是localhost可以访问:

可以试下之一:
1、重启VisualStudio软件
2、把防火墙设置成允许52118端口数据出入,或者把防火墙关闭;
3、注销电脑
4、重启电脑
最终效果如下:

2.3.创建Web Api(3)
2.3.1 搭建项目



2.3.2 添加模型model
模型是表示应用程序数据的一种对象。ASP.NET Web API可以自动地把模型序列化成JSON、XML、或某些其它格式,然后这些序列化数据写到HTTP响应的消息体中。只要一个客户端能够读取这种序列化格式,它就可以对这种对象进行反序列化。大多数客户端都能够解析XML或JSON。另一方面,通过设置HTTP请求消息中的Accept报头,客户端能够指示它所希望的是哪一种格式。
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace TestAPI.Models { public class Product { public int Id { get; set; } public string Name { get; set; } public string Category { get; set; } public decimal Price { get; set; } } }
2.3.3.添加控制器Controller
控制器是一种处理HTTP请求的对象。“新项目”向导在创建该项目时为你创建了两个控制器。要看到它们,在“解决方案资源管理器”中展开Controllers文件夹。
HomeController是传统的ASP.NET MVC控制器。它负责对网站的HTML页面进行服务,且与Web API无直接关系。
ValuesController是一个例子型的WebAPI控制器。
如果曾使用过ASP.NET MVC,对控制器已有所熟悉。Web API中的控制器是类似的,只不过它们派生于ApiController类,而不是Controller类。你要注意到的第一个主要区别是Web API控制器上的动作并不返回视图,而返回的是数据。

删除ValuesController控制器,在新建一个ProductController控制器:
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Web.Http; using TestAPI.Models; namespace TestAPI.Controllers { public class ProductController : ApiController { //为了保持示例简单,产品被存储在该控制器类的一个固定数组中。实际中,你会查询一个数据库,或使用某些其它外部数据源。 Product[] products = new Product[] { new Product { Id = 1, Name = "Tomato Soup", Category = "Groceries", Price = 1 }, new Product { Id = 2, Name = "Yo-yo", Category = "Toys", Price = 3.75M }, new Product { Id = 3, Name = "Hammer", Category = "Hardware", Price = 16.99M } }; //GetAllProducts方法以IEnumerable<Product>类型返回产品的完整列表 public IEnumerable<Product> GetAllProducts() { return products; } //GetProductById方法通过ID查询一个单一产品 public Product GetProductById(int id) { var product = products.FirstOrDefault((p) => p.Id == id); if (product == null) { throw new HttpResponseException(HttpStatusCode.NotFound); } return product; } //GetProductsByCategory方法返回指定类别的全部产品。 public IEnumerable<Product> GetProductsByCategory(string category) { return products.Where( (p) => string.Equals(p.Category, category, StringComparison.OrdinalIgnoreCase)); } } }
该控制器上的每一个方法都映射到一个URI中:
|
Controller Method控制器方法 |
URL |
|
GetAllProducts |
/api/product |
|
GetProductById |
/api/product/id |
|
GetProductsByCategory |
/api/product/?category=category |
2.3.4 启动项目

该首页是一个ASP.NET MVC视图,它是由HomeControllers类返回的。为了调用Web API,我们必须使用前面列出的URI之一。例如,要得到全部产品列表,浏览http://localhost:xxxx/api/product/。
确切的结果取决于你所使用的浏览器。Internet Explorer(IE浏览器)将提示你是否打开或保存一个名称为products的“文件”;
这个“文件”实际只是HTTP的响应体。点击“打开”按钮,在“打开”对话框中选择Notepad(记事本),点击“OK”,并在提示出现时点击“打开”。该文件应当包含产品数组的一个JSON表达:

另一方面,Mozilla Firefox将在浏览器中以XML形式显示此列表

访问:http://localhost:11191/api/product?category=hardware

访问:http://localhost:11191/api/product/1

2.3.5.以javaScript和jQuery调用Web API

<!DOCTYPE html> <html lang="en"> <head> <title>ASP.NET Web API</title> <link href="http://www.cnblogs.com/Content/Site.css" rel="stylesheet" /> <script src="http://www.cnblogs.com/Scripts/jquery-1.7.1.min.js" type="text/javascript"></script> <script type="text/javascript"> $(document).ready(function () { // 发送 AJAX 请求,响应将是一个JSON对象的数组。getJSON的第二个参数是在请求成功完成时调用的一个回调函数。 $.getJSON("api/product/", function (data) { // 成功时, 'data'含有一组产品列表. $.each(data, function (key, val) { //格式化文本,以便显示. var str = val.Name + ': $' + val.Price; // 添加一个产品列表项. $('<li/>', { text: str }) .appendTo($('#products')); }); }); }); function find() { var id = $('#prodId').val(); $.getJSON("api/product/" + id, function (data) { var str = data.Name + ': $' + data.Price; $('#product').text(str); }) .fail( function (jqXHR, textStatus, err) { $('#product').text('Error: ' + err); }); } </script> </head> <body id="body"> <div class="main-content"> <div> <h1>All Products</h1> <ul id="products" /> </div> <div> <label for="prodId">ID:</label> <input type="text" id="prodId" size="5" /> <input type="button" value="Search" onclick="find();" /> <p id="product" /> </div> </div> </body> </html>
2.3.6效果

输入ID获取一个相应产品的价格:

2.4 增删改查CRUD
2.4.1创建项目
如上所述
2.4.2创建model
namespace ProductTest.Models { public class Product { public int ProductID { get; set; } public string ProductName { get; set; } public decimal Price { get; set; } public int Count { get; set; } public string Description{get; set;} } }
2.4.3.创建Contorller
using ProductTest.Models; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Web.Http; namespace ProductTest.Controllers { public class ProductsController : ApiController { // Mock product list static List<Product> productMockList = initProductMockDataList(); private static List<Product> initProductMockDataList() { return new List<Product>() { new Product {ProductID=1,ProductName="Product A",Price=1000000,Count=5,Description="Description A"}, new Product {ProductID=2,ProductName="Product B",Price=200000,Count=2,Description="Description B"}, new Product {ProductID=3,ProductName="Product C",Price=500000,Count=8,Description="Description C"}, new Product {ProductID=4,ProductName="Product D",Price=80000,Count=10,Description="Description D"}, new Product {ProductID=5,ProductName="Product E",Price=300000,Count=3,Description="Description E"} }; } // GET api/products public IEnumerable<Product> GetAllProducts() { return productMockList; } // GET api/products/id public Product GetProdcut(int id) { return productMockList.Where(p => p.ProductID == id).FirstOrDefault(); } // POST api/products public void CreateProduct([FromBody]Product product) { var lastProduct = productMockList.OrderByDescending(p => p.ProductID).FirstOrDefault(); int newProductID = lastProduct.ProductID + 1; product.ProductID = newProductID; productMockList.Add(product); } // PUT api/products public void UpdateProduct(int id, [FromBody]Product product) { var currentProduct = productMockList.Where(p => p.ProductID == id).FirstOrDefault(); if (currentProduct != null) { foreach (var item in productMockList) { if (item.ProductID.Equals(currentProduct.ProductID)) { item.ProductName = product.ProductName; item.Price = product.Price; item.Count = product.Count; item.Description = product.Description; } } } } // DELETE api/products public void DeleteProduct(int id) { var product = productMockList.Where(p => p.ProductID == id).FirstOrDefault(); if (product != null) { productMockList.Remove(product); } } } }
2.4.4.页面布局index.cshtml
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Index</title> <script src="http://libs.baidu.com/jquery/1.9.1/jquery.min.js" type="text/javascript"></script> </head> <body> <p><h2>ASP.NET Web API (CRUD)</h2></p> <div> <input id="btnGetProductList" name="btnGetProductList" type="button" value="Get Product List" /> <div id="productsBlock" style="padding-top:10px;display:none;"> <div style="padding-left:5px;">Product List</div> <div id="products"></div> <div> <input id="btnCreateProduct" name="btnCreateProduct" type="button" value="Create Product" /> </div> <div id="editProductBlock" style="padding:10px;width:20%;border:1px solid green;display:none;"> <div id="typeBlock" style="font-weight:bold;">Edit Product</div> <table> <tr><td>Product ID:</td><td><input id="txtProductID" name="txtProductID" type="text" disabled /></td></tr> <tr><td> Product Name:</td><td><input id="txtProductName" name="txtProductName" type="text" /></td></tr> <tr><td>Count:</td><td><input id="txtCount" name="txtCount" type="text" /></td></tr> <tr><td> Price:</td><td><input id="txtPrice" name="txtPrice" type="text" /></td></tr> <tr><td> Description:</td><td><input id="txtDescription" name="txtDescription" type="text" /></td></tr> </table> <div style="padding-top:5px;"> <div id="message" style="color:green;"></div> <input id="btnSave" name="btnSave" type="button" value="Save" /> <input id="btnCreate" name="btnCreate" type="button" value="Create" /> </div> </div> </div> </div> <script> // Click get product list $('#btnGetProductList').click(function () { LoadProductList(); }); // Load product list function LoadProductList() { $.ajax({ url: '/api/products', contentType: 'application/html; charset=utf-8', type: 'GET', dataType: 'json' }).success(function (result) { $('#productsBlock').show(); DisplayProductList(result); }).error(function (data) { alert(data); }); } // Display product list function DisplayProductList(result) { var productTable = $("<table cellpadding='5' cellspacing='5'></table>"); var productTableTitle = $("<tr style='background-color:#7FBA00;'><th>Product ID</th><th>Product Name</th><th>Price</th><th>Count</th><th>Description</th><th></th></tr>"); productTableTitle.appendTo(productTable); for (var i = 0; i < result.length; i++) { var productTableContent = $("<tr style='background-color: #7FBA00; color: white;'><td>" + result[i].ProductID + "</td><td>" + result[i].ProductName + "</td><td>" + result[i].Price + "</td><td>" + result[i].Count + "</td><td>" + result[i].Description + "</td>" + "<td><a href='#' onclick='ViewProduct(" + result[i].ProductID + ")'>View</a></td></tr>"); productTableContent.appendTo(productTable); } $('#products').html(productTable); } // View product function ViewProduct(productId) { $('#editProductBlock').show(); $('#btnCreate').hide(); $.ajax({ url: '/api/products/' + productId, contentType: 'application/html;charset=utf-8', type: 'GET' }).success(function (result) { if (result != null) { $("#txtProductID").val(result.ProductID); $("#txtProductName").val(result.ProductName); $("#txtCount").val(result.Count); $("#txtPrice").val(result.Price); $("#txtDescription").val(result.Description); } }).error(function (data) { alert(data); }); } $('#btnCreateProduct').click(function () { $('#editProductBlock').show(); $('#btnCreate').show(); $('#btnSave').hide(); $('#typeBlock').html("Create Product"); }); // Create product $('#btnCreate').click(function () { var product = { ProductID: 0, ProductName: $('#txtProductName').val(), Price: $('#txtPrice').val(), Count: $('#txtCount').val(), Description: $('#txtDescription').val() }; $.ajax({ url: '/api/products/', type: 'POST', data: JSON.stringify(product), contentType: 'application/json' }).success(function (result) { LoadProductList(); $('#message').html("Product create success."); }).error(function (data) { alert(data); }); }); // Update product $('#btnSave').click(function () { var product = { ProductID: $('#txtProductID').val(), ProductName: $('#txtProductName').val(), Price: $('#txtPrice').val(), Count: $('#txtCount').val(), Description: $('#txtDescription').val() }; $.ajax({ url: '/api/products/' + $('#txtProductID').val(), type: 'POST', data: JSON.stringify(product), contentType: 'application/json' }).success(function (result) { LoadProductList(); $('#message').html("Product save success."); }).error(function (data) { alert(data); }); }); // Display product list function DisplayProductList(result) { var productTable = $("<table cellpadding='5' cellspacing='5'></table>"); var productTableTitle = $("<tr style='background-color:#7FBA00;'><th>Product ID</th><th>Product Name</th><th>Price</th><th>Count</th><th>Description</th><th></th></tr>"); productTableTitle.appendTo(productTable); for (var i = 0; i < result.length; i++) { var productTableContent = $("<tr style='background-color: #7FBA00; color: white;'><td>" + result[i].ProductID + "</td><td>" + result[i].ProductName + "</td><td>" + result[i].Price + "</td><td>" + result[i].Count + "</td><td>" + result[i].Description + "</td>" + "<td><a href='#' onclick='ViewProduct(" + result[i].ProductID + ")'>View</a> <a href='#' onclick='DeleteProduct(" + result[i].ProductID + ")'>Delete</a></td></tr>"); productTableContent.appendTo(productTable); } $('#products').html(productTable); } // Delete product function DeleteProduct(productID) { $.ajax({ url: '/api/products/' + productID, type: 'DELETE', }).success(function (result) { LoadProductList(); $('#message').html("Product delete success."); }).error(function (data) { alert(data); }) } </script> </body> </html>
2.4.5 效果



浙公网安备 33010602011771号