2012-05-10 1 views
0

우리는 기존의 WebForms 구현으로 현재 프레임 워크 사이트의 Mvc3 구현 작업을 시작했습니다.구조체 맵을 사용하여 앱의 코어 내에서 일반적인 경로 결정하기 IoC

이 작업을 통해 유연성을 위해 IoC와 DI를 Structuremap과 통합 할 수있었습니다.

당신에게 몇 가지 배경을 제공하기 위해, 우리는 다음과 같은 프로젝트 구조를 가지고 :

App.Core < - 코어 클래스 라이브러리

App.Mvc < - MVC 클래스 라이브러리
App.Mvc.Web < - Mvc3 APP

App.WebForms < - 웹 양식 클래스 라이브러리
App.WebForms.Web < - 웹 양식 응용 프로그램 또는 사이트

우리는 Mvc와 WebForms 구현 모두에서 Mvc의 라우팅을 사용하고 있습니다. IRouteProvider를 사용하여 Orchard 프로젝트에서와 같이 경로 게시에 동일한 방법을 사용했습니다. N 개의 IRouteProvider 구현을 만들어서 게시자는 자신의 우선 순위에 따라 등록 및 주문할 수 있습니다.

정상적으로 작동합니다. MVC의 UrlHelper 또는 WebForms의 Page.GetRouteUrl을 사용하여 경로를 등록하고 사용할 수 있습니다.

문제는 App.Core가 이러한 경로 (모든 경로가 아닌 일부 경로)를 해결할 수 있어야하며 구현되는 사이트에 따라 변경 될 수 있다는 것입니다. .

예를 들어, 제품 세부 경로 기본 경로는 "/ {category}/{product_name}/{product_id}"일 수 있지만이를 무시하고 특정 사이트의 경우 "/ {brand}/{product_name }/{product_id} "대신 사용하십시오.

즉, 코어에서 RouteTable.Routes.GetVirtualPath를 고정 된 매개 변수 집합으로 사용하는 것은 사이트간에 변경 될 수 있기 때문에 가능하지 않습니다.

가장 일반적인 경로에 대한 메서드를 사용하여 IRouteResolver 인터페이스를 만들었습니다.이 인터페이스는 각 클래스 라이브러리 (Mvc 또는 Webforms)의 SM에 등록되어 있지만 각 사이트에서 재정의 될 수도 있습니다.

public class MvcRouteResolver : IRouteResolver 
{ 
    UrlHelper _urlHelper; 
    ICategoryModelBroker _categoryModelBroker; 
    IBrandModelBroker _brandModelBroker; 
    IProductModelBroker _productModelBroker; 
    public MvcRouteResolver(UrlHelper urlHelper) 
    { 
     _urlHelper = urlHelper; 
     _categoryModelBroker = ObjectFactory.GetInstance<ICategoryModelBroker>(); 
     _brandModelBroker = ObjectFactory.GetInstance<IBrandModelBroker>(); 
     _productModelBroker = ObjectFactory.GetInstance<IProductModelBroker>(); 
    } 

    public string GetRouteUrl(object routeParameters) 
    { 
     return GetRouteUrl(new RouteValueDictionary(routeParameters)); 
    } 
    public string GetRouteUrl(System.Web.Routing.RouteValueDictionary routeParameters) 
    { 
     return GetRouteUrl(null, new RouteValueDictionary(routeParameters)); 
    } 
    public string GetRouteUrl(string routeName, object routeParameters) 
    { 
     return GetRouteUrl(routeName, new RouteValueDictionary(routeParameters)); 
    } 
    public string GetRouteUrl(string routeName, System.Web.Routing.RouteValueDictionary routeParameters) 
    { 
     return _urlHelper.RouteUrl(routeName, routeParameters); 
    } 
    public string GetUrlFor(Product product) 
    { 
     string category = string.Empty; 
     if (product.Categories.Count > 0) 
      category = product.Categories[0].Breadcrumb.Replace("@@", "-"); 
     else if (product.Brands.Any()) 
      category = product.Brands.FirstOrDefault().Name; 
     else 
      category = "detail"; 

     return GetRouteUrl(new { controller="Product", action="Detail", productId = product.Id, brandName = _productModelBroker.GetSlug(product), productName = _productModelBroker.GetSluggedName(product) }); 
    } 
    public string GetUrlFor(Category category) 
    { 
     return GetRouteUrl(new { controller = "Product", action = "ListByCategory", id = category.Id, name = _categoryModelBroker.GetSlug(category) }); 
    } 
    public string GetUrlFor(Brand brand) 
    { 
     return GetRouteUrl(new { controller = "Product", action = "ListByBrand", id = brand.Id, name = _brandModelBroker.GetSlug(brand) }); 
    } 
} 

