ASP.NET Web API의 사용자 지정 메서드 이름


110

WCF 웹 API에서 새로운 ASP.NET MVC 4 웹 API로 변환하고 있습니다. UsersController가 있고 Authenticate라는 메서드를 갖고 싶습니다. GetAll, GetOne, Post 및 Delete를 수행하는 방법에 대한 예가 있지만 이러한 서비스에 추가 메소드를 추가하려면 어떻게해야합니까? 예를 들어, 내 UsersService에는 사용자 이름과 암호를 전달하는 Authenticate라는 메서드가 있어야하지만 작동하지 않습니다.

public class UsersController : BaseApiController
{
    public string GetAll()
    {
        return "getall!";
    }

    public string Get(int id)
    {
        return "get 1! " + id;
    }

    public User GetAuthenticate(string userName, string password, string applicationName)
    {
        LogWriter.Write(String.Format("Received authenticate request for username {0} and password {1} and application {2}",
            userName, password, applicationName));

        //check if valid leapfrog login.
        var decodedUsername = userName.Replace("%40", "@");
        var encodedPassword = password.Length > 0 ? Utility.HashString(password) : String.Empty;
        var leapFrogUsers = LeapFrogUserData.FindAll(decodedUsername, encodedPassword);

        if (leapFrogUsers.Count > 0)
        {
            return new User
            {
                Id = (uint)leapFrogUsers[0].Id,
                Guid = leapFrogUsers[0].Guid
            };
        }
        else
            throw new HttpResponseException("Invalid login credentials");
    }
}

myapi / api / users /로 이동하면 GetAll이 호출되고 myapi / api / users / 1로 이동하면 Get이 호출됩니다.하지만 myapi / api / users / authenticate? username = {0}을 호출하면 & password = {1} 그러면 Get (인증되지 않음) 및 오류가 호출됩니다.

매개 변수 사전에 'Navtrak.Services.WCF.NavtrakAPI.Controllers.UsersController'의 메소드 'System.String Get (Int32)'에 대해 널 입력이 불가능한 유형 'System.Int32'의 매개 변수 'id'에 대한 널 항목이 있습니다. 선택적 매개 변수는 참조 유형이거나 널 입력 가능 유형이거나 선택적 매개 변수로 선언되어야합니다.

Authenticate와 같은 사용자 지정 메서드 이름을 어떻게 호출 할 수 있습니까?


이 링크를 참조하십시오 : 5th answer stackoverflow.com/questions/12775590/…
Vishwa G

답변:


137

기본적으로 경로 구성은 RESTFul 규칙을 따릅니다. 즉, Get, Post, Put 및 Delete 작업 이름 만 허용합니다 (기본적으로 global.asax =>에서 경로를 확인하면 작업 이름을 지정할 수 없습니다 =>. HTTP 동사를 사용하여 디스패치). 따라서 GET 요청을 보낼 때 /api/users/authenticate기본적으로 Get(int id)액션을 호출하고 id=authenticateGet 액션이 정수를 기대하기 때문에 분명히 충돌 하는 것을 전달 합니다.

표준 작업 이름과 다른 작업 이름을 원하면 다음에서 경로 정의를 수정할 수 있습니다 global.asax.

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

이제로 이동 /api/values/getauthenticate하여 사용자를 인증 할 수 있습니다 .


20
다른 작업을 허용하면서 Get (id), Get () Put, Delete, Post를 계속 사용하도록하는 방법이 있습니까?
Shawn Mclean 2012 년

@ShawnMclean 나는 또는 (또는 무엇이든)이 일치하지 않도록 {action}제약 조건이 없는 다른 경로를 지정할 수 있다고 생각합니다 . 그런 다음 대린에 의해 제안 하나를 통해 떨어질 수있을 것입니다{id}intGuid
스티브 Greatrex

2
여기서 한 가지 더 중요한 점은 이러한 라우팅 스타일을 사용하면 속성을 사용하여 허용 된 HTTP 메서드 (예 : [HttpGet])를 지정해야한다는 것입니다.
히말라야 Garg를

1
다른 작업을 사용해야합니까? REST 규칙 내에서 수행중인 작업을 실제로 맞추려고 노력 했습니까? 다른 작업을 사용할 필요는 없습니다.
niico

