[C#] 웹 API 컨트롤러의 다중 HttpPost 메소드

MVC4 Web API 프로젝트를 사용하기 시작했으며 여러 HttpPost방법 이있는 컨트롤러가 있습니다. 컨트롤러는 다음과 같습니다.

제어 장치

public class VTRoutingController : ApiController
{
    [HttpPost]
    public MyResult Route(MyRequestTemplate routingRequestTemplate)
    {
        return null;
    }

    [HttpPost]
    public MyResult TSPRoute(MyRequestTemplate routingRequestTemplate)
    {
        return null;
    }
}

다음 MyRequestTemplate은 요청을 통해 오는 Json을 처리하는 템플릿 클래스를 나타냅니다.

오류:

Fiddler를 사용하여 요청 http://localhost:52370/api/VTRouting/TSPRoute하거나 http://localhost:52370/api/VTRouting/Route 오류가 발생하면 :

요청과 일치하는 여러 조치가 발견되었습니다.

위의 방법 중 하나를 제거하면 정상적으로 작동합니다.

Global.asax

에서 기본 라우팅 테이블을 수정하려고 시도했지만 global.asax여전히 오류가 발생합니다. global.asax에서 경로를 정의하는 데 문제가 있다고 생각합니다. 다음은 global.asax에서하는 일입니다.

public static void RegisterRoutes(RouteCollection routes)
{
    routes.MapHttpRoute(
        name: "MyTSPRoute",
        routeTemplate: "api/VTRouting/TSPRoute",
        defaults: new { }
    );

    routes.MapHttpRoute(
        name: "MyRoute",
        routeTemplate: "api/VTRouting/Route",
        defaults: new { action="Route" }
    );
}

POST를 사용하여 Fiddler에서 요청을하고 MyRequestTemplate의 RequestBody에서 json을 전달합니다.



답변

단일 컨트롤러에서 여러 작업을 수행 할 수 있습니다.

이를 위해서는 다음 두 가지를 수행해야합니다.

  • 먼저 다음과 ActionName같은 속성 으로 작업을 장식하십시오.

     [ActionName("route")]
     public class VTRoutingController : ApiController
     {
       [ActionName("route")]
       public MyResult PostRoute(MyRequestTemplate routingRequestTemplate)
       {
         return null;
       }
    
      [ActionName("tspRoute")]
      public MyResult PostTSPRoute(MyRequestTemplate routingRequestTemplate)
      {
         return null;
      }
    }
    
  • 둘째, WebApiConfig파일 에서 다음 경로를 정의 하십시오.

    // Controller Only
    // To handle routes like `/api/VTRouting`
    config.Routes.MapHttpRoute(
        name: "ControllerOnly",
        routeTemplate: "api/{controller}"               
    );
    
    
    // Controller with ID
    // To handle routes like `/api/VTRouting/1`
    config.Routes.MapHttpRoute(
        name: "ControllerAndId",
        routeTemplate: "api/{controller}/{id}",
        defaults: null,
        constraints: new { id = @"^\d+$" } // Only integers 
    );
    
    // Controllers with Actions
    // To handle routes like `/api/VTRouting/route`
    config.Routes.MapHttpRoute(
        name: "ControllerAndAction",
        routeTemplate: "api/{controller}/{action}"
    );
    

답변

문제에 대한 훨씬 더 나은 해결책 Route은 주석으로 메소드의 경로를 지정할 수있는 사용 하는 것입니다 .

[RoutePrefix("api/VTRouting")]
public class VTRoutingController : ApiController
{
    [HttpPost]
    [Route("Route")]
    public MyResult Route(MyRequestTemplate routingRequestTemplate)
    {
        return null;
    }

    [HttpPost]
    [Route("TSPRoute")]
    public MyResult TSPRoute(MyRequestTemplate routingRequestTemplate)
    {
        return null;
    }
}


답변

사용하다:

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

더 이상 RESTful 접근 방식은 아니지만 이제 웹 API가 동사를 기반으로 자동으로 결정하도록하는 대신 이름으로 작업을 호출 할 수 있습니다.

[POST] /api/VTRouting/TSPRoute

[POST] /api/VTRouting/Route

일반적인 생각과는 달리이 방법에는 아무런 문제가 없으며 웹 API를 남용하지 않습니다. Web API의 모든 멋진 기능 (델리 게이터, 콘텐츠 협상, 미디어 형식 포맷터 등)을 여전히 활용할 수 있습니다. RESTful 방식을 버릴뿐입니다.


답변

웹 API 엔드 포인트 (컨트롤러)는 get / post / put / delete 동사를 허용하는 단일 리소스입니다. 일반적인 MVC 컨트롤러 가 아닙니다 .

필요한 경우 보내는 매개 변수를 허용하는 하나의 HttpPost 메서드 /api/VTRouting만있을 수 있습니다 . [http] 항목으로 꾸미는 한 함수 이름 은 중요하지 않습니다 . 그래도 시도한 적이 없습니다.

편집 : 작동하지 않습니다. 해결하면 유형에 모델 바인딩을 시도하지 않고 매개 변수의 수를 따르는 것 같습니다.

다른 매개 변수를 허용하도록 함수를 오버로드 할 수 있습니다. 나는 당신이하는 방식으로 선언했지만 메소드에 다른 (호환되지 않는) 매개 변수를 사용하면 괜찮을 것이라고 확신합니다. 매개 변수가 동일하면 모델 바인딩이 어떤 것을 의미하는지 알 수 없으므로 운이 좋지 않습니다.

[HttpPost]
public MyResult Route(MyRequestTemplate routingRequestTemplate) {...}

[HttpPost]
public MyResult TSPRoute(MyOtherTemplate routingRequestTemplate) {...}

이 부분은 작동합니다

새 템플릿을 만들 때 제공되는 기본 템플릿은 이것을 매우 명백하게 만듭니다.이 규칙을 고수해야한다고 말하고 싶습니다.

public class ValuesController : ApiController
{
    // GET is overloaded here.  one method takes a param, the other not.
    // GET api/values  
    public IEnumerable<string> Get() { .. return new string[] ... }
    // GET api/values/5
    public string Get(int id) { return "hi there"; }

    // POST api/values (OVERLOADED)
    public void Post(string value) { ... }
    public void Post(string value, string anotherValue) { ... }
    // PUT api/values/5
    public void Put(int id, string value) {}
    // DELETE api/values/5
    public void Delete(int id) {}
}

많은 작업을 수행하는 하나의 클래스를 Ajax 사용을 위해 만들고 싶다면 표준 컨트롤러 / 액션 패턴을 사용하지 않는 큰 이유가 없습니다. 유일한 차이점은 메소드 서명이 예쁘지 않다는 것이므로 Json( returnValue)반환하기 전에 물건을 감싸 야 합니다.

편집하다:

간단한 유형을 사용할 때 표준 템플릿 (포함하도록 편집)을 사용할 때 오버로드가 제대로 작동합니다. 다른 서명을 가진 2 개의 사용자 정의 객체를 사용하여 다른 방법으로 테스트했습니다. 그것을 작동시킬 수 없었습니다.

  • 복잡한 객체와의 바인딩은 “깊게”보이지 않으므로 그렇게 할 필요가 없습니다.
  • 쿼리 문자열에 추가 매개 변수를 전달하여이 문제를 해결할 수 있습니다.
  • 사용 가능한 옵션을 제공 할 수있는 것보다 더 나은 기록

이것은이 경우 나를 위해 일했습니다, 그것이 당신을 얻는 곳을보십시오. 테스트 만 예외입니다.

public class NerdyController : ApiController
{
    public void Post(string type, Obj o) {
        throw new Exception("Type=" + type + ", o.Name=" + o.Name );
    }
}

public class Obj {
    public string Name { get; set; }
    public string Age { get; set; }
}

그리고 콘솔에서 다음과 같이 호출됩니다.

$.post("/api/Nerdy?type=white", { 'Name':'Slim', 'Age':'21' } )


답변

동일한 Web API Controller에 여러 Get 및 Post 메소드를 추가 할 수 있습니다. 여기서 기본 경로는 문제를 일으키는 것입니다. 웹 API는 위에서 아래로 일치하는 경로를 확인하므로 모든 요청에 ​​대해 기본 경로가 일치합니다. 기본 경로에 따라 하나의 제어기에서 단 하나의 Get and Post 메소드 만 가능합니다. 다음 코드를 맨 위에 배치하거나 주석 처리 / 삭제 기본 경로

    config.Routes.MapHttpRoute("API Default",
                               "api/{controller}/{action}/{id}",
                               new { id = RouteParameter.Optional });


답변

컨트롤러 수준에서 경로 접두사 [RoutePrefix ( “api / Profiles”)]를 넣고 동작 방법 [Route ( “LikeProfile”)]에 경로를 붙입니다. global.asax 파일에서 아무것도 변경할 필요가 없습니다.

namespace KhandalVipra.Controllers
{
    [RoutePrefix("api/Profiles")]
    public class ProfilesController : ApiController
    {
        // POST: api/Profiles/LikeProfile
        [Authorize]
        [HttpPost]
        [Route("LikeProfile")]
        [ResponseType(typeof(List<Like>))]
        public async Task<IHttpActionResult> LikeProfile()
        {
        }
    }
}


답변

나는 그 질문에 이미 대답했다고 생각합니다. 또한 서명 된 mehtod는 있지만 이름은 다른 webApi 컨트롤러를 찾고있었습니다. WebApi로 계산기를 구현하려고했습니다. 계산기에는 서명은 같지만 이름이 다른 4 가지 방법이 있습니다.

public class CalculatorController : ApiController
{
    [HttpGet]
    [ActionName("Add")]
    public string Add(int num1 = 1, int num2 = 1, int timeDelay = 1)
    {
        Thread.Sleep(1000 * timeDelay);
        return string.Format("Add = {0}", num1 + num2);
    }

    [HttpGet]
    [ActionName("Sub")]
    public string Sub(int num1 = 1, int num2 = 1, int timeDelay = 1)
    {
        Thread.Sleep(1000 * timeDelay);
        return string.Format("Subtract result = {0}", num1 - num2);
    }

    [HttpGet]
    [ActionName("Mul")]
    public string Mul(int num1 = 1, int num2 = 1, int timeDelay = 1)
    {
        Thread.Sleep(1000 * timeDelay);
        return string.Format("Multiplication result = {0}", num1 * num2);
    }

    [HttpGet]
    [ActionName("Div")]
    public string Div(int num1 = 1, int num2 = 1, int timeDelay = 1)
    {
        Thread.Sleep(1000 * timeDelay);
        return string.Format("Division result = {0}", num1 / num2);
    }
}

WebApiConfig 파일에는 이미

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

IIS에서 인증 / 권한을 설정하기 만하면됩니다!

도움이 되었기를 바랍니다!