가 기본 웹폼 구현 보이는 같은 : 문제는 지금

public class WebRouteResolver : IRouteResolver 
{ 
    Control _control; 
    HttpContext _context; 
    public WebRouteResolver() 
     :this(HttpContext.Current) 
    { 

    } 
    public WebRouteResolver(HttpContext context) 
    { 
     _context = context; 
    } 
    public WebRouteResolver(Control control) 
    { 
     _control = control; 
    } 
    public WebRouteResolver(Page page) 
    { 
     _control = page as Control; 
    } 

    public string GetRouteUrl(object routeParameters) 
    { 
     return GetRouteUrl(new RouteValueDictionary(routeParameters)); 
    } 
    public string GetRouteUrl(System.Web.Routing.RouteValueDictionary routeParameters) 
    { 
     return GetRouteUrl(null, new RouteValueDictionary(routeParameters)); 
    } 
    public string GetRouteUrl(string routeName, object routeParameters) 
    { 
     return GetRouteUrl(routeName, new RouteValueDictionary(routeParameters)); 
    } 
    public string GetRouteUrl(string routeName, System.Web.Routing.RouteValueDictionary routeParameters) 
    { 
     VirtualPathData virtualPath = null; 
     if(_control.IsNotNull()) 
      virtualPath = RouteTable.Routes.GetVirtualPath(_control.Page.Request.RequestContext, routeName, routeParameters); 
     else 
      virtualPath = RouteTable.Routes.GetVirtualPath(_context.Request.RequestContext, routeName, routeParameters); 

     if (virtualPath != null) 
     { 
      return virtualPath.VirtualPath; 
     } 
     return null; 
    } 
    private string ResolveUrl(string originalUrl) 
    { 
     if(_control.IsNotNull()) 
      return _control.ResolveUrl(originalUrl); 

     // *** Absolute path - just return 
     if (originalUrl.IndexOf("://") != -1) 
      return originalUrl; 

     // *** Fix up image path for ~ root app dir directory 
     if (originalUrl.StartsWith("~")) 
     { 
      string newUrl = ""; 
      if (_context != null) 
       newUrl = _context.Request.ApplicationPath + 
         originalUrl.Substring(1).Replace("//", "/"); 
      else 
       // *** Not context: assume current directory is the base directory 
       throw new ArgumentException("Invalid URL: Relative URL not allowed."); 

      // *** Just to be sure fix up any double slashes 
      return newUrl; 
     } 

     return originalUrl; 
    } 

    public string GetUrlFor(Product product) 
    { 
     string category = string.Empty; 
     if (product.Categories.Count > 0) 
      category = product.Categories[0].Breadcrumb.Replace("@@", "-"); 
     else if (product.Brands.Any()) 
      category = product.Brands.FirstOrDefault().Name; 
     else 
      category = "detail"; 

     if (Config.RoutingEnabled) 
     { 
      return GetRouteUrl(new { @category = CommonHelper.ToFriendlyUrl(category), name = CommonHelper.ToFriendlyUrl(product.Name), id = product.Id }); 
     } 
     return ResolveUrl(Config.GetStoreSetting("productDetailUrl")) + "?id={0}&name={1}&category={2}".Fill(product.Id, CommonHelper.ToFriendlyUrl(product.Name), CommonHelper.ToFriendlyUrl(category)); 
    } 
    public string GetUrlFor(Category category) 
    { 
     string breadcrumb = category.Breadcrumb.Replace("@@", "-"); 
     if (Config.RoutingEnabled) 
      return GetRouteUrl(new { @category = CommonHelper.ToFriendlyUrl(breadcrumb), category_id = category.Id}); 

     return ResolveUrl(Config.GetStoreSetting("productListingUrl") + "?category_id={0}&category={1}".Fill(category.Id, CommonHelper.ToFriendlyUrl(category.Name))); 
    } 
    public string GetUrlFor(Brand brand) 
    { 
     if (Config.RoutingEnabled) 
      return GetRouteUrl(new { @brand = CommonHelper.ToFriendlyUrl(brand.Name), brand_id = brand.Id }); 

     return ResolveUrl(Config.GetStoreSetting("productListingUrl") + "?brand_id={0}&brand={1}".Fill(brand.Id, CommonHelper.ToFriendlyUrl(brand.Name))); 
    } 
} 

