ASP.NET Core 2.2 基礎知識(十三) WebAPI 概述


我們先創建一個 WebAPI 項目,看看官方給的模板到底有哪些東西

 

官方給出的模板:

    [Route("api/[controller]")]
    [ApiController]
    public class ValuesController : ControllerBase
    {
        // GET api/values
        [HttpGet]
        public ActionResult<IEnumerable<string>> Get()
        {
            return new string[] { "value1", "value2" };
        }

        // GET api/values/5
        [HttpGet("{id}")]
        public ActionResult<string> Get(int id)
        {
            return "value";
        }

        // POST api/values
        [HttpPost]
        public void Post([FromBody] string value)
        {
        }

        // PUT api/values/5
        [HttpPut("{id}")]
        public void Put(int id, [FromBody] string value)
        {
        }

        // DELETE api/values/5
        [HttpDelete("{id}")]
        public void Delete(int id)
        {
        }
    }

同時,在 Startup 類中注冊了 Mvc 中間件.

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseMvc();
        }

 

實際上, 繼承 ControllerBase ,特性 [Route] [ApiController] 都是為了提供一些便利功能,一個最"輕量"的 WebAPI 是這樣的:

新建一個 TestController:

    public class TestController
    {
        public string Get()
        {
            return "hello world";
        }
    }

啥也沒有,很干凈.

注冊 Mvc 中間件時添加路由:

            //app.UseMvc(route => { route.MapRoute("default", "api/{controller}"); });//不能這樣寫,這種最輕量的方式,不支持 Restful 風格的請求方式
            app.UseMvc(route => { route.MapRoute("default", "api/{controller}/{action}"); });

測試:

 

當然,我們也可以不在 注冊 Mvc 中間件的時候添加路由,還是像官方推薦的那樣,在控制器上利用路由特性,這種方式就支持 Restful 風格的請求方式了.

    [Route("api/[controller]")]
    public class TestController
    {
        public string Get()
        {
            return "hello world";
        }
    }

 

 

那 ControllerBase 提供了哪些便利功能呢?看源碼就明白了:

截一小部分圖:

 

[ApiController] 特性則提供如下便利功能:

綁定源參數推理

當沒有[ApiController]特性時,參數綁定都默認從QueryString獲取.假設有如下控制器和實體類:

    [Route("api/[controller]")]  
    public class TestController
    {
        public string Get(Person person, int id, string name, Student student)
        {
            var temp = new { person, id, name, student };
            return JsonConvert.SerializeObject(temp);
        }
    }
    public class Person
    {
        public int Id { get; set; }

        public string Name { get; set; }
    }

    public class Student
    {
        public int Id { get; set; }

        public string Name { get; set; }
    }

請求結果:

 

可以看到,所有的參數都綁定上了.

但工作中,復雜類型我們一般都是 post 提交,寫在 body 里面.

現在我們改用post提交 ,稍微修改一下 action :

    [Route("api/[controller]")]  
    public class TestController
    {
        public string Get(Person person)
        {
            return JsonConvert.SerializeObject(person);
        }
    }

請求:

 

結果沒有綁定上:

 

 這也證明了 在沒有 [ApiController] 特性時,默認都是從 QueryString 獲取參數來綁定.

 上述例子要想綁定成功,需要給 action 的入參打上 [FromBody] 特性:

        public string Get([FromBody]Person person)
        {
            return JsonConvert.SerializeObject(person);
        }

請求結果:

 

 

ASP.NET Core 的綁定特性似乎比 ASP.NET 多了一些,下面是官網給的:

 

如果 Controller 上應用了 [ApiController] 特性,那么框架會根據參數類型自動選擇綁定特性.

現在我們給 TestController 應用 [ApiController] 特性,同時刪掉 Action 上的 [FromBody] 特性:

    [Route("api/[controller]")]
    [ApiController]
    public class TestController
    {
        public string Get(Person person)
        {
            return JsonConvert.SerializeObject(person);
        }
    }

 

 請求結果:

 

至於自動選擇綁定特性的規則,我也沒有全部測試,不過我感覺應該和 ASP.NET 是一樣的.

但是,有個地方不一樣,不知道算不算 ASP.NET Core 的優化:

對於之前的 ASP.NET WebAPI ,如果 QueryString 的參數沒有涵蓋 Action 上定義的所有參數,那么是請求不到該 Action 的.

比如,這是一個 ASP.NET WebAPI 控制器,Get 方法定義了兩個入參:

    public class TestController : ApiController
    {
        public string Get(int id,string name)
        {
            var temp = new {id, name};
            return JsonConvert.SerializeObject(temp);
        }
    }

那么,如果我們的 QueryString 只傳遞了其中一個,是請求不到 Get 方法的.

 

但是, ASP.NET Core 是可以的:

 

 

上面提到的這個自動選擇綁定特性的規則,可以通過代碼來禁止(紅色部分,其余的是禁用 [ApiController] 特性提供的其他便利功能的):

            services.AddMvc()
                .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
                .ConfigureApiBehaviorOptions(options =>
                {
                    options.SuppressConsumesConstraintForFormFileParameters = true;
                    options.SuppressInferBindingSourcesForParameters = true;
                    options.SuppressModelStateInvalidFilter = true;
                    options.SuppressMapClientErrors = true;
                    options.ClientErrorMapping[404].Link =
                        "https://httpstatuses.com/404";
                });

至於其他便利功能,可以查看官方文檔:https://docs.microsoft.com/zh-cn/aspnet/core/web-api/?view=aspnetcore-2.2

其實我寫的這些,大多數都是抄的官方文檔.


免責聲明!

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



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