2014-10-04 150 views
0

我正在構建一個ASP Web API應用程序,這次我想我將使用MVC模式。我和大部分東西相處得很好,但有一件事我不確定。首先我所有的項目包括以下內容:C#(Web API)多層(IOC)API控制器返回類型

  • 數據層
  • 業務層
  • 模型層(只是模型的屬性)
  • 服務應用(在這裏是我的控制器)

    每個人都在一個單獨的項目中

可以說我有以下控制器

public class TestController : ApiController 
{ 
    ISomeService _someBusiness; 

    public TestController(ISomeService someBusiness) 
    { 
     _someBusiness = someBusiness; 
    } 

    public **SomeModelObject** GetModelObject(ind id) 
    { 
     return _someBusiness .GetSomeModelObject(id); 
    } 

} 

現在我的問題是返回值爲GetModelObject(int id)。這裏寫着SomeModelObject。這意味着我的Service應用程序(或我的控制器)必須知道正在使用的模型的所有內容(所以我沒有看到在單獨的.dll中定義它的要點)。一種方法是將模型(準確地說是get/set方法)定義爲接口,但我認爲每個模型類都有一個接口太多了(主要是因爲,正如我所說的,只是屬性被存儲在模型中),儘管如此,我只是覺得不適合爲只存儲數據的類創建接口。那麼,在這種情況下是否有任何通用響應類型(甚至是一些完全不同的方法),還是我必須使用我的模型類(或者我可能總是使用字符串,並且它正在被轉換爲適當的格式客戶端) ?

+0

我不明白爲什麼你有一個問題引用模型層的DLL從服務。這是很正常的事情。 – Fordio 2014-10-04 10:46:59

回答

0

使用接口來隱藏模型對象的複雜性有很好的理由。它保存數據,當然。但是它包含了僅對數據層有意義的不必要數據。以此EF型號:

public class Employee 
{ 
    public int Id { get; set; } 
    public string EmployeeNumber { get; set; } 
    public string Name { get; set; } 
    public virtual Collection<TimeCard> TimeCards { get; set; } 

    public int DepartmentId { get; set; } 
    public virtual Department Department { get; set; } 
} 

這是一個仙女常見的EF模型。它包含一個代理鍵Id和一個外鍵DepartmentId。這些值除了數據庫和擴展後的實體框架之外毫無意義。 EmployeeNumber是唯一標識用戶域中實體的自然鍵。

數據庫訪問之外,你應該只處理自然數據值。您可以通過在Business層中聲明另一個攜帶數據的類並執行映射來做到這一點,或者更好的辦法是使用一個接口來隱藏所有無用的成員。

public interface IEmployee 
{ 
    string EmployeeNumber { get; } 
    string Name { get; set; } 

    ICollection<ITimeCard> TimeCards { get; } 
    IDepartment Department { get; set; } 
} 

注意接口中缺少一些setter。您永遠不會想要更改EmployeeNumber,因爲這是實體的自然鍵。同樣,您永遠不會將收集對象分配給TimeCards屬性。你只能迭代,添加或刪除它們。

現在你的Employee類成爲

public class Employee : IEmployee 
{ 
    public int Id { get; set; } 
    public string EmployeeNumber { get; set; } 
    public string Name { get; set; } 
    public virtual Collection<TimeCard> TimeCards { get; set; } 
    ICollection<ITimeCard> IEmployee.TimeCards { get { return TimeCards; } } 

    public int DepartmentId { get; set; } 
    public virtual Department Department { get; set; } 
    IDepartment IEmployee.Department { get { return Department; } set { Department = value; } } 
} 

在業務層及以上的,你只用IEmployee,IDepartment和ITimeCard的變量。因此,您將更緊密的API暴露給更高層,這是一件好事。

+0

感謝您的回答,我會像這樣實施它,看看它是否符合我的需求。還有一個問題。我已將所有接口放入單獨的項目(Interfaces.dll)中。這是正確的方法,或者我應該讓他們與實際的層(模型層的接口應該在modellayer.dll等內)?這兩種方法都有它們的優缺點,但是我選擇了一個單獨項目中的所有項目。 – user3466562 2014-10-04 12:52:42

+0

最好將它們放在單獨的項目中,但並不重要。如果一切都在一個解決方案中,稍後很容易將它們轉移到新項目中。 – 2014-10-04 22:28:14

+0

當我使用ISomeObject作爲返回類型時,我在瀏覽器中出現以下異常:使用數據協定名稱'SomeObject:schemas.datacontract.org/2004/07/ModelLayer'輸入'ModelLayer.SomeObject';沒有預料到。考慮使用DataContractResolver或將任何不知道的類型靜態添加到已知類型的列表中 - 例如,使用KnownTypeAttribute屬性或將它們添加到傳遞給DataContractSerializer的已知類型的列表中。 System.Runtime.Serialization.SerializationException我需要在界面內定義一些序列化嗎? – user3466562 2014-10-05 11:24:31

0

你可以嘗試使用在控制器級別的通用方法:

public class BusinessController<T> : ApiController 
{ 
    ISomeService _someBusiness; 

    public TestController(ISomeService someBusiness) 
    { 
     _someBusiness = someBusiness; 
    } 

    public T GetModelObject(ind id) 
    { 
     return _someBusiness.GetSomeModelObject(id); 
    } 

} 

最後你controlers從BusinessController繼承,而不是ApiController:

public class TestController : BusinessController<SomeModelObject> 
{ 
} 

你也可以把模板的提前注入通過使用IoC容器和引導程序來實現正確的「ISomeService」。

+0

這實際上是我從來沒有見過的東西。這整個依賴注入(特別是如果你有很多類)進展表現如何?現在我有大約10個類,我是doint依賴注入(與Unity),我想知道這是如何影響性能(或者它只是影響初始啓動的應用程序)? – user3466562 2014-10-04 13:00:26

+0

依賴注入是一種技術來提高mainaitability和架構。這是SOLID原則中的「D」。關於表現,如果你做得很好,沒有可衡量的懲罰。開銷在「解決」Ioc容器方法上,取代了常規的「新」。如果您不打算創建數千個對象,並且對象實例化時間並不是非常重要,那麼您可以依賴IoC而不需要任何外觀。 – 2014-10-04 13:02:59