2012-12-14 4 views
2

ASP.NET WebForms 응용 프로그램의 이전 HttpHandler API에서 메소드를 대체해야하는 경우가 있습니다. WebAPI를 새 API의 기반으로 사용하고 있으며 새로운 API에서 작업을 찾을 수 없을 때 폴백 (fallback)을위한 라우팅이 필요하다는 점을 제외하면 큰 성과를 거두었습니다. 현재 사실이 아니며 대신 WebAPI 컨트롤러에 일치하는 작업이 없을 때마다 "404 : Not Found"가 표시됩니다.조치가 없을 때 중복 라우트를 다음 일치 경로로 폴백해야합니다.

다음과 같이 새로운 API에 대한 나의 경로는 다음과 같습니다

var route = new Route("api/{language}-{country}/Person/{command}", this); 
RouteTable.Routes.Add(route); 

I :

var apiroute = routes.MapHttpRoute(
    "API Default", 
    "api/{language}-{country}/{controller}/{action}/{id}", 
    new { id = RouteParameter.Optional } 
); 

오래된 HttpHandler를 API를 다음과 같이 (순서는 WebAPI 경로 이후) 자신의 경로를 등록 List 액션이있는 PersonController가 있지만 이전 APi로 폴백되지 않은 경우 첫 번째 라우트를 일치 시키려면/api/en-US/Person/List를 원한다.

질문 :는이 작업이 실제로 컨트롤러를 사용할 수있는 경우에만 일치에 대한 첫 번째 경로에 필터를 추가 할 수 있습니까? 어떻게 내가이 일을 성취 할 수 있겠습니까?

답변

1

또한이 경로에 일치하게 될 작업 만하면 라우팅 속성을 주석 청소기 해결책이 될 수 있습니다 그리고 당신은 당신이 원하는 것을 달성하는 데 도움이 될 수 있습니다 attribute based routing을 조사 할 수 있습니다

업데이트.

또는

이것보다 더 나은 방법이있을 수 있지만 사용자 정의를 구현하는 경우, 그것은 가능하다 IRouteConstraint 예를 들어, this article. 당신을 개선 할 수

고도의 거칠고 준비 방법은 다음과 같습니다 :

public class IfActionExistsConstraint : IRouteConstraint 
{ 
    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) 
    { 
     var actionName = values["Action"] as string; 

     if (actionName == null) 
     { 
      return false; 
     } 

     var controllerName = values["Controller"] as string; 
     var controllerTypeResolver = GlobalConfiguration.Configuration.Services.GetHttpControllerTypeResolver(); 
     var controllerTypes = controllerTypeResolver.GetControllerTypes(GlobalConfiguration.Configuration.Services.GetAssembliesResolver()); 
     var controllerType = controllerTypes.SingleOrDefault(ct => ct.Name == string.Format("{0}Controller", controllerName)); 

     if(controllerType == null) 
     { 
      return false; 
     } 

     return controllerType.GetMethod(actionName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance) != null; 
    } 
} 

등록 : 나는하지만이 수도 같은 일을 달성하기 위해 더욱 최적화 된 방법을 기대했다

var apiroute = routes.MapHttpRoute(
    name: "API Default", 
    routeTemplate: "api/{language}-{country}/{controller}/{action}/{id}", 
    defaults: new { id = RouteParameter.Optional }, 
    constraints: new { IfActionExistsConstraint = new IfActionExistsConstraint() } 
); 
+0

잘하는 게 최선입니다. 잠재적으로 성능에 큰 영향을 미치지 않을 수있는 유형 및 이름의 일부 메모리 내 캐싱을 추가하십시오. 나는 또한 특별히 오버라이드 할 각 라우트를 설정하는 것을 고려해 보았으며 사용의 용이성과 성능 사이에서 어떤 접근법이 가장 좋은지 결정하지 못했습니다. – magix

+0

@magix는 메모리 오버 헤드 (ControllerSelector 프레임 워크가하는 것)를 통해 지적한대로 최적화 할 수 있지만 큰 오버 헤드라고 동의합니다. 필자는 속성 기반 라우팅을 포함하도록 내 대답을 업데이트하여 라우트 정의에 대한 세부적인 세분성을 허용하고 도움이 될 수도 있습니다. –

+0

도움 주셔서 감사합니다! – magix