[英]Routing a selection of controller methods to the root URL of the web API
[英]Web API 2 Attribute Routing Controller Selection
我在項目中使用Web API 2屬性路由來為數據提供JSON接口。 我面臨控制器選擇的怪異行為,尚未確定是錯誤還是功能:)讓我描述一下我的方法。
我想借助屬性路由來模擬OData語法(由於設計原則,拒絕直接使用OData)。 例如,要獲取id = 5的實體,請使用對URI http://mydomain.com/api/Entity(5)的 HTTP GET請求。 我希望對HTTP PUT動詞使用相同的URI來更新實體。 這是旅程的起點...
我想有一個用於獲取實體的單獨控制器(在下面提供的示例中為FirstController
)和一個用於修改實體的控制器( SecondController
)。 兩個控制器都處理相同的URI(例如http://mydomain.com/api/Entity(5) ),唯一的區別是與URI一起使用的HTTP動詞FirstController
應該由FirstController
處理,PUT應該由SecondController
處理。 但是URI是沒有一個人處理的。 而是返回HTTP 404錯誤。 當我僅將GET和PUT操作“合並”到一個控制器(在FirstController
注釋)時,兩個動詞均得到正確處理。 我正在使用IIS Express,並且所有常規路由都被禁用,僅由屬性路由負責。
控制器選擇過程似乎不適用於HTTP動詞。 換句話說, HttpGet
和HttpPut
屬性僅限制動作的使用,但在選擇控制器時它們不用作條件。 我不太了解MVC / Web API基礎知識,所以讓我問您一個大問題:
行為是否如前所述,是MVC / Web API 2故意實現的功能還是要修復的錯誤?
如果將其視為功能,則會阻止我遵循設計原則。 我可以使用“合並”的控制器,但仍然認為這是一種不好的做法……還是我在思路中缺少什么?
我的環境設置:
以下是FirstController
類的實現:
public class FirstController : ApiController
{
[HttpGet]
[Route("api/Entity({id:int})")]
public Output GetEntity(int id)
{
Output output = new Output() { Id = id, Name = "foo" };
return output;
}
//[HttpPut]
//[Route("api/Entity({id:int})")]
//public Output UpdateEntity(int id, UpdateEntity command)
//{
// Output output = new Output() { Id = id, Name = command.Name };
// return output;
//}
}
以下是SecondController
類的實現:
public class SecondController : ApiController
{
[HttpPut]
[Route("api/Entity({id:int})")]
public Output UpdateEntity(int id, UpdateEntity command)
{
Output output = new Output() { Id = id, Name = command.Name };
return output;
}
}
以下是控制台應用程序的實現,用於測試所描述的行為:
class Program
{
static void Main(string[] args)
{
// HTTP client initialization
HttpClient httpClient = new HttpClient();
httpClient.BaseAddress = new Uri("http://localhost:1567");
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// HTTP GET - FirstController.GetEntity
HttpResponseMessage getEntityResponse = httpClient.GetAsync("/api/Entity(5)").Result;
Output getOutput = getEntityResponse.Content.ReadAsAsync<Output>().Result;
// HTTP PUT - SecondController.UpdateEntity
UpdateEntity updateCommand = new UpdateEntity() { Name = "newEntityname" };
HttpResponseMessage updateEntityResponse = httpClient.PutAsJsonAsync("/api/Entity(10)", updateCommand).Result;
Output updateOutput = updateEntityResponse.Content.ReadAsAsync<Output>().Result;
}
}
為了完成,使用了以下DTO:
public class UpdateEntity
{
public string Name { get; set; }
}
public class Output
{
public int Id { get; set; }
public string Name { get; set; }
}
預先感謝您的回復,
揚·卡西納(Jan Kacina)
這種設計是有意的,因為我們認為這是一個錯誤情況,即用戶在不同的控制器上具有相同的路由模板,這可能在選擇過程中造成歧義。
另外,如果我們不考慮屬性路由,那么如何使用常規路由呢? 假設我們有2條常規路線,第一個路線針對FirstController,第二個路線針對SecondController。 現在,如果請求網址類似於api/Entity(5)
,則Web API將始終與路由表中的第一條路由匹配,該路由將始終命中FirstController且永遠不會到達SecondController。 請記住,一旦Web API匹配了路由,它就會嘗試執行操作選擇過程,並且如果操作選擇過程沒有導致選擇操作,則會向客戶端發送錯誤響應。 您可能假設如果未在一個控制器中選擇任何動作,則Web API會將其路由到路由配置中的下一個動作。 這是不正確的。
路由探測僅發生一次,如果結果匹配,則接下來的步驟將進行...即控制器和操作選擇。 希望這可以幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.