Development Tip

속성 라우팅을 사용하는 동안 쿼리 문자열이 작동하지 않음

yourdevel 2020. 12. 3. 20:40
반응형

속성 라우팅을 사용하는 동안 쿼리 문자열이 작동하지 않음


Web API 2 응용 프로그램에 대해 더 깨끗한 URL을 사용 System.Web.Http.RouteAttribute하고 System.Web.Http.RoutePrefixAttribute있습니다. 대부분의 요청에 대해 라우팅 (예 :)을 사용 Controller/param1/param2하거나 쿼리 문자열 (예 :)을 사용할 수 있습니다 Controller?param1=bob&param2=mary.

불행히도 내 컨트롤러 중 하나 (하나만)를 사용하면 실패합니다. 내 컨트롤러는 다음과 같습니다.

[RoutePrefix("1/Names")]
public class NamesController : ApiController
{

    [HttpGet]
    [Route("{name}/{sport}/{drink}")]
    public List<int> Get(string name, string sport, string drink)
    {
        // Code removed...
    }

    [HttpGet]
    [Route("{name}/{drink}")]
    public List<int> Get(string name, string drink)
    {
        // Code removed...
    }
}

라우팅을 사용하여 요청하면 둘 다 잘 작동합니다. 그러나 쿼리 문자열을 사용하면 실패하고 해당 경로가 존재하지 않는다는 메시지가 표시됩니다.

WebApiConfig.cs클래스의 Register(HttpConfiguration config)함수 (기본 경로 전후)에 다음을 추가하려고 시도했지만 아무 작업도 수행하지 않았습니다.

config.Routes.MapHttpRoute(
name: "NameRoute",
routeTemplate: "{verId}/Names/{name}/{sport}/{drink}",
defaults: new { name = RouteParameter.Optional, sport = RouteParameter.Optional, drink = RouteParameter.Optional },
constraints: new { verId = @"\d+" });

따라서 명확성을 위해 다음 두 가지를 모두 수행하고 싶습니다.

localhost:12345/1/Names/Ted/rugby/coke
localhost:12345/1/Names/Ted/coke

과,

localhost:12345/1/Names?name=Ted&sport=rugby&drink=coke
localhost:12345/1/Names?name=Ted&drink=coke

