2015-02-06 102 views
0

我建立一個原型使用的ASP.NET Web API 2,一個RESTful API時,佛simplictiy讓我們假設我有三個實體:客戶,許可和用戶。每個客戶都有一套許可證和用戶。語義在我看來,資源的URI應該是這樣的:不同的Web API 2個控制器使用屬性路由

myurl/api/customers for accessing all customers 
myurl/api/customers/{cid} for accessing the customer {cid} 
myurl/api/customers/{cid}/licences for accessing all licences of customer {cid} 
myurl/api/customers/{cid}/licences/{lid} for accessing the licence {lid} of customer {cid} 

這同樣適用於用戶。預期的語義允許例如兩個用戶如果屬於不同的客戶,則具有相同的ID。除了也許許可證的實體(決定不是最終還)每個客戶都會有一個專門的數據庫,所以在這個領域和資源路徑沒有重疊像

myurl/api/users 

使只可意會的方式「加入的所有用戶表從

使用屬性路由此設置是很容易實現的所有客戶數據庫。但是,所有的方法都在同一個控制器來實現,因爲來自不同控制器的方法不能共享相同的前綴AFAIK。

實際應用程序將包含更多的實體,而不僅僅是三個,所以我exp控制器的實施變得相當龐大。我現在的問題是,我怎麼把這個方法分解成不同的控制器?我想過使用一個主控制器,它只是將工作分派給另一個控制器。例如

[Route("{customer:int}/licences/{licence:int}")] 
public HttpResponseMessage GetLicence(int customer, int licence) 
{ 
    // pretend the called method is static 
    return LicenceController.GetLicence(customer, licence); 
} 

但是,我不知道如何正確實現:我應該爲每個調用創建一個新的LicenceController嗎?或者擁有這種類型的屬性並將其稱爲方法?其實實現一些靜態方法?

另一個缺點是,這引入了選擇和執行控制器類我覺得不乾淨的溶液之間的硬編碼的依賴關係。

我想出了與使用這樣的資源路徑的解決方法:

myurl/api/licences/customer-{cid} for accessing all licences of customer {cid} 
myurl/api/licences/customer-{cid}/{lid} for accessing the licence {lid} of customer {cid} 

這工作得很好,但IMO攪亂均勻語義。我知道我可以編寫一個自定義選擇器類,但這似乎是一些工作,以使其正確。

所以我的問題是,什麼是最好的(也許是最有效的)的方式來分割與傳入的HTTP消息涉及到單獨的控制器,這樣有鬆耦合和資源的語義是一致的代碼?

回答

1

您將有兩個控制器。一個返回客戶,一個返回許可證。對於客戶沒有必要使用屬性的默認值是罰款:

public class CustomersController : ApiController 
{ 
    // GET: api/Customers 
    public IEnumerable<Customer> Get() 
    { 
     return new List<Customer> 
     { 
      new Customer { Id = 1, Name = "Wayne" }, 
      new Customer { Id = 2, Name = "John" } 
     }; 
    } 

    // GET: api/Customers/5 
    public Customer Get(int id) 
    { 
     return new Customer { Id = 1, Name = "Wayne" }; 
    } 
} 

然後你可以在你RoutePrefix控制器上的屬性以添加api/Customers/1/licences,其餘可通過Route上的動作來處理。我叫控制器CustomerLicencesController因爲你可能希望有一個許可證控制器來獲取特定的許可證或所有許可證,如api/licencesapi/licences/1

[RoutePrefix("api/customers/{customer}/licences")] 
public class CustomerLicencesController : ApiController 
{ 
    // GET: api/Customers/1/licences 
    [Route("")] 
    public IEnumerable<Licence> Get(int customer) 
    { 
     return new List<Licence> 
     { 
      new Licence { Id = 1, Name = "Test" }, 
      new Licence { Id = 2, Name = "Test2" } 
     }; 
    } 

    // GET: api/Customers/1/licences/1 
    [Route("{id}")] 
    public Licence Get(int customer, int id) 
    { 
     return new Licence { Id = 1, Name = "Test" }; 
    } 
} 

有關Route屬性的更多信息,請參閱this

+0

我試過這樣的,沒有工作的解決方案。然而,我在考慮到你的答案的時候再次嘗試了它,現在它完成了它的工作。所以我必須在我的代碼中出現一些錯誤。在此期間我想到的一點可能是原因:當Route或RoutePrefix包含「{customer}」時,該方法的參數必須以acutally命名爲「customer」。否則,即使類型確實不匹配。無論如何,非常感謝! – Ratatwisker 2015-02-06 16:37:50