1
@niico : Get ()이 반환 할 요소의 수를 반환하는 Count () 메서드가 필요하다고 가정 해보십시오. 나는 그것을 Get (), Get (id), Post (...), Put (...) 또는 Delete (id)에 맞추는 방법을 알지 못합니다. 그리고 물론 제가 상상할 수있는 방법이 무한히 더 많습니다.
옌스 MANDER

88

이것은 일반 REST 메서드도 지원하면서 추가 GET 메서드를 통합하기 위해 지금까지 생각 해낸 최고의 방법입니다. WebApiConfig에 다음 경로를 추가하십시오.

routes.MapHttpRoute("DefaultApiWithId", "Api/{controller}/{id}", new { id = RouteParameter.Optional }, new { id = @"\d+" });
routes.MapHttpRoute("DefaultApiWithAction", "Api/{controller}/{action}");
routes.MapHttpRoute("DefaultApiGet", "Api/{controller}", new { action = "Get" }, new { httpMethod = new HttpMethodConstraint(HttpMethod.Get) });
routes.MapHttpRoute("DefaultApiPost", "Api/{controller}", new {action = "Post"}, new {httpMethod = new HttpMethodConstraint(HttpMethod.Post)});

아래 테스트 클래스에서이 솔루션을 확인했습니다. 아래 컨트롤러에서 각 방법을 성공적으로 칠 수있었습니다.

public class TestController : ApiController
{
    public string Get()
    {
        return string.Empty;
    }

    public string Get(int id)
    {
        return string.Empty;
    }

    public string GetAll()
    {
        return string.Empty;
    }

    public void Post([FromBody]string value)
    {
    }

    public void Put(int id, [FromBody]string value)
    {
    }

    public void Delete(int id)
    {
    }
}

다음 요청을 지원하는지 확인했습니다.

GET /Test
GET /Test/1
GET /Test/GetAll
POST /Test
PUT /Test/1
DELETE /Test/1

참고 하여 추가 GET 작업이 시작되지 않는 경우이 방법에 HttpGet 속성을 추가 할 수 있습니다 '가져 오기'고.


1
좋은 해결책은 내가 구성하는 경우, 당신은 내게 말할 수 putdelete당신이 그랬던 것처럼 동사 등을 get하고 post, 너무 잘 작동합니다?
Felipe Oriani 2013 년

1
제 생각에 이것은 WebAPI 프로젝트의 기본값에 포함되어야합니다 (아마도 주석 처리됨). 그것은 ... 같은 시간에 당신에게 WebAPI 및 MVC 스타일의 경로를 제공합니다
존 Culviner에게

1
@FelipeOriani, 이러한 요청은 일반적으로 해당 작업을 적용하려는 리소스를 식별하기 위해 id 매개 변수와 함께 제공되므로 구성 put또는 delete동사 가 필요하거나 필요하지 않을 것이라고 생각합니다 . delete호출하기 /api/foo삭제하려고하는 foo에 있기 때문에 오류가 발생한다? 따라서 DefaultApiWithId 경로는 이러한 경우를 잘 처리해야합니다.
nwayve

4
이것은 나를 위해 전혀 작동하지 않았습니다. 기본 GET을 시도 할 때 오류 메시지가 나타납니다.
Matt

첫 번째 DefaultApiWithId의 경우 기본값이 new {id = RouteParameter.Optional} 대신 null이어야하지 않습니까? 'ID'가 필요하지 않습니까?
Johnny Oshika 2014 년

22

나는 MVC4 세계에 들어갔다.

그 가치를 위해 SitesAPIController가 있고 다음과 같이 호출 할 수있는 사용자 지정 메서드가 필요했습니다.

http://localhost:9000/api/SitesAPI/Disposition/0

마지막 매개 변수에 대해 다른 값을 사용하여 처리가 다른 레코드를 가져옵니다.

마지막으로 나를 위해 일한 것은 다음과 같습니다.

SitesAPIController의 메소드 :

// GET api/SitesAPI/Disposition/1
[ActionName("Disposition")]
[HttpGet]
public Site Disposition(int disposition)
{
    Site site = db.Sites.Where(s => s.Disposition == disposition).First();
    return site;
}

그리고 이것은 WebApiConfig.cs에서

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

// this i added
config.Routes.MapHttpRoute(
    name: "Action",
    routeTemplate: "api/{controller}/{action}/{disposition}"
 );

{disposition}을 {id}로 명명하는 동안 다음과 같은 문제가 발생했습니다.