하지만 슬프게도 쿼리 문자열 버전은 작동하지 않습니다! :(

업데이트 됨

두 번째 Action을 모두 제거하고 이제 선택적 매개 변수와 함께 단일 Action을 사용하려고합니다. [Route("{name}/{drink}/{sport?}")]Tony가 스포츠를 nullable로 만들도록 제안한대로 경로 속성을 변경 했지만 이제 localhost:12345/1/Names/Ted/coke어떤 이유로 든 유효한 경로가되지 않습니다. 쿼리 문자열은 이전과 동일한 방식으로 작동합니다.

업데이트 2 이제 컨트롤러에 단일 작업이 있습니다.

[RoutePrefix("1/Names")]
public class NamesController : ApiController
{

    [HttpGet]
    [Route("{name}/{drink}/{sport?}")]
    public List<int> Get(string name, string drink, string sport = "")
    {
        // Code removed...
    }
}

그러나 여전히 쿼리 문자열을 사용하면 라우팅 방법을 사용하는 동안 적절한 경로를 찾지 못합니다.


현재 프로젝트에 대한 웹 API를 빌드하는 동안 '검색 매개 변수를 쿼리 문자열로 포함하는 방법'이라는 동일한 문제에 직면했습니다. 인터넷 검색 후 다음이 잘 작동합니다.

API 컨트롤러 작업 :

[HttpGet, Route("search/{categoryid=categoryid}/{ordercode=ordercode}")]

public Task<IHttpActionResult> GetProducts(string categoryId, string orderCode)
{

}

우편 배달부를 통해 시도한 URL :

http://localhost/PD/search?categoryid=all-products&ordercode=star-1932

http://localhost/PD is my hosted api

많은 노력을 기울이고 인터넷 검색을 한 후에 '수정'을 찾았습니다. 이것이 이상적인 / 모범 사례 / 일반적인 잘못된 것인지는 모르겠지만 내 문제를 해결합니다.

[Route("")]내가 한 것은 이미 사용하고있는 경로 속성 에 추가 하는 것뿐이었습니다. 이것은 기본적으로 Web API 2 라우팅이 쿼리 문자열을 허용하도록 허용합니다. 이제 유효한 경로이기 때문입니다.

예를 들면 다음과 같습니다.

[HttpGet]
[Route("")]
[Route("{name}/{drink}/{sport?}")]
public List<int> Get(string name, string drink, string sport = "")
{
    // Code removed...
}

이 두 수 localhost:12345/1/Names/Ted/cokelocalhost:12345/1/Names?name=Ted&drink=coke유효합니다.


속성 라우팅을 사용하면 기본값을 지정해야하므로 선택 사항이됩니다.

[Route("{name}/{sport=Football}/{drink=Coke}")]

값을 할당하면 선택 사항이 될 수 있으므로 포함 할 필요가 없으며 지정할 값을 전달합니다.

이에 대한 쿼리 문자열을 테스트하지는 않았지만 동일하게 작동해야합니다.

나는 방금 질문을 다시 읽었고 동일한 경로를 가진 2 개의 Get 동사가 있음을 알았습니다. 라우팅이 어느 것을 사용할지 알지 못하기 때문에 충돌이 발생할 것이라고 생각합니다. 아마도 선택적 매개 변수를 사용하면 도움이 될 것입니다. 널이 될 수 있음을 지정하고 진행 방법에 대해 메소드에서 검사를 수행 할 수도 있습니다.

[Route("{name}/{sport?}/{drink?}")]

그런 다음 메서드의 변수를 확인하여 null인지 확인하고 필요에 따라 처리합니다.

이것이 도움이되기를 바랍니다. ㅋㅋ

이 사이트가 아닌 경우 속성 라우팅에 대한 자세한 내용이 있습니다.

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

해당 사이트에서 클립 :

선택적 매개 변수 및 기본값 매개 변수에 물음표를 추가하여 매개 변수가 선택 사항임을 지정할 수 있습니다.

[Route("countries/{name?}")]
public Country GetCountry(string name = "USA") { }

Currently, a default value must be specified on the optional parameter for action selection to succeed, but we can investigate lifting that restriction. (Please let us know if this is important.)

Default values can be specified in a similar way:

[Route("countries/{name=USA}")]
public Country GetCountry(string name) { }

The optional parameter '?' and the default values must appear after inline constraints in the parameter definition.


Just a side note from my part as well. In order for queryString params to work, you need to provide a default value for your method parameters to make it optional. Just as you would also do when normally invoking a C# method.

[RoutePrefix("api/v1/profile")]
public class ProfileController : ApiController
{

   ...

   [HttpGet]
   [Route("{profileUid}")]
   public IHttpActionResult GetProfile(string profileUid, long? someOtherId) 
   {
      // ...
   }

   ...

}

This allows me to call the endpoint like this:

/api/v1/profile/someUid
/api/v1/profile/someUid?someOtherId=123

Using Route("search/{categoryid=categoryid}/{ordercode=ordercode}") will enable you to use both Querystrings and inline route parameters as answered by mosharaf hossain. Writing this answer as this should be top answer and best way. Using Route("") will cause problems if you have multiple Gets/Puts/Posts/Deletes.


Here's a slight deviant of @bhargav kishore mummadireddy's answer, but an important deviation. His answer will default the querystring values to an actual non-empty value. This answer will default them to empty.

It allows you to call the controller through path routing, or using the querystring. Essentially, it sets the default value of the querystring to empty, meaning it will always be routed.

This was important to me, because I want to return 400 (Bad Request) if a querystring is not specified, rather than having ASP.NET return the "could not locate this method on this controller" error.

[RoutePrefix("api/AppUsageReporting")]
public class AppUsageReportingController : ApiController
    {
        [HttpGet]
        // Specify default routing parameters if the parameters aren't specified
        [Route("UsageAggregationDaily/{userId=}/{startDate=}/{endDate=}")]
        public async Task<HttpResponseMessage> UsageAggregationDaily(string userId, DateTime? startDate, DateTime? endDate)
        {
            if (String.IsNullOrEmpty(userId))
            {
                return Request.CreateResponse(HttpStatusCode.BadRequest, $"{nameof(userId)} was not specified.");
            }

            if (!startDate.HasValue)
            {
                return Request.CreateResponse(HttpStatusCode.BadRequest, $"{nameof(startDate)} was not specified.");
            }

            if (!endDate.HasValue)
            {
                return Request.CreateResponse(HttpStatusCode.BadRequest, $"{nameof(endDate)} was not specified.");
            }
        }
    }

Since you have [Route("{name}/{drink}/{sport?}")] as attribute routing, this code will never be hit.

config.Routes.MapHttpRoute(
name: "NameRoute",
routeTemplate: "{verId}/Names/{name}/{sport}/{drink}",
defaults: new { name = RouteParameter.Optional, sport = RouteParameter.Optional, drink = RouteParameter.Optional },
constraints: new { verId = @"\d+" });

So only the attribute route [Route("{name}/{drink}/{sport?}")] is going to be honored here. Since your request localhost:12345/1/Names?name=Ted&sport=rugby&drink=coke, doesn't have name, sport or drink in the URL it is not going to match this attribute route. We do not consider the query string parameters when matching the routes.

To solve this, you need to make all 3 optional in your attribute route. Then it will match the request.


I use FromUri attribute as solution

[Route("UsageAggregationDaily")]
public async Task<HttpResponseMessage> UsageAggregationDaily([FromUri] string userId = null, [FromUri] DateTime? startDate = null, [FromUri] DateTime? endDate = null)

참고URL : https://stackoverflow.com/questions/22642874/query-string-not-working-while-using-attribute-routing

반응형