웹 API 라우팅-api / {controller} / {action} / {id} "dysfunctions"api / {controller} / {id}


94

Global.asax에 기본 경로가 있습니다.

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

특정 기능을 대상으로 할 수 있기를 원했기 때문에 다른 경로를 만들었습니다.

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

따라서 내 컨트롤러에는 다음이 있습니다.

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

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

전화 .../api/records/bycategoryid/5하면 내가 원하는 것을 얻을 수 있습니다. 그러나 전화 .../api/records/1하면 오류가 발생합니다.

요청과 일치하는 여러 작업이 발견되었습니다. ...

그 이유를 이해합니다. 경로는 유효한 URL을 정의하지만 함수 일치에 관해서는 둘 다 Get(int id)ByCategoryId(int id)match api/{controller}/{id}, 이것이 프레임 워크를 혼란스럽게 합니다.

기본 API 경로를 다시 작동하고 경로를 유지하려면 {action}어떻게해야합니까? RecordByCategoryIdController기본 API 경로와 일치 하도록 이름이 다른 컨트롤러를 만드는 것을 생각했습니다 .../api/recordbycategoryid/5. 그러나 나는 그것이 "더러운"(따라서 불만족스러운) 해결책이라는 것을 알게되었다. 나는 이것에 대한 답변을 {action}찾았고이 문제를 언급 하는 경로 사용에 대한 자습서가 없습니다 .

답변:


104

경로 엔진은 규칙을 추가 할 때와 동일한 시퀀스를 사용합니다. 첫 번째로 일치하는 규칙을 가져 오면 다른 규칙 확인을 중지하고이를 수행하여 컨트롤러 및 작업을 검색합니다.

따라서 다음을 수행해야합니다.

  1. 특정 규칙을 일반 규칙 (예 : 기본값)보다 먼저 배치합니다. 즉, RouteTable.Routes.MapHttpRoute먼저 "WithActionApi"를 매핑 한 다음 "DefaultApi"를 매핑 하는 데 사용 합니다.

  2. defaults: new { id = System.Web.Http.RouteParameter.Optional }id가 선택 사항이면 "/ api / {part1} / {part2}"와 같은 URL이 "DefaultApi"에 포함되지 않으므로 "WithActionApi"규칙 의 매개 변수를 제거하십시오 .

  3. "DefaultApi"에 명명 된 작업을 추가하여 입력 할 작업을 경로 엔진에 알립니다. 그렇지 않으면 컨트롤러에 하나 이상의 작업이 있으면 엔진은 사용할 작업을 인식하지 못하고 "요청과 일치하는 여러 작업을 찾았습니다 : ..."를 발생시킵니다. 그런 다음 Get 메서드와 일치하도록하려면 ActionNameAttribute를 사용합니다 .

따라서 경로는 다음과 같아야합니다.

// 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 }
);

그리고 컨트롤러 :

[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
위의 조언을 시도했고 모든 것이 예상대로 작동합니다. 그 "비밀"에 대해 대단히 감사합니다.
Mickael Caruso

답변의 포인트 2에서은 id선택 사항 인 경우 라우트에 대해 일치하는 작업이 발견되지 않으면 URL과 같은 URL /api/{part1}/{part2}이 여전히 DefaultApi라우트에 들어갈 수 있습니다 WithActionApi. 내가 틀렸다면 나를 고쳐주세요.
orad

api / {controller} / {action} 만 갖고 싶다면 어떻게 되나요? 이드없이. 다른 사람이 같은 문제에 직면 한 경우. WebApiConfig는 잊어 버리세요. 속성 라우팅에 대해 읽어보십시오.
ahsant

40

속성 라우팅의 도움으로 문제를 해결할 수 있습니다.

제어 장치

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

jquery의 URI

api/category/1

경로 구성

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.
        }
    }
}

기본 라우팅은 기본 규칙 기반 라우팅으로 작동합니다.

제어 장치

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

Jquery의 URI

/api/records/1 

경로 구성

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 }
        );
    }
}

자세한 내용은 검토 기사 속성 라우팅 여기 라우팅 onvention 기반


신의 대답. 하지만 api / {controller} / {action} / {id}를 api / {controller} / {id}와 함께 추가 할 수 없습니까?
카림

속성 라우팅은 문제를 확실히 해결합니다. 한 가지 중요한 점 : Web API 2 이전에는 Web API 프로젝트 템플릿이 다음과 같은 코드를 생성했습니다. protected void Application_Start () {WebApiConfig.Register (GlobalConfiguration.Configuration); } 속성 라우팅이 활성화 된 경우이 코드는 예외를 throw합니다. 속성 라우팅을 사용하도록 기존 Web API 프로젝트를 업그레이드하는 경우이 구성 코드를 다음으로 업데이트해야합니다. protected void Application_Start () {GlobalConfiguration.Configure (WebApiConfig.Register); }
Deeb

0

이 시도.

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

가능한 이유는 ApiController에서 Controller를 상속하지 않았기 때문일 수도 있습니다. 나와 함께 일어난 일을 이해하는 데 시간이 걸렸습니다.


0

경로를 구별하려면 ID가 숫자 여야한다는 제약 조건을 추가해보세요.

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 }
         );  
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.