{
"Message": "No HTTP resource was found that matches the request URI 'http://localhost:9000/api/SitesAPI/Disposition/0'.",
"MessageDetail": "No action was found on the controller 'SitesAPI' that matches the request."
}

이름을 {disposition}으로 바꾸면 작동하기 시작했습니다. 따라서 분명히 매개 변수 이름은 자리 표시 자의 값과 일치합니다.

이 답변을 더 정확하고 설명하기 위해 자유롭게 편집하십시오.


팁 고마워. 당신과 같은 실수를 저질렀습니다.
abhi

16

Web Api는 기본적으로이 기본 라우팅을 재정의하기 위해 api / {controller} / {id} 형식의 URL을 예상합니다. 아래 두 가지 방법 중 하나로 라우팅을 설정할 수 있습니다.

첫 번째 옵션 :

WebApiConfig.cs에 아래 경로 등록 추가

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

아래와 같이 HttpGet 및 매개 변수로 작업 메서드를 장식하십시오.

[HttpGet]
public HttpResponseMessage ReadMyData(string param1,
                        string param2, string param3)

 {

// your code here

}

위의 메소드 url을 호출하면 다음과 같습니다.

http : // localhost : [yourport] / api / MyData / ReadMyData? param1 = value1 & param2 = value2 & param3 = value3

두 번째 옵션 컨트롤러 클래스에 경로 접두사를 추가하고 아래와 같이 HttpGet으로 작업 메서드를 장식합니다. 이 경우 WebApiConfig.cs를 변경할 필요가 없습니다. 기본 라우팅을 가질 수 있습니다.

[RoutePrefix("api/{controller}/{action}")]
public class MyDataController : ApiController
{

[HttpGet]
public HttpResponseMessage ReadMyData(string param1,
                        string param2, string param3)

{

// your code here

}

}

위의 메소드 url을 호출하면 다음과 같습니다.

http : // localhost : [yourport] / api / MyData / ReadMyData? param1 = value1 & param2 = value2 & param3 = value3


나는 두 번째 옵션을 매우 좋아합니다. VB.net에서 사용하는 방법도 보여줄 수 있습니까? 감사합니다.
user1617676

12

ASP.NET MVC 6 과 함께 ASP.NET 5 를 사용하는 경우 일반적으로 MVC가 기본 RESTful 규칙을 사용하여 적절한 경로 컬렉션을 만들 수 있기 때문에 이러한 답변의 대부분은 작동하지 않습니다. 당신은 아무것도 찾을 수 없습니다Routes.MapRoute() 편집 전화를 .

ConfigureServices()에 의해 호출 된 메소드 Startup.cs는 호출 할 때 그런 식으로, : 파일은 ASP.NET 5에 내장 된 의존성 주입 프레임 워크 MVC를 등록합니다 ApplicationBuilder.UseMvc()클래스에서 후, MVC 프레임 워크는 자동으로 앱이 기본 경로를 추가합니다. UseMvc()프레임 워크 소스 코드 내에서 메서드 구현 을 살펴보면 내부에서 어떤 일이 발생하는지 살펴볼 수 있습니다 .

public static IApplicationBuilder UseMvc(
    [NotNull] this IApplicationBuilder app,
    [NotNull] Action<IRouteBuilder> configureRoutes)
{
    // Verify if AddMvc was done before calling UseMvc
    // We use the MvcMarkerService to make sure if all the services were added.
    MvcServicesHelper.ThrowIfMvcNotRegistered(app.ApplicationServices);

    var routes = new RouteBuilder
    {
        DefaultHandler = new MvcRouteHandler(),
        ServiceProvider = app.ApplicationServices
    };

    configureRoutes(routes);

    // Adding the attribute route comes after running the user-code because
    // we want to respect any changes to the DefaultHandler.
    routes.Routes.Insert(0, AttributeRouting.CreateAttributeMegaRoute(
        routes.DefaultHandler,
        app.ApplicationServices));

    return app.UseRouter(routes.Build());
}

이것에 대한 좋은 점은 프레임 워크가 이제 모든 어려운 작업을 처리하고 컨트롤러의 모든 작업을 반복하고 기본 경로를 설정하여 중복 작업을 절약한다는 것입니다.

나쁜 점은 자신의 경로를 추가하는 방법에 대한 문서가 거의 또는 전혀 없다는 것입니다. 다행히도 컨벤션 기반 및 / 또는 특성 기반 접근 방식 (일명 특성 라우팅 ) 을 사용하여 쉽게 수행 할 수 있습니다 .

