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

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와 같은 사용자 지정 메서드 이름을 어떻게 호출 할 수 있습니까?



답변

기본적으로 경로 구성은 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하여 사용자를 인증 할 수 있습니다 .


답변

이것은 일반 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 속성을 추가 할 수 있습니다 ‘가져 오기’고.


답변

나는 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}으로 바꾸면 작동하기 시작했습니다. 따라서 분명히 매개 변수 이름은 자리 표시 자의 값과 일치합니다.

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


답변

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


답변

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() .

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


답변

명명 된 작업에 대한 자세한 내용은이 문서를 참조하십시오. 또한 액션 이름 앞에 “get”을 붙이는 대신 [HttpGet] 속성을 사용할 수 있음을 보여줍니다.

http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api


답변

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