Tôi xin lỗi trước, bài đăng này sẽ diễn ra một chút so với những gì bạn đã hỏi, nhưng tất cả điều này đã sôi nổi khi tôi đọc câu hỏi của bạn.
- Nó phù hợp với tên của hành động với động từ (verb = GET? Tìm kiếm tên phương pháp bắt đầu bằng "nhận được")
- nếu một tham số được thông qua, các api tìm kiếm một hành động với một tham số
Vì vậy, trong mã của bạn, hãy lấy yêu cầu GET mà không có tham số khớp với hàm Get*()
mà không có tham số. A chứa và ID tìm kiếm một Get***(int id)
.
Ví dụ
Trong khi ngữ nghĩa phù hợp rất đơn giản, nó tạo ra một số nhầm lẫn cho các nhà phát triển MVC (cũng ít nhất nhà phát triển này). Hãy xem xét một số ví dụ:
Tên vô danh - Phương thức nhận của bạn có thể được đặt tên bất cứ điều gì, miễn là bắt đầu bằng "get". Vì vậy, trong trường hợp của một bộ điều khiển widget, bạn có thể đặt tên cho các hàm của mình GetStrawberry()
và nó vẫn sẽ được khớp. Hãy suy nghĩ về kết hợp như một cái gì đó như: methodname.StartsWith("Get")
Nhiều phương pháp đối sánh - Điều gì sẽ xảy ra nếu bạn có hai phương pháp Nhận không có tham số? GetStrawberry()
và GetOrange()
. Tốt nhất tôi có thể nói, hàm được định nghĩa đầu tiên (đầu tệp) trong mã của bạn thắng ... lạ. Điều này có tác dụng phụ của việc làm cho một số phương pháp trong bộ điều khiển của bạn không thể truy cập (ít nhất là với các tuyến đường mặc định) .... người lạ.
LƯU Ý: phiên bản beta cư xử như trên cho 'phù hợp với nhiều phương pháp' - phiên bản phát hành RC & là OCD hơn một chút. Nó ném một lỗi nếu có nhiều trận đấu tiềm năng. Thay đổi này loại bỏ sự nhầm lẫn của nhiều kết quả không rõ ràng. Đồng thời, nó làm giảm khả năng kết hợp các giao diện kiểu REST và RPC trong cùng một bộ điều khiển, dựa vào thứ tự chồng chéo &.
Việc cần làm?
Vâng, WebAPI là mới và sự đồng thuận vẫn đang kết hợp. Cộng đồng dường như đang tiếp cận các nguyên tắc REST một chút. Tuy nhiên, không phải mọi API có thể hoặc nên được RESTful, một số được tự nhiên thể hiện trong một phong cách RPC. REST & những gì mọi người gọi REST dường như là nguồn của quite a bitof confusion, wellat least toRoy Fielding.
Là một nhà thực dụng, tôi nghi ngờ rằng nhiều API sẽ là 70% RESTful, với một loạt các phương thức kiểu RPC. Thứ nhất, sự gia tăng bộ điều khiển một mình (được đưa ra phương pháp ràng buộc webapi) sẽ thúc đẩy các nhà phát triển bonkers. Thứ hai, WebAPI không thực sự có cách dựng sẵn để tạo cấu trúc lồng nhau của đường dẫn api (có nghĩa là: /api/controller/
thật dễ dàng, nhưng /api/CATEGORY/Sub-Category/Controller
có thể thực hiện được, nhưng là một cơn đau). Theo quan điểm của tôi, tôi rất thích xem cấu trúc thư mục webAPI kiểm soát các đường dẫn API mặc định ... có nghĩa là nếu tôi tạo thư mục Danh mục trong dự án giao diện người dùng của mình thì /api/Category
sẽ là đường dẫn mặc định (cái gì đó parallel to this MVC article).
Tôi đã làm gì?
Vì vậy, tôi đã có một vài yêu cầu: (1) để có thể sử dụng cú pháp an toàn trong hầu hết trường hợp, (2) có một số "không gian tên" tách bộ điều khiển (nghĩ các thư mục con), (3) có thể gọi các phương thức giống như rpc khi cần thiết. Thực hiện các yêu cầu này đã đi xuống để định tuyến thông minh.
// SEE NOTE AT END ABOUT DataToken change from RC to RTM
Route r;
r = routes.MapHttpRoute(name : "Category1",
routeTemplate : "api/Category1/{controller}/{id}",
defaults : new { id = RouteParameter.Optional });
r.DataTokens["Namespaces"] = new string[] {" UI.Controllers.Category1"};
r = routes.MapHttpRoute(name : "Category2",
routeTemplate : "api/Category2/{controller}/{id}",
defaults : new { id = RouteParameter.Optional });
r.DataTokens["Namespaces"] = new string[] {" UI.Controllers.Category2"};
routes.MapHttpRoute( name : "ApiAllowingBL",
routeTemplate : "api/{controller}/{action}/{id}",
defaults : new { id = RouteParameter.Optional });
routes.MapHttpRoute( name : "DefaultApi",
routeTemplate : "api/{controller}/{id}",
defaults : new { id = RouteParameter.Optional });
- Hai tuyến đường đầu tiên tạo ra "tiểu thư mục" tuyến đường. Tôi cần phải tạo một lộ trình cho mỗi thư mục con, nhưng tôi giới hạn bản thân mình với các danh mục chính, vì vậy tôi chỉ kết thúc với 3-10 trong số này. Lưu ý cách các tuyến này thêm mã thông báo dữ liệu
Namespace
, để hạn chế những lớp nào được tìm kiếm cho một tuyến đường cụ thể.Điều này tương ứng với thiết lập không gian tên điển hình khi bạn thêm các thư mục vào một dự án giao diện người dùng.
- Tuyến đường thứ ba cho phép tên phương thức cụ thể được gọi (như mvc truyền thống). Vì API web không hoạt động với tên hành động trong URL, nên tương đối dễ dàng để biết cuộc gọi nào muốn tuyến đường này.
- Mục nhập tuyến đường cuối cùng là tuyến api web mặc định. Điều này bắt bất kỳ lớp nào, đặc biệt là các lớp bên ngoài 'thư mục con' của tôi.
Nói Another Way
Giải pháp của tôi đi xuống xuống để điều khiển tách một chút nhiều hơn như vậy /api/XXXX
đã không nhận được quá đông đúc.
- Tôi tạo thư mục trong dự án giao diện người dùng của mình (cho phép nói
Category1
) và đặt bộ điều khiển api trong thư mục.
- Visual studio tự nhiên đặt không gian tên lớp dựa trên thư mục. Vì vậy,
Widget1
trong thư mục Category1
nhận được không gian tên mặc định là UI.Category1.Widget1
.
- Đương nhiên, tôi muốn URL api phản ánh cấu trúc thư mục (
/api/Category1/Widget
). Ánh xạ đầu tiên bạn thấy ở trên hoàn thành điều đó, bằng cách mã hóa cứng /api/Category1
vào tuyến đường, sau đó mã thông báo namespace
hạn chế các lớp sẽ được tìm kiếm cho bộ điều khiển phù hợp.
LƯU Ý: tính đến việc phát hành DataTokens
là null theo mặc định. Tôi không phải là chắc chắn nếu this is a bug, or a feature. Vì vậy, tôi đã viết một chút phương pháp helper và thêm vào tập tin RouteConfig.cs
của tôi ....
r.AddRouteToken("Namespaces", new string[] {"UI.Controllers.Category1"});
private static Route AddRouteToken(this Route r, string key, string[] values) {
//change from RC to RTM ...datatokens is null
if (r.DataTokens == null) {
r.DataTokens = new RouteValueDictionary();
}
r.DataTokens[key] = values;
return r;
}
Chú thích 2: thậm chí còn nghĩ đây là một WebAPI 1 bưu điện, như @Jamie_Ide chỉ ra trong bình luận giải pháp trên không hoạt động trong WebAPI 2 vì IHttpRoute.DataTokens
không có setter. Để khắc phục bạn này có thể sử dụng một phương pháp mở rộng đơn giản như thế này:
private static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate, object defaults, object constraints, string[] namespaceTokens)
{
HttpRouteValueDictionary defaultsDictionary = new HttpRouteValueDictionary(defaults);
HttpRouteValueDictionary constraintsDictionary = new HttpRouteValueDictionary(constraints);
IDictionary<string, object> tokens = new Dictionary<string, object>();
tokens.Add("Namespaces", namespaceTokens);
IHttpRoute route = routes.CreateRoute(routeTemplate, defaultsDictionary, constraintsDictionary, dataTokens: tokens, handler:null);
routes.Add(name, route);
return route;
}
Trong WebAPI Tôi _think_ bạn có nghĩa vụ phải có một bộ điều khiển cho mỗi tài nguyên, do đó bạn sẽ không có hai phương pháp xóa. –
Cảm ơn Shane, đó là thông tin tốt, nhưng ý tôi là đặc biệt giống như một phương thức thu âm duy nhất và phương pháp ghi nhiều lần. GET có lẽ là một ví dụ thích hợp hơn, nhưng bạn có thể có một phương thức lấy một bản ghi bằng một ID và một phương thức khác nhận tất cả các bản ghi với một FK nhất định. Nhưng cả hai đều sử dụng động từ GET; Tôi không hiểu nơi trí thông minh định tuyến phân biệt giữa những điều này tồn tại. –