컨벤션 기반

Startup.cs 클래스에서 다음을 바꿉니다.

app.UseMvc();

이것으로 :

app.UseMvc(routes =>
            {
                // Route Sample A
                routes.MapRoute(
                    name: "RouteSampleA",
                    template: "MyOwnGet",
                    defaults: new { controller = "Items", action = "Get" }
                );
                // Route Sample B
                routes.MapRoute(
                    name: "RouteSampleB",
                    template: "MyOwnPost",
                    defaults: new { controller = "Items", action = "Post" }
                );
            });

속성 기반

MVC6에 대한 좋은 것은 당신이 또한 중 하나를 장식하여 당 컨트롤러 기준으로 경로를 정의 할 수 있다는 것입니다 Controller클래스 및 / 또는 Action적절한와 방법 RouteAttribute및 / 또는 HttpGet/ HttpPost다음과 같은 템플릿 매개 변수를 :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc;

namespace MyNamespace.Controllers
{
    [Route("api/[controller]")]
    public class ItemsController : Controller
    {
        // GET: api/items
        [HttpGet()]
        public IEnumerable<string> Get()
        {
            return GetLatestItems();
        }

        // GET: api/items/5
        [HttpGet("{num}")]
        public IEnumerable<string> Get(int num)
        {
            return GetLatestItems(5);
        }       

        // GET: api/items/GetLatestItems
        [HttpGet("GetLatestItems")]
        public IEnumerable<string> GetLatestItems()
        {
            return GetLatestItems(5);
        }

        // GET api/items/GetLatestItems/5
        [HttpGet("GetLatestItems/{num}")]
        public IEnumerable<string> GetLatestItems(int num)
        {
            return new string[] { "test", "test2" };
        }

        // POST: /api/items/PostSomething
        [HttpPost("PostSomething")]
        public IActionResult Post([FromBody]string someData)
        {
            return Content("OK, got it!");
        }
    }
}

이 컨트롤러는 다음 요청을 처리합니다.

 [GET] api/items
 [GET] api/items/5
 [GET] api/items/GetLatestItems
 [GET] api/items/GetLatestItems/5
 [POST] api/items/PostSomething

또한 두 가지 접근 방식을 사용하는 경우 속성 기반 경로 (정의 된 경우)가 규칙 기반 경로를 재정의하고 둘 다에 의해 정의 된 기본 경로를 재정의합니다. UseMvc() .

자세한 내용 은 내 블로그 에서 다음 게시물읽을 수도 있습니다 .


1
이것은 완벽 해요! 다른 답변은 실제로 내가 필요한 것을 수행하지 않았습니다. 하지만 당신은 나를 구했습니다 :)
아서 왕 3 세 3

미리 정의 된 모델을 두 번째 매개 변수로 사용하는 방법이 있습니까? 나는이 같은 특정 사용자 패치있을 때 예를 들어, : public IActionResult Patch(int id, [FromQuery] Person person), 들어오는 모든 속성이 null입니다!
아서 왕 3 세 3


0

WebAPIConfig.cs를 다음과 같이 수정하십시오.

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

그런 다음 API를 다음과 같이 구현하십시오.

    // GET: api/Controller_Name/Show/1
    [ActionName("Show")]
    [HttpGet]
    public EventPlanner Id(int id){}

0

Web APi 2 및 이후 버전은 속성 라우팅이라는 새로운 유형의 라우팅을 지원합니다. 이름에서 알 수 있듯이 속성 라우팅은 속성을 사용하여 경로를 정의합니다. 속성 라우팅을 사용하면 웹 API의 URI를 더 세부적으로 제어 할 수 있습니다. 예를 들어 리소스 계층을 설명하는 URI를 쉽게 만들 수 있습니다.

예를 들면 :

[Route("customers/{customerId}/orders")]
public IEnumerable<Order> GetOrdersByCustomer(int customerId) { ... }

완벽 할 것이며 예를 들어 WebApiConfig.cs에서 추가 코드가 필요하지 않습니다. WebApiConfig.cs에서 웹 API 라우팅이 활성화되어 있는지 확인하기 만하면됩니다. 그렇지 않은 경우 아래와 같이 활성화 할 수 있습니다.

        // Web API routes
        config.MapHttpAttributeRoutes();

WebApiConfig.cs에서 더 많은 작업을 수행하거나 변경할 필요가 없습니다. 자세한 내용은 이 기사를 참조하십시오 .

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