public interface IRouteResolver 
{ 
    string GetRouteUrl(object routeParameters); 
    string GetRouteUrl(RouteValueDictionary routeParameters); 
    string GetRouteUrl(string routeName, object routeParameters); 
    string GetRouteUrl(string routeName, RouteValueDictionary routeParameters); 

    string GetUrlFor(Product product); 
    string GetUrlFor(Category category); 
    string GetUrlFor(Brand brand); 
} 

인터페이스의 기본 MVC 구현은 다음과 같습니다처럼

인터페이스 본다 그 때문에 생성자 인수 (UrlHelper에 대한 Mvc 및 페이지 또는 컨트롤 t 그는 Webforms입니다) 우리는 SM을 사용하지 않고 IRouteResolver 플러그인의 인스턴스를 잡는 대신 구체적인 유형을 사용해야합니다.예를 들어

나는 우리가 특별히에 대한 해결을 오버라이드 (override) 할 때 웹 또는 MVC가 아닌 경우에 대한 기본 동작을 포함

public static IRouteResolver RouteResolver(this Control control) 
{ 
    return new WebRouteResolver(control); 
} 
public static IRouteResolver RouteResolver(this Page page) 
{ 
    return new WebRouteResolver(page); 
} 

페이지 또는 제어에 대한 해결 사용할 수 있도록 다음과 같은 확장이 사이트 당 기준.

질문 : 이러한 생성자 인수를 SM에 플러그인으로 추가하는 것이 안전합니까?

이 기능 요청에 대해 권장 할 수있는 또 다른 접근 방식이나 패턴이 있습니까?

모든 아이디어/제안을 주시면 감사하겠습니다.

많은 감사, P.

+0

(A SM 레지스트리 클래스를 사용을 위해 설정하여 각 클래스 라이브러리에서 수행 된 IRouteResolver에 대한 SM에 언급 등록을 잊었다). ();를 사용하십시오. –

답변

0

은 내가 Passing constructor arguments when using StructureMap에서 답을 찾은 것 같아

오버라이드 (override)가 같은 생성자를 가지고

는 한, 나는이 생각 :

public static IRouteResolver RouteResolver(this Control control) 
{ 
    return ObjectFactory.With("control").EqualTo(control).GetInstance<IRouteResolver>(); 
} 
public static IRouteResolver RouteResolver(this Page page) 
{ 
    return ObjectFactory.With("page").EqualTo(page).GetInstance<IRouteResolver>(); 
} 

아마 작동합니까 , 일부 테스트를 수행합니다.

0

다른 접근법을 취했습니다. 위의 코드는 코어에서 작동하지 않았습니다. 지금 경로를 해결하기 위해 RouteCollection하고있는 HttpContext에만 의존 :

public abstract class BaseRouteResolver : IRouteResolver 
{ 
    protected HttpContext _context; 
    protected RouteCollection _routeCollection; 
    public BaseRouteResolver() 
     :this(RouteTable.Routes, HttpContext.Current) 
    { 

    } 
    public BaseRouteResolver(RouteCollection routeCollection, HttpContext context) 
    { 
     _routeCollection = routeCollection; 
     _context = context; 
    } 

    public string GetRouteUrl(object routeParameters) 
    { 
     return GetRouteUrl(new RouteValueDictionary(routeParameters)); 
    } 
    public string GetRouteUrl(System.Web.Routing.RouteValueDictionary routeParameters) 
    { 
     return GetRouteUrl(null, new RouteValueDictionary(routeParameters)); 
    } 
    public string GetRouteUrl(string routeName, object routeParameters) 
    { 
     return GetRouteUrl(routeName, new RouteValueDictionary(routeParameters)); 
    } 
    public string GetRouteUrl(string routeName, System.Web.Routing.RouteValueDictionary routeParameters) 
    { 
     VirtualPathData virtualPath = _routeCollection.GetVirtualPath(_context.Request.RequestContext, routeName, routeParameters); 
     if (virtualPath != null) 
      return virtualPath.VirtualPath; 
     return null; 
    } 

    public abstract string GetUrlFor(Product product); 

    public abstract string GetUrlFor(Category category); 

    public abstract string GetUrlFor(Brand brand); 
}