ASP.NET WebApi [FromBody]獲取對象值一直為null的問題


解決問題前,首先確定[FormBodyAttribute]的定義以及功能范圍,相關資料:

https://docs.microsoft.com/en-us/aspnet/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api

其實文中已經講得足夠詳細,一般來講FormUri獲取參數不會存在什么疑惑,但在不了解規則的情況下如何設置和獲取FormBody標識的值卻有些迷惑:我到底該怎么傳遞參數api才能夠獲取到參數?很多文章給出的解決方案是利用="json string"這樣的方式進行提交,但實在太別扭了。這樣的代碼寫出去會被打吧…所以,到底該怎么請求呢?

如果你仔細閱讀過文章,相信你應該注意到了這一段:

When a parameter has [FromBody], Web API uses the Content-Type header to select a formatter. 

意思是對於被標記為FromBody的parameter,WebApi默認會根據Content-Type中選擇格式化方法。由於Web程序中常常使用JSON方式傳遞數據,所以這里只針對Content-Type="application/json"的請求進行分析。接着看下一句:

In this example, the content type is "application/json" and the request body is a raw JSON string (not a JSON object).

其實到這里已經給出解決方案了,即Content-Type="application/json"的請求都需要將參數轉換為JSON string,而非JSON Object.

接下來代碼說話的時間到了:

1)創建一個復雜對象的實體類DataParameter:

    [Serializable]
    public class DataParameter
    {
        public DataParameter()
        {
            this.DataItems = new List<DataItemParameter>();
        }

        public int Id { get; set; }

        public List<DataItemParameter> DataItems { get; set; }
    }

    [Serializable]
    public class DataItemParameter
    {
        public DataItemParameter() { }
        public DataItemParameter(int id, string name)
        {
            this.Id = id;
            this.Name = name;
        }

        [Range(10, 20)]
        public int Id { get; set; }

        [Required]
        public string Name { get; set; }

        public List<DataItemProperty> Properties { get; set; }
    }

    [Serializable]
    public class DataItemProperty
    {
        public string Name { get; set; }
    }

2)創建一個ApiController的派生類,並創建兩個接收數據並返回的Action:

[RoutePrefix("api/data")]
    public class DataController : ApiController
    {
        /// <summary>
        /// 復雜數據類型
        /// </summary>
        /// <param name="parameter">Complex Data</param>
        /// <returns></returns>
        [Route("complex"), HttpPost]
        public DataParameter PostComplexData([FromBody]DataParameter parameter)
        {
            return parameter;
        }

        /// <summary>
        /// 簡單數據類型請求
        /// <![CDATA[
        /// primitive types:[int, bool, double, and so forth]
        /// plus types:[TimeSpan, DateTime, Guid, decimal, and string]
        /// ]]>
        /// </summary>
        /// <param name="parameter">Simple Data</param>
        /// <returns></returns>
        [Route("simple"), HttpPost]
        public string PostSimpleData([FromBody] string parameter)
        {
            return parameter;
        }

3)創建請求(Postman| jQuery):

3.1)Postman:設置請求方式為POST,填寫請求地址:http://localhost:2364/api/data/complex(本機api請求地址)

設置

Content-Type="application/json"

Body選擇Raw,填入請求數據:

{
	"Id": 1,
	"DataItems": [{
		"Id": 1,
		"Name": "DI1",
		"Properties": [{
			"Name": "DI1->P1"
		}]
	}, {
		"Id": 2,
		"Name": "DI2",
		"Properties": [{
			"Name": "DI2->P2"
		}]
	}]
}

點擊請求,發現已經可以接收到數據並返回:

查看發送內容: 

POST /api/data/complex HTTP/1.1
Host: localhost:2364
Content-Type: application/json
Cache-Control: no-cache
Postman-Token: f1bc12c3-3694-4113-b4af-7d4cac6c60f2

{
	"Id": 1,
	"DataItems": [{
		"Id": 1,
		"Name": "DI1",
		"Properties": [{
			"Name": "DI1->P1"
		}]
	}, {
		"Id": 2,
		"Name": "DI2",
		"Properties": [{
			"Name": "DI2->P2"
		}]
	}]
}

這里可以看到發送了一個完整的JSON對象,同時服務器也將這個對象返回給了我們。

3.2)JQuery

啰嗦一段:考慮一個問題,當我們使用jQuery.post、jQuery.ajax發送請求時,附帶的data是一個對象還是一個字符串呢?

$.ajax({
  url: "/api/data/complex", type: "POST", contentType: "application/json", data: JSON.stringify({
          "Id": 1,   "DataItems": [{     "Id": 1,     "Name": "DI1",     "Properties": [{       "Name": "DI1->P1"     }]    },
          {
            "Id": 2, "Name": "DI2", "Properties": [{   "Name": "DI2->P2" }] }] }), success: function (res) { console.log(res); } }); //簡易數據類型 $.ajax({ url: "/api/data/simple", type: "POST", contentType: "application/json", data: JSON.stringify("請求類型為application/json,內容為json字符串"), success: function (res) { console.log(res); } });

請注意jQuery發送請求時data並非一個JSON對象,而是一個被JSON.stringify(data)后的JSON字符串。為什么會這樣?打開瀏覽器控制台看看它們的差別吧 :)

最后做一個總結吧:

1、請求時Content-Type統一設為application/json,可以避免Content-Type不一致導致的問題,方便維護和查找問題。

2、在Postman中請求時除了設置Content-Type外,不要忘了在Body中選擇Raw方式。

3、ajax請求時,data不是一個JSON Object,而是一個JSON字符串。

 


免責聲明!

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



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