Định tuyến API web - api / {controller} / {action} / {id} “dysfunctions” api / {controller} / {id}


94

Tôi có Tuyến đường mặc định trong Global.asax:

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

Tôi muốn có thể nhắm mục tiêu một chức năng cụ thể, vì vậy tôi đã tạo một tuyến đường khác:

RouteTable.Routes.MapHttpRoute(
         name: "WithActionApi",
         routeTemplate: "api/{controller}/{action}/{id}",
         defaults: new { id = System.Web.Http.RouteParameter.Optional }
         );

Vì vậy, trong bộ điều khiển của tôi, tôi có:

    public string Get(int id)
    {
        return "object of id id";
    }        

    [HttpGet]
    public IEnumerable<string> ByCategoryId(int id)
    {
        return new string[] { "byCategory1", "byCategory2" };
    }

Gọi điện .../api/records/bycategoryid/5sẽ cho tôi những gì tôi muốn. Tuy nhiên, gọi điện .../api/records/1sẽ báo lỗi cho tôi

Đã tìm thấy nhiều hành động phù hợp với yêu cầu: ...

Tôi hiểu lý do tại sao lại như vậy - các tuyến chỉ xác định URL nào là hợp lệ, nhưng khi nói đến khớp chức năng, cả hai Get(int id)ByCategoryId(int id)đối sánh api/{controller}/{id}, đó là điều gây nhầm lẫn cho khung.

Tôi cần làm gì để tuyến API mặc định hoạt động trở lại và giữ nguyên tuyến {action}? Tôi đã nghĩ đến việc tạo một bộ điều khiển khác có tên RecordByCategoryIdControllerđể phù hợp với tuyến API mặc định, mà tôi sẽ yêu cầu .../api/recordbycategoryid/5. Tuy nhiên, tôi thấy rằng đó là một giải pháp "bẩn" (do đó không đạt yêu cầu). Tôi đã tìm kiếm câu trả lời về vấn đề này và không có hướng dẫn nào về cách sử dụng tuyến đường {action}thậm chí còn đề cập đến vấn đề này.

Câu trả lời:


104

Công cụ định tuyến sử dụng trình tự giống như khi bạn thêm các quy tắc vào đó. Khi nhận được quy tắc phù hợp đầu tiên, nó sẽ ngừng kiểm tra các quy tắc khác và lấy quy tắc này để tìm kiếm bộ điều khiển và hành động.

Bạn nên làm điều đó:

  1. Đặt các quy tắc cụ thể của bạn trước các quy tắc chung của bạn (như mặc định), có nghĩa là sử dụng RouteTable.Routes.MapHttpRouteđể ánh xạ "WithActionApi" trước, sau đó là "DefaultApi".

  2. Xóa defaults: new { id = System.Web.Http.RouteParameter.Optional }tham số của quy tắc "WithActionApi" của bạn vì khi id là tùy chọn, url như "/ api / {part1} / {part2}" sẽ không bao giờ chuyển thành "DefaultApi".

  3. Thêm một hành động được đặt tên vào "DefaultApi" của bạn để cho công cụ định tuyến biết hành động nào cần nhập. Nếu không, khi bạn có nhiều hành động trong bộ điều khiển của mình, công cụ sẽ không biết phải sử dụng hành động nào và ném "Đã tìm thấy nhiều hành động phù hợp với yêu cầu: ...". Sau đó, để làm cho nó phù hợp với phương pháp Get của bạn, hãy sử dụng ActionNameAttribute .

Vì vậy, tuyến đường của bạn sẽ như thế này:

// Map this rule first
RouteTable.Routes.MapRoute(
     "WithActionApi",
     "api/{controller}/{action}/{id}"
 );

RouteTable.Routes.MapRoute(
    "DefaultApi",
    "api/{controller}/{id}",
    new { action="DefaultAction", id = System.Web.Http.RouteParameter.Optional }
);

Và bộ điều khiển của bạn:

[ActionName("DefaultAction")] //Map Action and you can name your method with any text
public string Get(int id)
{
    return "object of id id";
}        

[HttpGet]
public IEnumerable<string> ByCategoryId(int id)
{
    return new string[] { "byCategory1", "byCategory2" };
}

1
Tôi đã thử những lời khuyên ở trên và mọi thứ hoạt động như mong đợi. Cảm ơn bạn rất nhiều vì "bí mật" đó.
Mickael Caruso

Tại điểm 2 trong câu trả lời của bạn, nếu idlà tùy chọn thì URL như /api/{part1}/{part2}vẫn có thể đi vào DefaultApituyến nếu không tìm thấy hành động phù hợp nào cho WithActionApituyến. Vui long sửa cho tôi nêu tôi sai.
orad

điều gì sẽ xảy ra nếu tôi chỉ muốn có api / {controller} / {action}. không có id. Nếu ai đó đang gặp phải vấn đề tương tự. quên WebApiConfig. đọc về Định tuyến thuộc tính.
ahsant

40

Bạn có thể giải quyết vấn đề của mình với sự trợ giúp của Định tuyến thuộc tính

Bộ điều khiển

[Route("api/category/{categoryId}")]
public IEnumerable<Order> GetCategoryId(int categoryId) { ... }

URI trong jquery

api/category/1

Cấu hình tuyến đường

using System.Web.Http;

namespace WebApplication
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API routes
            config.MapHttpAttributeRoutes();

            // Other Web API configuration not shown.
        }
    }
}

và định tuyến mặc định của bạn đang hoạt động như định tuyến dựa trên quy ước mặc định

Bộ điều khiển

public string Get(int id)
    {
        return "object of id id";
    }   

URI trong Jquery

/api/records/1 

Cấu hình tuyến đường

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Attribute routing.
        config.MapHttpAttributeRoutes();

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

Xem lại bài viết để biết thêm thông tin Định tuyến thuộc tính và định tuyến dựa trên phát minh tại đây & cái này


thần trả lời. nhưng chúng ta không thể thêm cho tất cả, api / {controller} / {action} / {id} cùng với api / {controller} / {id}?
karim

Định tuyến thuộc tính giải quyết triệt để vấn đề. Một điểm quan trọng: Trước Web API 2, các mẫu dự án Web API đã tạo mã như sau: protected void Application_Start () {WebApiConfig.Register (GlobalConfiguration.Configuration); } Nếu định tuyến thuộc tính được bật, mã này sẽ đưa ra một ngoại lệ. Nếu bạn nâng cấp một dự án Web API hiện có để sử dụng định tuyến thuộc tính, hãy đảm bảo cập nhật mã cấu hình này thành mã sau: protected void Application_Start () {GlobalConfiguration.Configure (WebApiConfig.Register); }
Deeb

0

Thử cái này.

public class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services

        var json = config.Formatters.JsonFormatter;
        json.SupportedMediaTypes.Add(new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"));
        config.Formatters.Remove(config.Formatters.XmlFormatter);

        // Web API routes
        config.MapHttpAttributeRoutes();

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

        );
    }
}

0

Lý do có thể cũng có thể là bạn chưa kế thừa Controller từ ApiController. Xảy ra với tôi mất một thời gian để hiểu như nhau.


0

Để phân biệt các tuyến, hãy thử thêm một ràng buộc mà id phải là số:

RouteTable.Routes.MapHttpRoute(
         name: "DefaultApi",
         routeTemplate: "api/{controller}/{id}",
         constraints: new { id = @"\d+" }, // Only matches if "id" is one or more digits.
         defaults: new { id = System.Web.Http.RouteParameter.Optional }
         );  
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.