2013-03-28 4 views
8

Tôi muốn có hai hành động GET khác nhau để truy vấn dữ liệu bằng cách, tên và id,WebAPI Controller với hai GET hành động

tôi có các đường bay:

 config.Routes.MapHttpRoute(
      name: "ActionApi", 
      routeTemplate: "api/{controller}/{action}/{id}", 
      defaults: new { id = RouteParameter.Optional } 
     ); 

     config.Routes.MapHttpRoute(
      name: "ActionApiByName", 
      routeTemplate: "api/{controller}/{action}/{name}", 
      defaults: new { name = RouteParameter.Optional } 
     ); 

     config.Routes.MapHttpRoute(
      name: "DefaultApi", 
      routeTemplate: "api/{controller}/{id}", 
      defaults: new { id = RouteParameter.Optional } 
     ); 

và những hành động trong bộ điều khiển:

[HttpGet] 
    public CompanyModel CompanyId(Guid id) 
    { 
      //Do something 
    } 


    [HttpGet] 
    public CompanyModel CompanyName(string name) 
    { 
      //Do something 
    } 

trong khi một cuộc gọi như thế này: http://localhost:51119/api/companies/CompanyId/3cd97fbc-524e-47cd-836c-d709e94c5e1e công trình và được cho là phương pháp 'CompanyId',

một cuộc gọi tương tự như http://localhost:51119/api/companies/CompanyName/something được tôi để 404 không tìm thấy

nhưng điều này: 'http://localhost:51119/api/companies/CompanyName/?name=something' hoạt động tốt

bất cứ ai có thể giải thích hành vi này và những gì tôi làm sai?

Trả lời

10

Bộ chọn tuyến đường API Web không có cách nào để biết liệu chuỗi ở cuối URL của bạn có phải là GUID hay không. Do đó, nó không phải là về để chọn đúng lộ trình cho hành động GET thích hợp.

Để chọn tuyến đường chính xác, bạn cần thêm ràng buộc tuyến đường cho mẫu uri GUID.

public class GuidConstraint : IHttpRouteConstraint 
    { 
     public bool Match(HttpRequestMessage request, IHttpRoute route, string parameterName, IDictionary<string, object> values, 
          HttpRouteDirection routeDirection) 
     { 
      if (values.ContainsKey(parameterName)) 
      { 
       string stringValue = values[parameterName] as string; 

       if (!string.IsNullOrEmpty(stringValue)) 
       { 
        Guid guidValue; 

        return Guid.TryParse(stringValue, out guidValue) && (guidValue != Guid.Empty); 
       } 
      } 

      return false; 
     } 
    } 

Sau đó, thêm ràng buộc vào tuyến đường sẽ xử lý GUID.

config.Routes.MapHttpRoute(
      name: "ActionApi", 
      routeTemplate: "api/{controller}/{action}/{id}", 
      defaults: new { id = RouteParameter.Optional }, 
      constraints: new { id = new GuidConstraint() } // Added 
     ); 

Kể từ khi tuyến đường này là cụ thể hơn chung "chuỗi" tuyến đường, nó cần phải được đặt trên một trong đó là sẽ giải quyết tên.

Tuyến đường này nên phù hợp với hành động.

Hy vọng điều này sẽ hữu ích.

+0

Tôi chấp nhận câu trả lời của bạn vì nó hoạt động tốt, nhưng tôi vẫn không hiểu tại sao nó không được ánh xạ với hành động đúng, trong URI tôi trực tiếp là một lần để 'CompanyName' và một lần để 'CompanyId', should't nó chọn hành động thích hợp? –

+2

[Câu hỏi SO này] (http://stackoverflow.com/questions/9569270/custom-method-names-in-asp-net-web-api) có thể giúp giải thích lý do. Theo mặc định, các tuyến API Web tuân theo các quy ước REST. Vì vậy, bạn có thể thấy hành vi khác nhau với các tuyến đường MVC thông thường. –

+0

Brilliant! Web API cũng chỉ được nghĩ ra! –