ASP.Net Web API GET에 여러 매개 변수를 어떻게 전달해야합니까?


136

.Net MVC4 웹 API를 사용하여 RESTful API를 (희망적으로) 구현하고 있습니다. 시스템에 몇 가지 매개 변수를 전달하고 몇 가지 작업을 수행 한 다음 개체 목록을 결과로 반환해야합니다. 특히 나는 두 날짜를 지나서 그들 사이에있는 레코드를 반환합니다. 또한 후속 호출이 시스템에서 재 처리되지 않도록 반환 된 레코드를 추적하고 있습니다.

몇 가지 접근 방식을 고려했습니다.

  1. 매개 변수를 하나의 단일 JSON 문자열로 직렬화하고 API에서 분리합니다. http://forums.asp.net/t/1807316.aspx/1

  2. 쿼리 문자열에 매개 변수를 전달하십시오.
    여러 쿼리 매개 변수를 편안한 API에 전달하는 가장 좋은 방법은 무엇입니까?

  3. 경로에서 매개 변수 정의 : api / controller / date1 / date2

  4. 본질적으로 매개 변수가있는 객체를 전달할 수있는 POST를 사용합니다.

  5. 웹 API (현재)가 ODATA를 지원하기 때문에 ODATA 연구 나는 아직이 일을 많이하지 않았으므로 익숙하지 않습니다.

적절한 REST 사례는 데이터를 가져올 때 GET을 사용해야 함을 나타냅니다. 그러나 GET은 nullipotent이어야하며 (부작용은 발생하지 않음) API 시스템에 레코드를 표시하여 부작용을 일으키는 특정 구현이 위반되는지 궁금합니다.

또한 변수 매개 변수를 지원하는 문제로 이어졌습니다. 입력 매개 변수 목록이 변경되면 선택 3에 대한 경로를 많이 정의해야하는 번거 로움이 있습니다. 그리고 매개 변수가 런타임에 정의되면 어떻게 될까요?

어쨌든 내 특정 구현의 경우 어떤 선택이 가장 좋습니까?

답변:


10

이 기록 표시는 무엇을 의미합니까? 이것이 로깅 목적으로 만 사용되는 경우이 리소스에 대한 모든 쿼리를 기록하기 때문에 GET을 사용하고 모든 캐싱을 비활성화합니다. 레코드 마킹에 다른 목적이있는 경우 POST를 사용하십시오. 사용자는 자신의 조치가 시스템에 영향을 미치며 POST 방법이 경고임을 알아야합니다.


표시는 단순히 후속 통화가 반복되지 않도록 처리 및 반환되는 레코드를 추적하는 것을 의미합니다. 제 경우에는 다른 테이블에 삽입하여 처리되는 것을 추적하고 있습니다.
sig606

지금은 주로 당신이 말한 이유-행동이 발생하고 소비자가 그 사실을 알고 있기 때문에 POST로 구현했습니다. 또한 다른 데이터를 전달할 때 resp를 사용하면 쉽고 유연 해 보입니다.
sig606

@ sig606 : POST가 나를위한 길이지만 프로토콜은 안전하지 않은 것 같습니다. 클라이언트 측에서 어떤 일이 발생하고 레코드가 검색되지만 버그로 인해 처리되지 않으면 어떻게됩니까? 더 이상 반환하지 않으며 클라이언트에 데이터가 손실됩니다.
LukLed

현재 내 API는 처리 된 후에 만 ​​레코드를 반환합니다. 따라서 소비자는 API에 두 날짜를 전달합니다. 이 두 날짜 사이의 레코드가 처리되고 표시됩니다. 그런 다음 데이터가 호출자에게 반환됩니다. 클라이언트에 도달하기 전에 처리 중 또는 처리 후 문제가 발생하면 문제가 있다고 가정합니다.
sig606

141

가장 쉬운 방법은 단순히 사용하는 것 AttributeRouting입니다.

컨트롤러 내에서 분명합니다. 왜 글로벌 WebApiConfig파일 에서 이것을 원 하십니까?

예:

    [Route("api/YOURCONTROLLER/{paramOne}/{paramTwo}")]
    public string Get(int paramOne, int paramTwo)
    {
        return "The [Route] with multiple params worked";
    }

{}이름은 매개 변수와 일치해야합니다.

간단하지만 이제이 GET인스턴스에서 여러 매개 변수를 처리 하는 별도의 구성 요소가 있습니다.


12
대단하다. 대부분의 사람들은 WebApiConfig파일에 경로를 설정하는 것이 좋지만 실제로는 더 좋습니다.
rhyek

4
실제로, 우리 (대부분의 사람들)는 구성을위한 중앙 집중식 관리 영역을 갖는 것이 좋습니다. 웹 API (Microsoft 또는 기타)의 경우 REST의 중앙 집중식 패턴이 핵심입니다. 속성 라우팅은 귀엽지 만 일회성 예외는 너무 유혹적입니다.
David Betz

