2012-05-10 1 views
0

現在、私たちは既存のWebForms実装を使用して、フレームワークサイトのMvc3実装を行うという使命に着手しました。構造マップを使用してアプリケーションのコア内で一般的なルートを解決するIoC

このタスクでは、柔軟性のためにIoCとDIをStructure Mapと統合することができました。

はあなたにいくつかの背景を与えるために、私たち次のプロジェクトの構造を有する:

App.Core < - コアクラスライブラリ

App.Mvc < - MVCクラスライブラリ
App.Mvc.Web < - Mvc3 APP

App.WebForms < - Webフォームクラスライブラリ
App.WebForms.Web < - Webフォームアプリやサイト

私たちはMvcとWebFormsの両方の実装でMvcのルーティングを使用しています.IRouteProviderを使用してOrchardプロジェクトと同じ方法でルートパブリッシングを行いました.IRouteProviderのN個の実装を作成して出版社はその優先順位によって登録し、注文する。

これは正常に動作しており、WebフォームのMVCまたはPage.GetRouteUrlのUrlHelperでルートを登録して使用することができます。

問題は、App.Coreがこれらのルート(すべてではなく一部の最も一般的なルート)を解決できるようになり、実装されているサイトに応じて変更できるということです。 。

たとえば、商品の詳細なデフォルトルートは「/ {category}/{product_name}/{product_id}」ですが、これを上書きして特定のサイトに対しては「/ {brand}/{product_name }/{product_id} "となります。

これは、コアでは、RouteTable.Routes.GetVirtualPathを固定パラメータセットで使用するだけでは、サイト間で変更される可能性があるためです。

最も一般的なルートのメソッドを持つIRouteResolverインターフェイスを作成しました。このインターフェイスは、各クラスライブラリ(MvcまたはWebforms)でSMに登録されているデフォルト実装を持ちますが、各サイトでオーバーライドすることもできます。

のようにインターフェースが見えます:デフォルトのWebフォームの実装がどのように見える

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))); 
    } 
} 

問題は今のようなインターフェースのデフォルトのMVCの実装が見え

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); 
} 

その理由は、コンストラクタの引数(UrlHelperは、Mvcとページまたはコントロールのt彼はWebformsを使用しています)、IRを使用してIRouteResolverプラグインのインスタンスを取得するのではなく、具体的なタイプを使用する必要があります。例えば

私はページ上のリゾルバを使用可能にするには、以下の拡張子を持っているか、コントロール

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

これは、既定のWebまたはMVCのための行動ではなく、我々は、具体的にリゾルバを上書きしたい場合をカバーサイトごとに

SMにプラグインとしてこれらのコンストラクタ引数を追加するのは安全ですか?

この機能のリクエストに推奨できる別のアプローチ/パターンはありますか?

ご意見やご提案をいただければ幸いです。

多くのおかげで、 P.

+0

は言及を忘れてしまった、IRouteResolverのためのSMの登録は(SMレジストリクラスを使用して、のために設定することにより、各クラスライブラリ上で行われます)。();を使用します。 –

答えて

0

私は限りオーバーライドは同じコンストラクタを持っているとして、私はこの考えてPassing constructor arguments when using StructureMap

で答えを見つけたと思う:

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); 
} 
関連する問題