---
# System prepended metadata

title: WebApi
tags: [Learning]

---

# WebApi
###### tags: `Learning`

## 建立 ApiController

![](https://i.imgur.com/8APXOiM.png)

## 預設改為 Json 格式回應
在 Global.asax 中加入一行:
```
// 關閉 XML 格式回應，就會預設回應 Json 格式
GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear();
```
[參考資料](https://blog.miniasp.com/post/2012/10/12/ASPNET-Web-API-Force-return-JSON-format-instead-of-XML-for-Google-Chrome-Firefox-Safari)

---

## Json 序列化時 Exception
JsonSerializationException Self referencing loop detected with type
![](https://i.imgur.com/aHES4UX.png)

### 發生原因: Entity Framework...會建一些關聯的欄位...
這次的原因是 Employees 中，又有 Employees 的欄位，所以造成序列化無限迴圈

參考循環、循環參考...

這邊使用的是北風資料庫的 Employees Table，因為欄位中有一個 ReportsTo，就是員工要回報給誰(主管)，所以那個 Employees2 是主管的資料。
至於 Employess1 呢? 為什麼是個清單，是指要回報狀況給此員工的員工是誰 Ex. A、B、C 都要回報給 D(主管)，D 的 Employees1 就會有 A、B、C 的資料

![](https://i.imgur.com/Fs6jZ76.png)

![](https://i.imgur.com/xXPiO6R.png)

### 解法:
```
// 如果 Json 序列化是使用 Json.Net 序列化 ( 應該是微軟原生的Json(?) )，
// 這行程式可以忽略循環引用 ( 就是 Model 中有相同類型的 Property，導致進行 Json 序列化時無限迴圈 )
config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
```

### 附註
#### JsonSerializerSettings
> ReferenceLoopHandling.Error（默認）如果遇到參考循環將出錯。這就是為什麼您會獲得例外。
> ReferenceLoopHandling.Serialize 如果對像是嵌套的但不是無限期的，則很有用。
> ReferenceLoopHandling.Ignore 如果對象本身是子對象，則不會序列化該對象。
> 
> 原文↓
> 
> ReferenceLoopHandling.Error (default) will error if a reference loop is encountered. This is why you get an exception.
ReferenceLoopHandling.Serialize is useful if objects are nested but not indefinitely.
ReferenceLoopHandling.Ignore will not serialize an object if it is a child object of itself.

[資料來源](https://stackoverflow.com/questions/7397207/json-net-error-self-referencing-loop-detected-for-type)

---

## Route
使用情境:
更新 API 的方法的時候，可用 v1、v2... 來做區別，為了相容舊系統 ( 還有系統用 v1，v1 就不能下線，所以此時 v1、v2 是同時在線上可以呼叫 )

本來可能呼叫方法是 api/Employee 就能 Get 資料，但為了區分版本， 需要寫成 api/Employee/v1，這時候需要 Route，當然可以在 RouteConfig 專門設一個有版本的 Route 匹配。

但是如果只是偶發的版本情況，其實也可以直接在 Function 上加入 Route Attribute，直接指定路徑
<span style="color:red">特別注意！！WebApiConfig.cs 需要加上 config.MapHttpAttributeRoutes(); 才會參考 Attribute 的路由 </span>
![](https://i.imgur.com/8lCtQMI.png)

```
[Route("api/Employee/v1")]
```
FYI，路徑是可以加上一些驗證的喔
```
[Route("api/Employee/v1/{id:regex}")]
```

## Function 自定義改名
加上 HttpGet Attribute 就好
![](https://i.imgur.com/alD9jXv.png)

HttpGet 的優先權會高於
```
public List<Employees> Get(){
    //...
}
```

---

## CORS 跨來源資源共用
練習過程中直接遇到這個問題
> has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

#### 解法

1. 在專案中加入 Microsoft.AspNet.WebApi.Cors 的 Nuget 套件
2. 安裝完成後，打開專案中的[App_Start\WebApiConfig.cs]檔案，並在裡面加上一行"config.EnableCors();"
3. 在 Action 中加上 Attribute![](https://i.imgur.com/ZmDw084.png)origins代表允許存取的來源網域，headers代表允許的標頭，而method則是代表允許使用的方法，如Get或是Post等等，這幾個屬性的設定，若是更改為*，就代表允許所有的來源以及所有請求方式

[讓WebAPI可以跨網域執行，並動態指定允許呼叫的來源網域](https://dotblogs.com.tw/maduka/2018/01/29/214811)

[Microsoft - 在 ASP.NET Web API 2 中啟用跨原始來源要求](https://docs.microsoft.com/zh-tw/aspnet/web-api/overview/security/enabling-cross-origin-requests-in-web-api)

#### CORS的作用

##### 為了改善網絡應用程式，開發人員要求瀏覽器供應商允許跨域請求。跨域請求主要用於：
1. 調用XMLHttpRequest或fetchAPI通過跨站點方式訪問資源
2. 網絡字體，例如Bootstrap（通過CSS使用@font-face 跨域調用字體）
3. 通過canvas標籤，繪製圖表和視頻。

#### CORS的安全隱患
1. HTTP頭只能說明請求來自一個特定的域：不能保證這個事實。因為HTTP頭可以被偽造。
2. 第三方有可能被入侵：像是 假設 Facebook 授權某個 Api 給 A 網站使用，而 A 網站被駭，則駭客可以使用該 Api
3. 惡意跨域請求：即便頁面只允許來自某個信任網站的請求，但是它也會收到大量來自其他域的跨域請求。.這些請求有時可能會被用於執行應用層面的DDOS攻擊，並不應該被應用來處理。
4. 內部資訊洩漏：假定一個內部站點開啟了CORS，如果內部網絡的用戶訪問了惡意網站，惡意網站可以通過COR（跨域請求）來獲取到內部站點的內容。
5. 針對用戶的攻擊：攻擊者並不是直接從它們的系統資料庫中獲取數據，他們可能會編寫一個JavaScript數據採集腳本，並在自己的網站或者存在XSS問題的網站上插入這段腳本。當受害者訪問含有這種惡意JavaScript腳本網站時，瀏覽器將執行針對「productsearch.php」的SQL注入攻擊，採集所有的數據並發送給攻擊者。檢查伺服器日誌顯示是受害人執行了攻擊，因為除了來自Referrer的HTTP頭一般沒有其他日誌記錄。受害者並不能說他的系統被攻破，因為沒有任何任何惡意軟體或系統泄漏的痕跡。

[CORS攻擊：跨源資源共享安全分析](https://kknews.cc/zh-tw/tech/e8apaan.html)

#### 幾個重點
* 可以接受簡單的請求 ( 之前使用 WebService 都沒遇到這類問題，可能就是簡單請求 )，參考 -> [MDN - 跨來源資源共用（CORS）](https://developer.mozilla.org/zh-TW/docs/Web/HTTP/CORS)
* 可以配合身分驗證
* 還是有風險

---
