本文力求用最简的描述,演示C#开发和调用webapi。
所用的例子在.net5以及vs2019 v16.9.3中调试通过。
mvc框架实现的webapi和webapi框架的对比:
学过.net MVC的同学都知道,MVC中,c是可以返回字符串(多数是json字符串)的。因此,在不计体量的情况下,完全可以用mvc来开发webapi。
webapi相对于mvc,最大的好处就是轻量。因为它不用考虑视图等等内容。当然,配置也略微麻烦一点。
webapi实现步骤:
1、新建项目。如下图:
之后的项目配置界面,选择最简内容:
如需勾选什么,自己负责研究清楚。
2、创建项目之后,添加自己的控制器“HomeController”(原有的天气系统可以删除)
此处添加两个方法:index和index1
using Microsoft.AspNetCore.Mvc; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace WebApplication1.Controllers { [ApiController] [Route("[controller]/[action]")] public class HomeController :ControllerBase { public string Index() { return "Hello Katty."; } [HttpGet("{x}")] public string Index1(string x) { return x+ ",Hello Katty."; } } }
要点:
(1)、“[ApiController]”必须有,否则方法不会被识别为webapi方法。加了它以后,“[Route("[controller]/[action]")]”也就必须有了。它表示使用什么样的格式访问对应方法。
想要在多个控制器上使用ApiController属性,微软的建议是:
[ApiController] public class MyControllerBase : ControllerBase { }
然后
[Produces(MediaTypeNames.Application.Json)] [Route("[controller]")] public class PetsController : MyControllerBase
(见:https://docs.microsoft.com/zh-cn/aspnet/core/web-api/?view=aspnetcore-5.0)
(2)、参数可以用示例代码的方式添加。
(3)、控制器继承自ControllerBase而不是Controller。前者是后者的父类,更轻便,没有处理视图的代码。
(4)、要返回json,也可以返回类型是 ActionResult<T> 类型。 ASP.NET Core 自动将对象序列化为 JSON,并将 JSON 写入响应消息的正文中。 此返回类型的响应代码为 200 OK(假设没有未处理的异常)。
(见:https://docs.microsoft.com/zh-cn/aspnet/core/web-api/?view=aspnetcore-5.0)这一点和mvc相同。
3、配置启动文档" Properties\launchSettings.json" 。(可选)
1 { 2 "$schema": "http://json.schemastore.org/launchsettings.json", 3 "iisSettings": { 4 "windowsAuthentication": false, 5 "anonymousAuthentication": true, 6 "iisExpress": { 7 "applicationUrl": "http://localhost:39574", 8 "sslPort": 0 9 } 10 }, 11 "profiles": { 12 "IIS Express": { 13 "commandName": "IISExpress", 14 "launchBrowser": true, 15 "launchUrl": "api/home/index", 16 "environmentVariables": { 17 "ASPNETCORE_ENVIRONMENT": "Development" 18 } 19 } 20 } 21 }
可以在原文件的基础上,修改第15行。
4、修改webapi启动端口(可选)
修改配置文件appsettings.json
1 { 2 "Logging": { 3 "LogLevel": { 4 "Default": "Information", 5 "Microsoft.AspNetCore": "Warning" 6 } 7 }, 8 "AllowedHosts": "*", 9 "Kestrel": { 10 "Endpoints": { 11 "http": { "Url": "http://*:34567" } 12 } 13 } 14 }
添加9-13行。
至此,webapi完成。
//弃用
1、httpwebrequest方式调用webapi:
简单起见,采用控制台方式调用。
****
考虑到日后使用方便,参考了CSDN博主「大海中一粒沙子」的原创文章(原文链接:https://blog.csdn.net/u013730110/article/details/98941934)
新建了restClient类,代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Net;
using System.Web;
namespace ConsoleApp1
{
public class RestClient
{
/// <summary>
/// 请求服务器地址
/// </summary>
private string BaseUri;
public RestClient(string baseUri)
{
this.BaseUri = baseUri;
}
#region Get请求
public string Get(string uri)
{
//先根据用户请求的uri构造请求地址
string serviceUrl = string.Format("{0}/{1}", this.BaseUri, uri);
//创建Web访问对 象
HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(serviceUrl);
//通过Web访问对象获取响应内容
HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse();
//通过响应内容流创建StreamReader对象,因为StreamReader更高级更快
StreamReader reader = new StreamReader(myResponse.GetResponseStream(), Encoding.UTF8);
//string returnXml = HttpUtility.UrlDecode(reader.ReadToEnd());//解决编码问题
string returnXml = reader.ReadToEnd();//利用StreamReader就可以从响应内容从头读到尾
reader.Close();
myResponse.Close();
return returnXml;
}
#endregion
#region Post请求
public string Post(string data, string uri)
{
//先根据用户请求的uri构造请求地址
string serviceUrl = string.Format("{0}/{1}", this.BaseUri, uri);
//创建Web访问对象
HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(serviceUrl);
//数据转成“UTF-8”的字节流
byte[] buf = System.Text.Encoding.GetEncoding("UTF-8").GetBytes(data);
myRequest.Method = "POST";
myRequest.ContentLength = buf.Length;
myRequest.ContentType = "application/json";
myRequest.MaximumAutomaticRedirections = 1;
myRequest.AllowAutoRedirect = true;
//发送请求
Stream stream = myRequest.GetRequestStream();
stream.Write(buf, 0, buf.Length);
stream.Close();
//获取接口返回值
//通过Web访问对象获取响应内容
HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse();
//通过响应内容流创建StreamReader对象,因为StreamReader更高级更快
StreamReader reader = new StreamReader(myResponse.GetResponseStream(), Encoding.UTF8);
//string returnXml = HttpUtility.UrlDecode(reader.ReadToEnd());//解决编码问题
string returnXml = reader.ReadToEnd();//利用StreamReader就可以从响应内容从头读到尾
reader.Close();
myResponse.Close();
return returnXml;
}
#endregion
#region Put请求
public string Put(string data, string uri)
{
//先根据用户请求的uri构造请求地址
string serviceUrl = string.Format("{0}/{1}", this.BaseUri, uri);
//创建Web访问对象
HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(serviceUrl);
//把用户传过来的数据转成“UTF-8”的字节流
byte[] buf = System.Text.Encoding.GetEncoding("UTF-8").GetBytes(data);
myRequest.Method = "PUT";
myRequest.ContentLength = buf.Length;
myRequest.ContentType = "application/json";
myRequest.MaximumAutomaticRedirections = 1;
myRequest.AllowAutoRedirect = true;
//发送请求
Stream stream = myRequest.GetRequestStream();
stream.Write(buf, 0, buf.Length);
stream.Close();
//获取接口返回值
//通过Web访问对象获取响应内容
HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse();
//通过响应内容流创建StreamReader对象,因为StreamReader更高级更快
StreamReader reader = new StreamReader(myResponse.GetResponseStream(), Encoding.UTF8);
//string returnXml = HttpUtility.UrlDecode(reader.ReadToEnd());//解决编码问题
string returnXml = reader.ReadToEnd();//利用StreamReader就可以从响应内容从头读到尾
reader.Close();
myResponse.Close();
return returnXml;
}
#endregion
#region Delete请求
public string Delete(string data, string uri)
{
//先根据用户请求的uri构造请求地址
string serviceUrl = string.Format("{0}/{1}", this.BaseUri, uri);
//创建Web访问对象
HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(serviceUrl);
//把用户传过来的数据转成“UTF-8”的字节流
byte[] buf = System.Text.Encoding.GetEncoding("UTF-8").GetBytes(data);
myRequest.Method = "DELETE";
myRequest.ContentLength = buf.Length;
myRequest.ContentType = "application/json";
myRequest.MaximumAutomaticRedirections = 1;
myRequest.AllowAutoRedirect = true;
//发送请求
Stream stream = myRequest.GetRequestStream();
stream.Write(buf, 0, buf.Length);
stream.Close();
//获取接口返回值
//通过Web访问对象获取响应内容
HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse();
//通过响应内容流创建StreamReader对象,因为StreamReader更高级更快
StreamReader reader = new StreamReader(myResponse.GetResponseStream(), Encoding.UTF8);
//string returnXml = HttpUtility.UrlDecode(reader.ReadToEnd());//解决编码问题
string returnXml = reader.ReadToEnd();//利用StreamReader就可以从响应内容从头读到尾
reader.Close();
myResponse.Close();
return returnXml;
}
#endregion
}
}
实质:利用HttpWebRequest、HttpWebResponse发送和返回内容,由流来读写,自行研究,不再赘述。
****
代码为:
string s;
RestClient restClient = new("http://localhost:28916");
s=restClient.Get("home/index");
Console.WriteLine(s);
s = restClient.Get("home/index1/zs");
Console.WriteLine(s);
运行效果:
webapi:
控制台:
对于post等方式,由于封装类是用json发送数据的,所以思路:传递json过去,webapi反序列化为类。方便起见,可以匿名。(httpclient应该一样,未验证)
webapi:
public int post_Sum(dynamic x)
{
dynamic y = JsonConvert.DeserializeObject<dynamic>(x.ToString());
return y.x * 2;
}
其中两个dynamic换成object一样可以工作,感觉效率还高些。
调用端控制器:
RestClient rc = new RestClient("http://localhost:2674");
ViewData["data"]= rc.Post(JsonConvert.SerializeObject(new { x=15}), "api/values/post_Sum");
return View();
结果:页面显示30。
2、补充调用方式:httpclient
微软推荐用httpclient替代httpwebrequest。网上有人做过测试,后者的效率比前者高。所以,请读者根据实际情况进行取舍。
以下讲述get调用、使用json的post调用、键/值对post调用。
webapi主要代码:
public string Index(int x,int y) { return (x+y).ToString(); } [HttpPost] public string Index1(m a) { return (a.x+a.y).ToString(); }
很简单,m是一个简单类:
public class m { public int x { get; set; } public int y { get; set; } }
调用端为普通mvc,主要代码如下:
1 using Microsoft.AspNetCore.Mvc; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using Newtonsoft.Json; 6 using System.Net.Http; 7 8 namespace WebApplication2.Controllers 9 { 10 public class HomeController : Controller 11 { 12 public IActionResult Index() 13 { 14 ViewData["data"]=get("http://localhost:39574/api/home/index?x=1&y=2"); 15 ViewData["data1"] = post(new { x = 10, y = 15 }); 16 return View(); 17 } 18 public string get(string s) 19 { 20 var hc = new HttpClient(); 21 HttpResponseMessage response = hc.GetAsync(s).Result; 22 response.EnsureSuccessStatusCode();//抛异常 23 string responseBody = response.Content.ReadAsStringAsync().Result; 24 return responseBody; 25 } 26 public string post(object x) 27 { 28 var hc = new HttpClient(); 29 string t = JsonConvert.SerializeObject(x); 30 HttpContent content = new StringContent(t); 31 content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"); 32 HttpResponseMessage response = hc.PostAsync("http://localhost:39574/api/home/index1", content).Result; 33 response.EnsureSuccessStatusCode();//抛异常 34 string responseBody = response.Content.ReadAsStringAsync().Result; 35 return responseBody; 36 } 37 } 38 }
页面上主要显示两个viewdata,很简单。
运行效果:
使用键/值对访问post方法
webapi:
[Route("api/[controller]")] [ApiController] public class ValuesController : ControllerBase { [Route("[action]")] [HttpPost] public int add([FromForm] int x = 1, [FromForm] int y = 2) { return x+y; } }
注意:由于是仿form提交方式post数据过去,所以形参前面必须有“[FromForm]”。否则拿不到数据。
调用端-类:
public class MyHttpClient { static HttpClient _httpClient; public static void init() { _httpClient ??= new HttpClient(); } public static string post(string url) { //application/x-www-form-urlencoded编码传送 //Dictionary<string, string> data = new(); //data.Add("x", "200"); //data.Add("y", "300"); //var formdata = new FormUrlEncodedContent(data); //form-data编码传送 var formdata = new MultipartFormDataContent(); formdata.Add(new StringContent("500"), "y"); formdata.Add(new StringContent("400"), "x"); HttpResponseMessage response = _httpClient.PostAsync(url,formdata).Result; response.EnsureSuccessStatusCode();//抛异常 string responseBody = response.Content.ReadAsStringAsync().Result; return responseBody; } }
调用端-mvc:
public IActionResult Index() { //ViewData["data"] = ":)"; MyHttpClient.init(); ViewData["data"] = MyHttpClient.post("http://localhost:58397/api/values/add"); return View(); }
结果正确。
mvc控制器里还用到了异步知识(没办法,httpclient的方法都是异步方法),大家自行学习或忽略。
(完)
1. 应该先介绍一下webapi是基于restful规范来实现的,然后解释一下restful是什么规范 2. 可以把OpenAPI给选中,在项目运行起来后,能看到swagger调用页面 3. 在第一点中的restful会提到get,post,put,delete,然后介绍什么交幂等性,这四个方法所用的场景是什么。 4. 不建议用httpwebrequest这种类,用httpclient。5. 认证知识也要提及,这一块内容可以先用jwt作为样例简单的介绍,这部分内容可以后续专门章节展开。
以上建议来自技术群友:2003-夜空*星星(qq58926957),感谢宝贵意见!