ASP.NET 라우팅
업데이트: 2007년 11월
ASP.NET 라우팅을 사용하면 웹 사이트의 특정 파일에 매핑할 필요가 없는 URL을 사용할 수 있습니다. URL에서 파일에 매핑할 필요가 없기 때문에 웹 응용 프로그램에 사용자의 작업을 설명하는 URL을 사용할 수 있으므로 사용자가 더욱 쉽게 이해할 수 있습니다.
라우팅을 사용하지 않는 ASP.NET 응용 프로그램의 경우 URL에 대한 들어오는 요청은 일반적으로 .aspx 파일과 같이 디스크의 실제 파일에 매핑됩니다. 예를 들어 https://server/application/Products.aspx?id=4에 대한 요청은 브라우저에 응답을 렌더링하기 위한 코드 및 태그가 포함된 Products.aspx라는 파일에 매핑됩니다. 웹 페이지에서는 id=4라는 쿼리 문자열 값을 사용하여 표시할 콘텐츠의 형식을 확인하지만 사용자에게는 이 값이 특별한 의미를 지니지 않습니다.
ASP.NET 라우팅을 사용할 경우에는 URL 요청을 처리할 때 사용할 값에 대한 자리 표시자가 포함된 URL 패턴을 정의합니다. 런타임에 URL에서 응용 프로그램 이름 뒤에 나오는 부분은 사용자가 정의한 URL 패턴을 기반으로 별개의 값으로 구문 분석됩니다. 예를 들어 https://server/application/Products/show/beverages에 대한 요청에서 라우팅 파서는 Products, show 및 beverages라는 값을 요청의 처리기에 전달할 수 있습니다. 반면 URL 라우팅으로 관리되지 않는 요청의 경우 /Products/show/beverages 부분은 응용 프로그램에서 파일 경로로 해석됩니다.
URL 패턴을 사용하면 경로에 해당하는 URL을 프로그래밍 방식으로 만들 수도 있습니다. 이를 통해 ASP.NET 응용 프로그램의 하이퍼링크 생성 논리를 중앙에 집중시킬 수 있습니다.
ASP.NET 라우팅과 URL 다시 작성 비교
ASP.NET 라우팅은 다른 URL 다시 작성 체계와는 다릅니다. URL 다시 작성은 요청을 웹 페이지에 보내기 전에 URL을 실제로 변경하는 방식으로 들어오는 요청을 처리합니다. 예를 들어 URL 다시 작성을 사용하는 응용 프로그램은 URL을 /Products/Widgets/에서 /Products.aspx?id=4로 변경할 수 있습니다. 또한 일반적으로 URL 다시 작성에는 사용자 패턴에 기반을 둔 URL 생성을 위한 API가 없습니다. URL 다시 작성에서는 URL 패턴을 변경하면 원래 URL이 포함된 모든 하이퍼링크를 수동으로 업데이트해야 합니다.
ASP.NET 라우팅의 경우 들어오는 요청이 처리될 때 URL이 변경되지 않는데 이는 라우팅이 URL에서 값을 추출할 수 있기 때문입니다. URL을 만들어야 할 경우에는 URL을 자동으로 생성하는 메서드에 매개 변수 값을 전달합니다. URL 패턴을 변경하려면 한 위치에서 패턴을 변경합니다. 그러면 응용 프로그램에서 해당 패턴을 기반으로 만든 모든 링크가 자동으로 새 패턴을 사용하게 됩니다.
URL 경로 정의
사용자가 정의하는 URL 패턴을 경로라고 합니다. URL 요청에서 구문 분석된 값에 매핑되는 자리 표시자를 경로에 지정합니다. URL 요청 일치에 사용되는 상수 값을 지정할 수도 있습니다.
경로에서 자리 표시자(URL 매개 변수라고 함)는 중괄호({ 및 })로 묶어 정의합니다. / 문자는 URL 구문 분석 시 구분 기호로 해석됩니다. 경로 정의에서 구분 기호가 아니거나 중괄호로 묶이지 않은 정보는 상수 값으로 처리됩니다. 구분 기호 사이에서 추출된 값은 자리 표시자에 할당됩니다.
구분 기호 사이에 둘 이상의 자리 표시자를 정의할 수 있지만 이 경우 각각을 상수 값으로 구분해야 합니다. 예를 들어 {language}-{country}/{action}은 올바른 경로 패턴입니다. 그러나 {language}{country}/{action}은 자리 표시자 사이에 상수나 구분 기호가 없기 때문에 올바른 패턴이 아닙니다. 따라서 라우팅을 통해서는 language 자리 표시자의 값과 country 자리 표시자의 값을 어디에서 구분해야 할지 확인할 수 없습니다.
다음 표에서는 올바른 경로 패턴 및 패턴과 일치하는 URL 요청의 예를 보여 줍니다.
경로 정의 |
일치하는 URL의 예 |
---|---|
{controller}/{action}/{id} |
/Products/show/beverages |
{table}/Details.aspx |
/Products/Details.aspx |
blog/{action}/{entry} |
/blog/show/123 |
{reporttype}/{year}/{month}/{day} |
/sales/2008/1/5 |
{locale}/{action} |
/en-US/show |
{language}-{country}/{action} |
/en-US/show |
일반적으로 Global.asax 파일의 Application_Start 이벤트 처리기에서 호출되는 메서드에서 경로를 추가합니다. 이렇게 하면 응용 프로그램이 시작될 때 경로를 사용할 수 있게 됩니다. 또한 응용 프로그램에 대한 단위 테스트를 수행할 때 메서드를 직접 호출할 수 있습니다. 응용 프로그램에 대한 단위 테스트를 수행할 때 메서드를 직접 호출하려면 경로를 등록하는 메서드가 정적(Visual Basic의 Shared) 메서드여야 하고 RouteCollection 매개 변수를 가지고 있어야 합니다.
RouteTable 클래스의 정적 Routes 속성에 경로를 추가합니다. Routes 속성은 ASP.NET 응용 프로그램에 대한 모든 경로가 저장된RouteCollection 개체입니다. 다음 예제에서는 action 및 categoryName이라는 두 URL 매개 변수를 정의하는 Route 개체를 추가하는 Global.asax 파일의 코드를 보여 줍니다.
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
RegisterRoutes(RouteTable.Routes)
End Sub
Shared Sub RegisterRoutes(routes As RouteCollection)
Dim urlPattern As String
Dim categoryRoute As Route
urlPattern = "Category/{action}/{categoryName}"
categoryRoute = New Route(urlPattern, New CategoryRouteHandler)
routes.Add(categoryRoute)
End Sub
protected void Application_Start(object sender, EventArgs e)
{
RegisterRoutes(RouteTable.Routes);
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.Add(new Route
(
"Category/{action}/{categoryName}"
, new CategoryRouteHandler()
));
}
경로 매개 변수의 기본값 설정
경로를 정의할 때 매개 변수의 기본값을 할당할 수 있습니다. 기본값은 해당 매개 변수의 값이 URL에 포함되어 있지 않을 때 사용됩니다. 경로의 기본값을 설정하려면 Route 클래스의 Defaults 속성에 사전을 할당합니다. 다음 예제에서는 기본값이 있는 경로를 보여 줍니다.
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
RegisterRoutes(RouteTable.Routes)
End Sub
Shared Sub RegisterRoutes(ByVal routes As RouteCollection)
Dim urlPattern As String
Dim categoryRoute As Route
urlPattern = "Category/{action}/{categoryName}"
categoryRoute = New Route(urlPattern, New CategoryRouteHandler)
categoryRoute.Defaults = New RouteValueDictionary(New With _
{.categoryName = "food", _
.action = "show"} )
routes.Add(categoryRoute)
End Sub
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes(RouteTable.Routes);
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.Add(new Route
(
"Category/{action}/{categoryName}"
new CategoryRouteHandler()
)
{
Defaults = new RouteValueDictionary
{{"categoryName", "food"}, {"action", "show"}}
}
);
}
ASP.NET 라우팅을 통해 URL 요청을 처리할 때 예제의 경로 정의(categoryName에 대한 기본값 food와 action에 대한 기본값 show 포함)에 따라 다음 표와 같은 결과가 나타납니다.
URL |
매개 변수 값 |
---|---|
/Category |
action = "show"(기본값) categoryName = "food"(기본값) |
/Category/add |
action = "add" categoryName = "food"(기본값) |
/Category/add/beverages |
action = "add" categoryName= "beverages" |
가변적인 개수의 세그먼트 처리
가변적인 개수의 URL 세그먼트가 포함된 URL 요청을 처리해야 할 경우가 있습니다. 경로를 정의할 때 마지막 매개 변수에 별표(*)를 표시하여 매개 변수가 URL의 나머지 부분과 일치하도록 지정할 수 있습니다. 그러면 이 매개 변수가 catch-all 매개 변수로 참조됩니다. catch-all 매개 변수가 포함된 경로는 마지막 매개 변수에 대한 값을 포함하지 않은 URL과도 일치됩니다. 다음 예제에서는 알 수 없는 개수의 세그먼트와 일치하는 경로 패턴을 보여 줍니다.
query/{queryname}/{*queryvalues}
ASP.NET 라우팅을 통해 URL 요청을 처리할 때 예제의 경로 정의에 따라 다음 표와 같은 결과가 나타납니다.
URL |
매개 변수 값 |
---|---|
/query/select/bikes/onsale |
queryname = "select" queryvalues = "bikes/onsale" |
/query/select/bikes |
queryname = "select" queryvalues = "bikes" |
/query/select |
queryname = "select" queryvalues = 빈 문자열 |
경로에 제약 조건 추가
URL의 매개 변수 수를 기준으로 경로 정의에 URL 요청을 일치시킬 수 있을 뿐만 아니라 매개 변수의 값이 특정한 제약 조건을 충족하도록 지정할 수도 있습니다. 경로에 대한 제약 조건을 벗어난 값이 URL에 포함되어 있으면 해당 경로는 요청을 처리하는 데 사용되지 않습니다. 제약 조건을 추가하여 응용 프로그램에서 작동하는 값이 URL 매개 변수에 포함되도록 해야 합니다.
제약 조건은 정규식을 사용하거나 IRouteConstraint 인터페이스를 구현하는 개체를 사용하여 정의합니다. Routes 컬렉션에 경로 정의를 추가할 때 확인 테스트가 포함된 RouteValueDictionary 개체를 만들어 제약 조건을 추가합니다. 그런 다음 이 개체를 Constraints 속성에 할당합니다. 사전의 키는 제약 조건이 적용되는 매개 변수를 식별합니다. 사전의 값은 정규식을 나타내는 문자열 또는 IRouteConstraint 인터페이스를 구현하는 개체로 사용될 수 있습니다.
문자열을 제공할 경우 ASP.NET 라우팅에서는 문자열을 정규식으로 처리하고 Regex 클래스의 IsMatch 메서드를 호출하여 매개 변수 값이 올바른지 여부를 확인합니다. 정규식은 항상 대소문자를 구분하여 처리됩니다. 자세한 내용은 .NET Framework 정규식을 참조하십시오.
IRouteConstraint 개체를 제공할 경우 ASP.NET 라우팅에서는 IRouteConstraint 개체의 Match 메서드를 호출하여 매개 변수 값이 올바른지 여부를 확인합니다. Match 메서드는 매개 변수 값이 올바른지 여부를 나타내는 부울 값을 반환합니다.
다음 예제에서는 locale 및 year 매개 변수에 포함할 수 있는 값을 제한하는 제약 조건을 보여 줍니다.
Shared Sub RegisterRoutes(ByVal routes As RouteCollection)
Dim urlPattern As String
Dim reportRoute As Route
urlPattern = "{locale}/{year}"
reportRoute = New Route(urlPattern, New ReportRouteHandler)
reportRoute.Constraints = New RouteValueDictionary(New With _
{.locale = "[a-z]{2}-[a-z]{2}", .year = "\d{4}"})
routes.Add(reportRoute)
End Sub
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes(RouteTable.Routes);
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.Add(new Route
(
"{locale}/{year}"
, new ReportRouteHandler()
)
{
Constraints = new RouteValueDictionary
{{"locale", "[a-z]{2}-[a-z]{2}"},{year, @"\d{4}"}}
});
}
ASP.NET 라우팅을 통해 URL 요청을 처리할 때 이전 예제의 경로 정의에 따라 다음 표와 같은 결과가 나타납니다.
URL |
결과(Result) |
---|---|
/en-US |
일치하는 항목이 없습니다. locale 및 year가 모두 있어야 합니다. |
/en-US/08 |
일치하는 항목이 없습니다. year에 대한 제약 조건에 따라 연도가 4자리여야 합니다. |
/en-US/2008 |
locale = "en-US" year = "2008" |
라우팅이 적용되지 않은 경우의 시나리오
기본적으로 웹 서버에 이미 있는 실제 파일에 매핑되는 요청은 라우팅을 통해 처리되지 않습니다. 예를 들어 실제 파일이 Products/Beverages/Coffee.aspx에 있는 경우 https://server/application/Products/Beverages/Coffee.aspx에 대한 요청은 라우팅을 통해 처리되지 않습니다. 라우팅에서는 {controller}/{action}/{id}와 같은 정의된 패턴과 일치하는 요청도 처리되지 않습니다.
파일을 가리키는 요청을 포함하여 모든 요청을 라우팅을 통해 처리하려는 경우 RouteCollection 개체의 RouteExistingFiles 속성을 true로 설정하여 기본 동작을 덮어쓸 수 있습니다. 이 값을 true로 설정하면 정의된 패턴과 일치하는 모든 요청이 라우팅을 통해 처리됩니다.
또한 특정 URL 요청은 라우팅을 통해 처리되지 않도록 지정할 수도 있습니다. 경로를 정의하고 해당 패턴을 처리하는 데 StopRoutingHandler 클래스를 사용하도록 지정하여 특정 요청이 라우팅을 통해 처리되지 않도록 할 수 있습니다. 요청이 StopRoutingHandler 개체에 의해 처리될 경우 StopRoutingHandler 개체는 요청이 경로로 처리되는 것을 차단합니다. 대신 이러한 요청은 ASP.NET 페이지, 웹 서비스 또는 다른 ASP.NET 끝점으로 처리됩니다. 예를 들어 다음 경로 정의를 추가하여 WebResource.axd 파일에 대한 요청이 라우팅을 통해 처리되지 않도록 할 수 있습니다.
Shared Sub RegisterRoutes(ByVal routes As RouteCollection)
routes.Add(New Route("{resource}.axd/{*pathInfo}", New StopRouteHandler()))
End Sub
public static void RegisterRoutes(RouteCollection routes)
{
routes.Add(new Route("{resource}.axd/{*pathInfo}", new StopRouteHandler()));
}
URL과 경로를 일치시키는 방법
라우팅에서는 URL 요청을 처리할 때 요청의 URL을 경로와 일치시키려고 시도합니다. URL 요청과 경로의 일치 여부는 다음의 모든 조건에 따라 달라집니다.
사용자가 정의한 경로 패턴 또는 프로젝트 형식에 포함된 기본 경로 패턴(있는 경우)
경로 패턴을 Routes 컬렉션에 추가한 순서
경로에 지정한 기본값
경로에 지정한 제약 조건
실제 파일과 일치하는 요청을 처리하도록 라우팅을 정의했는지 여부
잘못된 처리기가 요청을 처리하는 것을 방지하려면 경로를 정의할 때 이러한 조건을 모두 고려해야 합니다. Routes 컬렉션에서 Route 개체가 나타나는 순서는 매우 중요합니다. 컬렉션의 첫 번째 경로에서 마지막 경로의 순서로 경로 일치가 수행됩니다. 일치하는 경로를 찾으면 이후의 경로는 확인하지 않습니다. 일반적으로 가장 구체적인 경로 정의부터 그렇지 않은 경로 정의의 순서로 Routes 속성에 경로를 추가합니다.
예를 들어 다음 패턴이 있는 경로를 추가한다고 가정해 보십시오.
경로 1: {controller}/{action}/{id}
경로 2: products/show/{id}
경로 2는 요청을 처리하지 않습니다. 그 이유는 경로 1이 먼저 확인되어, 경로 2에서도 처리할 수 있는 요청을 항상 경로 1이 처리하기 때문입니다. https://server/application/products/show/bikes에 대한 요청은 경로 2와 더 일치하는 것처럼 보이지만 다음 값을 통해 경로 1에서 처리됩니다.
controller = products
action = show
id = bikes
요청에 매개 변수가 누락되어 있으면 기본값이 사용됩니다. 이로 인해 경로가 예기치 않은 요청과 일치하는 상황이 발생할 수 있습니다. 예를 들어 다음 패턴이 있는 경로를 추가한다고 가정해 보십시오.
경로 1: {report}/{year}/{month}, year 및 month에 대한 기본값 포함
경로 2: {report}/{year}, year에 대한 기본값 포함
경로 2는 요청을 처리하지 않습니다. 경로 1은 월별 보고서용이고 경로 2는 연간 보고서용일 수 있습니다. 그러나 경로 1의 기본값은 경로 1이 경로 2에서도 처리할 수 있는 모든 요청을 처리함을 의미합니다.
annual/{report}/{year} 및 monthly/{report}/{year}/{month}와 같은 상수를 포함하여 패턴의 모호성을 피할 수 있습니다.
URL이 RouteTable 컬렉션에 정의된 어떤 Route 개체와도 일치하지 않으면 해당 요청은 ASP.NET 라우팅을 통해 처리되지 않습니다. 대신 이러한 요청에 대한 처리는 ASP.NET 페이지, 웹 서비스 또는 다른 ASP.NET 끝점으로 전달됩니다.
경로에서 URL 만들기
URL 생성 논리를 중앙에 집중시키려는 경우 경로를 사용하여 URL을 생성할 수 있습니다. RouteCollection 개체의 GetVirtualPath 메서드에 매개 변수 값을 사전으로 전달하여 URL을 만듭니다. GetVirtualPath 메서드는 RouteCollection 개체에서 사전의 매개 변수와 일치하는 첫 번째 경로를 찾습니다. 일치하는 경로가 URL을 생성하는 데 사용됩니다. 다음 예제에서는 경로 정의를 보여 줍니다.
Shared Sub RegisterRoutes(ByVal routes As RouteCollection)
routes.Add(New Route( _
"Category/{action}/{categoryName}", _
New RouteValueDictionary(New With _
{.categoryName = "food", _
.action = "show"}), _
New CategoryRouteHandler()) )
End Sub
public static void RegisterRoutes(RouteCollection routes)
{
routes.Add(new Route
(
"Category/{action}/{categoryName}"
new CategoryRouteHandler()
)
{
Defaults = new RouteValueDictionary {{"categoryName", "food"},
{"action", "show"}}
}
);
}
다음 예제에서는 경로를 기반으로 URL을 만드는 컨트롤을 보여 줍니다.
Dim urlParameters As RouteValueDictionary
urlParameters = New RouteValueDictionary(New With {.categoryName = "beverages", _
.action = "summarize"})
HyperLink1.href = RouteTable.Routes.GetVirtualPath _
(context, urlParameters).VirtualPath
HyperLink1.href = RouteTable.Routes.GetVirtualPath
(context,
new RouteValueDictionary {
{ "categoryName", "beverages" },
{"action", "summarize" }}
).VirtualPath;
이 코드를 실행하면 HyperLink1 컨트롤의 href 속성에 "Category/summarize/beverages"라는 값이 포함됩니다.
경로에서 URL을 만들 경우 경로 이름을 포함하여 사용할 경로를 지정할 수 있습니다. 자세한 내용은 방법: 라우팅을 통해 URL 만들기를 참조하십시오.