3
동의, 실제로 답변을 업데이트해야합니다. GET을 사용하여 여러 매개 변수를 수행하는 훨씬 더 좋은 방법이 있습니다. WebAPI를 처음 사용했을 때 이것을 게시했지만 이제는 새 컨트롤러를 만들고 싶지 않은 경우가 아니라면 AttributeRouting을 사용하지 않고 QueryString의 모든 매개 변수를 전달하면 자동으로 매핑됩니다. 사람들이이 오래된 방법을 사용하지 않도록 기회를 얻었을 때 업데이트
Mark Pieszak-Trilon.io

Route명명 된 매개 변수 (예 : 쿼리 매개 변수) 를 설정하는 방법이 있습니까?
Shimmy Weitzhandler

1
조치 메소드 이름이 필요한 경우이를 수용하도록 수정할 수 있습니다. [Route ( "api / YOURCONTROLLER / Get / {paramOne} / {paramTwo}")] 공개 문자열 Get (int paramOne, int paramTwo) {return "something"; }
Dash

49

WebApiConfig항목에 새 경로를 추가하십시오 .

예를 들어,

public IEnumerable<SampleObject> Get(int pageNumber, int pageSize) { ..

더하다:

config.Routes.MapHttpRoute(
    name: "GetPagedData",
    routeTemplate: "api/{controller}/{pageNumber}/{pageSize}"
);

그런 다음 HTTP 호출에 매개 변수를 추가하십시오.

GET //<service address>/Api/Data/2/10 

10
이것은 모든 부분을 나열하는 유일한 대답 인 것 같습니다. 누군가 api/controller?start=date1&end=date2스타일 URI 를 사용하는 방법을 더 잘 설명하기를 바랍니다 .
핫 릭

@Hick Licks Andrew Veriga의 답변은 쿼리 문자열 인수와 잘 작동합니다. 기본적으로 쿼리 문자열 이름을 클래스 속성에 바인딩하고 메서드에 전달합니다. 메소드는 [FromUri] 속성으로 표시된 단일 클래스 인수를 사용하며 조회 문자열 인수를 특성으로 갖습니다.
David Peterson

좋은 물건. 감사!
Hugo Nava Kopp

안녕하세요 @HotLicks와 GrahamWright이 질문에 대답 할 수 있다고 생각하십니까? 감사합니다. stackoverflow.com/questions/57565318/…

45

매개 변수를 전달 해야하는 RESTfull API를 구현해야했습니다. Mark의 첫 번째 예제 "api / controller? start = date1 & end = date2"에서 설명한 것과 같은 스타일로 쿼리 문자열의 매개 변수를 전달하여이 작업을 수행했습니다.

컨트롤러 에서 C #의 URL 분할 팁을 사용 했습니까?

// uri: /api/courses
public IEnumerable<Course> Get()
{
    NameValueCollection nvc = HttpUtility.ParseQueryString(Request.RequestUri.Query);
    var system = nvc["System"];
    // BL comes here
    return _courses;
}

제 경우에는 Ajax를 통해 WebApi를 다음과 같이 호출했습니다.

$.ajax({
        url: '/api/DbMetaData',
        type: 'GET',
        data: { system : 'My System',
                searchString: '123' },
        dataType: 'json',
        success: function (data) {
                  $.each(data, function (index, v) {
                  alert(index + ': ' + v.name);
                  });
         },
         statusCode: {
                  404: function () {
                       alert('Failed');
                       }
        }
   });

이게 도움이 되길 바란다...


2
ParameterBinding이 쿼리 스트링을 API 메소드 매개 변수에 자동으로 매핑하기 때문에 WebApi를 사용하지 않는 것 같습니다.
emp

1
예, 더 나은 방법은 [Route ( "api / DbMetaData / {system} / {searchString}")]와 같은 속성을 사용하고 Get (string system, string searchString)에 매개 변수를 추가 한 다음 " ... api / DbMetaData / mysystem / mysearchstring "
Nigel Findlater

C # MVC WebApi에서 그의 예제를 사용했으며 정상적으로 작동했습니다. 예를 들어 +1
Si8

38

http://habrahabr.ru/post/164945/ 에서 우수 솔루션을 찾았습니다 .

public class ResourceQuery
{
   public string Param1 { get; set; }
   public int OptionalParam2 { get; set; }
}

public class SampleResourceController : ApiController
{
    public SampleResourceModel Get([FromUri] ResourceQuery query)
    {
        // action
    }
}

5
여기에서 힌트는 [FromUri]
트랜스 포터

2
기사는 러시아어로되어 있지만 @tranceporter가 맞습니다. "FromUri"는 URL에서 매개 변수를 가져 오는 좋은 방법입니다. 도움이 될만한 다른 기사 : asp.net/web-api/overview/formats-and-model-binding/…
Greg Greg

이것은 내가 지금 꽤 오랫동안 해왔으며 훌륭하게 작동했습니다! 이 솔루션도 추천합니다.
David Peterson

을 제외한 다른 도우미 메서드를 호출 Get해도 여전히 사용할 수 [FromUri]있습니까? 나는 그것을 작동시키지 못하는 것 같습니다.
jocull

8

사용 GET을 또는 POST는 명확 의해 설명 @LukLed . 매개 변수를 전달할 수있는 방법과 관련하여 두 번째 접근 방식을 제안하는 것이 좋습니다 ( ODATA대해서도 많이 알지 못함 ).

1. 매개 변수를 하나의 단일 JSON 문자열로 직렬화하고 API에서 분리합니다. http://forums.asp.net/t/1807316.aspx/1

사용자 친화적 이고 SEO 친화적 이지 않습니다

쿼리 문자열에 매개 변수를 전달하십시오. 여러 쿼리 매개 변수를 편안한 API에 전달하는 가장 좋은 방법은 무엇입니까?

이것이 일반적으로 선호되는 접근 방식입니다.

경로의 매개 변수 정의 : api / controller / date1 / date2

이것은 좋은 접근 방식이 아닙니다. 이것은 어떤 것이 하나 date2의 하위 리소스 라고 느끼게하지만 date1그렇지 않습니다. date1date2매개 변수는 모두 쿼리 매개 변수이며 동일한 수준으로 제공됩니다.

간단한 경우에는 이와 같은 URI를 제안합니다.

api/controller?start=date1&end=date2

그러나 개인적으로 아래 URI 패턴을 좋아하지만이 경우 매개 변수를 매핑하기 위해 사용자 지정 코드를 작성해야합니다.

api/controller/date1,date2

사실, 그것들은 나의 오리지널 설명이었습니다. LukLed가 내 태그와 URL 링크를 빛낸 것 같습니다.
sig606

SEO의 경우에는 적용되지 않습니다. 이 코드는 "서버 간"이므로 외부 세계에서이 코드를 발견했는지는 상관하지 않습니다. 실제로 임의 액세스를 피하기 위해 적절한 보안 단계를 수행해야합니다. 시스템의 다른 부분에 대해 JSON 직렬화를 수행해야했습니다 (큰 obj 목록을 POST하려고하는 버그로 간주되어 문자열로 직렬화해야 했으므로).이 경우에는 크게 늘어나지 않습니다. .
sig606

1
나는 당신이 이미 답변을하고 왜 당신이 질문을하고 싶습니다 바랍니다?
VJAI

2
답변이 늦어서 죄송합니다, 마크 몇 가지 솔루션을 시도했지만 어느 것이 가장 좋은지 확실하지 않았으며 업계 표준 접근 방식을 고수하려고했기 때문에 여기 SO에 게시했습니다.
sig606

1
@Mark 다음으로 좋아하는 것 : stackoverflow.com/questions/9681658/… ?
RredCat


3
 [Route("api/controller/{one}/{two}")]
    public string Get(int One, int Two)
    {
        return "both params of the root link({one},{two}) and Get function parameters (one, two)  should be same ";
    }

루트 링크 ({one}, {two}) 및 Get 함수 매개 변수 (1, 2)의 매개 변수는 동일해야합니다.


2

나는 이것이 정말로 오래되었다는 것을 알고 있지만 최근에 같은 것을 원했고 여기에 내가 찾은 것이 있습니다 ...

    public HttpResponseMessage Get([FromUri] string var, [FromUri] string test) {
        var retStr = new HttpResponseMessage(HttpStatusCode.OK);
        if (var.ToLower() == "getnew" && test.ToLower() == "test") {
            retStr.Content = new StringContent("Found Test", System.Text.Encoding.UTF8, "text/plain");
        } else {
            retStr.Content = new StringContent("Couldn't Find that test", System.Text.Encoding.UTF8, "text/plain");
        }

        return retStr;
    }

이제 귀하의 주소 / URI / ...

http (s) : // myURL / api / myController /? var = getnew & test = test

결과 : "발견 된 테스트"


http (s) : // myURL / api / myController /? var = getnew & test = anything

결과 : "테스트를 찾을 수 없습니다"


원래 방법의 서명을 변경하고 라우팅 구성을 조정하지 않고도 달성하려는 작업을 정확하게 오버로드 할 수 있기 때문에 개인적으로 C # 에서이 스타일을 좋아합니다. 그것이 GET 요청을하는이 (구식적인) 접근법에 익숙한 다른 사람들에게 도움이되기를 바랍니다.
Rick Riggs

1
이 방법을 사용하는 타사 캘린더 앱에서 사용하는 이벤트 API를 만들어야했습니다. 이 답변을 찾았습니다.
clayRay


0
    public HttpResponseMessage Get(int id,string numb)
    {
        //this will differ according to your entity name
        using (MarketEntities entities = new MarketEntities())
        {
          var ent=  entities.Api_For_Test.FirstOrDefault(e => e.ID == id && e.IDNO.ToString()== numb);
            if (ent != null)
            {
                return Request.CreateResponse(HttpStatusCode.OK, ent);
            }
            else
            {
                return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Applicant with ID " + id.ToString() + " not found in the system");
            }
        }
    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.