2014年1月24日 星期五

ASP.NET MVC 4 WebApi 使用 Northwind 建置 Controller 所遇到的問題

如何在 Visual Studio 2012 建置 Northwind ,已經有在 Visual Studio 2012 安裝 Northwind 資料庫並建立 Entity Framework Database First ( .edmx ) 說明過了,若還未建置的可以參考。

建置完成後,開始建立 Controller,使用 Employees 員工資料表,將所有資料讀取出來:

public IEnumerable<Employees> GetEmployees()
{
    var employees = db.Employees;
    return employees;
}

執行後會發生錯誤:


不需要資料合約名稱為 'Employees_14BF9F9F0C1DAB0594B23F2EB7695ECA92DD0B880DFF02A4CD9698A2DADBA635:http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies' 的型別 'System.Data.Entity.DynamicProxies.Employees_14BF9F9F0C1DAB0594B23F2EB7695ECA92DD0B880DFF02A4CD9698A2DADBA635'。請考慮使用 DataContractResolver,或將任何不明的型別新增到已知型別清單 - 例如,可以使用 KnownTypeAttribute 屬性,或將它們新增到會傳送給 DataContractSerializer 的已知型別清單。

這是由於未禁用 Entity Framework 建立 Proxy 執行個體,所以可以使用以下兩種方法解決:

1.

在 Models 目錄下 Northwind 檔案中的 Northwind.Context.tt 之 Northwind.Context.cs 中,加上 this.Configuration.ProxyCreationEnabled = false;


public NORTHWNDEntities()
    : base("name=NORTHWNDEntities")
{
    this.Configuration.ProxyCreationEnabled = false;
}

2.


或者建立一個 BaseApiController 來使所有 Api 都繼承於它,而只要是共用方法、變數、函式都可以寫在裡面:

public class BaseApiController : ApiController
{
    protected NORTHWNDEntities db = new NORTHWNDEntities();

    public BaseApiController()
    {
        db.Configuration.ProxyCreationEnabled = false;
    }

}

其實兩種方法都可以解決這問題,只是程式碼擺的位置不一樣。

重新執行專案,同一個 Api,執行後會還是會發生錯誤:

類型 'System.Collections.Generic.HashSet`1[[MVVMwithExtjs.Models.Employees, MVVMwithExtjs, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' 的物件圖形包含循環,且如果已停用參照追蹤,便無法被序列化。

遇到循環參考,其實 KKBruceASP.NET WEB API - ENTITY FRAMEWORK(EDMX) NAVIGATION PROPERTY引發的JSON物件循環參考錯誤保哥ASP.NET Web API 無法輸出 Entity Framework 物件的解法 已經有說明過了,最佳解為「用 Partial Class 與 MetadataType 的方式擴充這些由 Visual Studio 幫我們產生的類別」。

如果隱藏輸出循環參考的資料,將會變成以下格式:
[
    {
        "$id": "1", 
        "Category": {
            "$id": "2", 
            "Products": [
                {
                    "$id": "3", 
                    "Category": {
                        "$ref": "2"
                    }, 
                    "Id": 2, 
                    "Name": "Yogurt"
                }, 
                {
                    "$ref": "1"
                }
            ], 
            "Id": 1, 
            "Name": "Diary"
        }, 
        "Id": 1, 
        "Name": "Whole Milk"
    }, 
    {
        "$ref": "3"
    }
]
物件多了 $id,甚至是整個物件內就只有一個 $ref ,資料變得較難閱讀。

因為使用 WebApi 就必須確認資料的完整性,如果都是在微軟的環境下當然沒有問題,但是資料如果提供給手機程式使用,或者是跨平台的環境中,這種資料格式就不見得在不同的環境中可以閱讀。

我的解法,是將這些循環參考的資料在送出之前,將循環參考的資料設為 null。
public IEnumerable GetEmployees()
{
    var employees = db.Employees;

    foreach (Employees employee in employees)
    {
        employee.Employees1 = null;
        employee.Employees2 = null;
    }

    return employees;
}

最後就會得到以下結果:


如果還需要更詳細的資料就另外再寫一個 API 就好了,在一個 API 若是給予太多資訊且又是公開資訊讀取,反而可能會造成 Server 的負擔,最重要的是:「資料的完整性」。


沒有留言 :

張貼留言

Related Posts Plugin for WordPress, Blogger...