VS2019下開發和調用webapi


本文力求用最簡的描述,演示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行。

至此,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的方法都是異步方法),大家自行學習或忽略。


 關於跨域:

無論是webapi還是mvc仿webapi,默認都不許跨網站get訪問(即跨域)(實測使用post方式調用webapi,可以跨域,不知道是不是bug)。

如果要實現跨域,請參閱微軟官方文檔:https://docs.microsoft.com/zh-cn/aspnet/core/security/cors?view=aspnetcore-5.0

在官方說明的基礎上,快速實現跨域,操作如下:

1、在startup.cs文件里,配置方法中,路由之后,節點之前,添加跨域

 1 public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
 2         {
 3             if (env.IsDevelopment())
 4             {
 5                 app.UseDeveloperExceptionPage();
 6             }
 7 
 8             app.UseRouting();
 9             app.UseCors();
10             app.UseAuthorization();
11 
12             app.UseEndpoints(endpoints =>
13             {
14                 endpoints.MapControllers();
15             });
16         }

如上第九行代碼

2、在webapi控制器里引用跨域名稱空間

using Microsoft.AspNetCore.Cors;

3、在要跨域的類或方法前面,添加跨域特性

1 [Route("api/[controller]/[action]")]
2     [ApiController]
3     [EnableCors]
4     public class HomeController : ControllerBase
5     {

如上第三行

 (完)


 

1. 應該先介紹一下webapi是基於restful規范來實現的,然后解釋一下restful是什么規范 2. 可以把OpenAPI給選中,在項目運行起來后,能看到swagger調用頁面 3. 在第一點中的restful會提到get,post,put,delete,然后介紹什么交冪等性,這四個方法所用的場景是什么。 4. 不建議用httpwebrequest這種類,用httpclient。5. 認證知識也要提及,這一塊內容可以先用jwt作為樣例簡單的介紹,這部分內容可以后續專門章節展開。

以上建議來自技術群友:2003-夜空*星星(qq58926957),感謝寶貴意見!


 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM