2016-06-23 12 views
0

私はカスタム(派生)RazorViewEngineを使用し、RazorGeneratorを使用してプリコンパイルしたビューを使用しようとしています。カスタムRazorViewEngineとRazorGeneratorプリコンパイル済みビューの使用

いくつかのコンテキスト:

我々は、複数のクライアントの実装に使用する基本製品を持っています。これにより、基本ビューのコアセットが得られます。ほとんどの場合、ほとんどのビューが機能します。現在、新しいソリューションごとに既存のビューをコピーし、必要に応じて変更します。これは、ビューの95%がクライアント間で同じで、5%が変更されることになります。

基本的なビューのセットをDLLにコンパイルし、クライアント間で再利用したいものです。これまではRazorGeneratorを使ってうまく動作しています。

次に、ビューのカスタマイズ(オーバーライド)を許可します。しかし、注意点があります。私たちのアプリケーションには、ユーザーがいる2つの「モード」があります。モードが異なると、異なるビューが必要になることがあります。

私はRazorGeneratorViewから派生クラスを作成しました。このビューは、基本的にAutofacが解決するUserProfileオブジェクトから "OrderingMode"を検査します。モードに基づいて、ビュー解決のためにパスロケータが置き換えられます。

個々のクライアントアプリケーションというアイデアは、伝統的なビューフォルダで最初にビューの解決を試みます。 Views/{OrderingMode}/{Controller}/{View} .cshtmlのサブディレクトリにのみ追加しています。

ビューが見つからない場合は、コンパイルされたライブラリ(コアビュー)が表示されます。

これにより、クライアントのために必要に応じて個々のビュー/パーシャルをオーバーライドすることができます。

public PosViewEngine() : base() 
    { 
     //{0} = View Name 
     //{1} = ControllerName 
     //{2} = Area Name 
     AreaViewLocationFormats = new[] 
     { 
      //First look in the hosting application area folder/Views/ordering type 
      //Areas/{AreaName}/{OrderType}/{ControllerName}/{ViewName}.cshtml 
      "Areas/{2}/Views/%1/{1}/{0}.cshtml", 

      //Next look in the hosting application area folder/Views/ordering type/Shared 
      //Areas/{AreaName}/{OrderType}/{ControllerName}/{ViewName}.cshtml 
      "Areas/{2}/Views/%1/Shared/(0}.cshtml", 

      //Finally look in the IMS.POS.Web.Views.Core assembly 
      "Areas/{2}/Views/{1}/{0}.cshtml" 
     }; 

     //Same format logic 
     AreaMasterLocationFormats = AreaViewLocationFormats; 

     AreaPartialViewLocationFormats = new[] 
     { 
      //First look in the hosting application area folder/Views/ordering type 
      //Areas/{AreaName}/{OrderType}/{ControllerName}/Partials/{PartialViewName}.cshtml 
      "Areas/{2}/Views/%1/{1}/Paritals/{0}.cshtml", 

      //Next look in the hosting application area folder/Views/ordering type/Shared 
      //Areas/{AreaName}/{OrderType}/{ControllerName}/{ViewName}.cshtml 
      "Areas/{2}/Views/%1/Shared/(0}.cshtml", 

      //Finally look in the IMS.POS.Web.Views.Core 
      "Areas/{2}/Views/{1}/{0}.cshtml" 
     }; 

     ViewLocationFormats = new[] 
     { 
      "Views/%1/{1}/{0}.cshtml", 
      "Views/%1/Shared/{0}.cshtml", 
      "Views/{1}/{0}.cshtml", 
      "Views/Shared/{0}.cshtml" 
     }; 

     MasterLocationFormats = ViewLocationFormats; 

     PartialViewLocationFormats = new[] 
     { 
      "Views/%1/{1}/Partials/{0}.cshtml", 
      "Views/%1/Shared/{0}.cshtml", 
      "Views/{1}/Partials/{0}.cshtml", 
      "Views/Shared/{0}.cshtml" 
     }; 




    } 

    protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath) 
    { 
     return base.CreatePartialView(controllerContext, partialPath.ReplaceOrderType(CurrentOrderingMode())); 
    } 

    protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath) 
    { 
     OrderType orderType = CurrentOrderingMode(); 
     return base.CreateView(controllerContext, viewPath.ReplaceOrderType(orderType), masterPath.ReplaceOrderType(orderType)); 
    } 

    protected override bool FileExists(ControllerContext controllerContext, string virtualPath) 
    { 
     return base.FileExists(controllerContext, virtualPath.Replace("%1/",string.Empty)); 
    } 


    private OrderType CurrentOrderingMode() 
    { 
     OrderType result; 
     _profileService = DependencyResolver.Current.GetService<IUserProfileService>(); 

     if (_profileService == null || _profileService.OrderingType == 0) 
     { 
      IApplicationSettingService settingService = 
       DependencyResolver.Current.GetService<IApplicationSettingService>(); 

      result = 
       settingService.GetApplicationSetting(ApplicationSettings.DefaultOrderingMode) 
        .ToEnumTypeOf<OrderType>(); 
     } 
     else 
     { 
      result = _profileService.OrderingType; 
     } 

     return result; 
    } 



} 

ここには、ViewEngineを登録するためにRazorGeneratorが使用するStartUpクラスがあります。

  1. このコードは(私はPosViewEngineを登録した後に)最後に実行され、これはサービス提供時に第一に解決さエンジンであることを意味(第1の位置にエンジンを挿入します。

    public static class RazorGeneratorMvcStart 
    { 
        public static void Start() 
        { 
         var engine = new PrecompiledMvcEngine(typeof(RazorGeneratorMvcStart).Assembly) 
         { 
          UsePhysicalViewsIfNewer = HttpContext.Current.Request.IsLocal 
         }; 
    
         ViewEngines.Engines.Insert(0, engine); 
    
         // StartPage lookups are done by WebPages. 
         VirtualPathFactoryManager.RegisterVirtualPathFactory(engine); 
        } 
    } 
    

    問題がありますアップ応答)。これでビューが見つかり、コアビューです。

  2. 私は私のカスタムビューエンジンまず最初にしてRazorGeneratorエンジン

    私はFILEEXISTS上の例外で終わる
    public static void Start() 
    { 
        var engine = new PrecompiledMvcEngine(typeof(RazorGeneratorMvcStart).Assembly) 
        { 
         UsePhysicalViewsIfNewer = HttpContext.Current.Request.IsLocal 
        }; 
    
        ViewEngines.Engines.Clear(); 
        ViewEngines.Engines.Insert(0, new PosViewEngine()); 
        ViewEngines.Engines.Insert(1, engine); 
    
        // StartPage lookups are done by WebPages. 
        VirtualPathFactoryManager.RegisterVirtualPathFactory(engine); 
    } 
    

(ControllerContext controllerContext、文字列virtualPathを登録するスタートアップのコードを変更した場合)メソッド - "相対仮想パス 'Views/Account/LogOn.cshtml'はここでは許可されていません。

明らかに、物理パスと仮想パスが混在していることとは関係があります。

他の誰かが同じことをしようとしていたようです。hereしかし、私はこれについての答えを見ませんでした。

答えて

0

このアプローチを試したい人は、私は答えを投稿します。基本的には、RazorGeneratorアセンブリにあるPrecompiledMvc​​Engineから派生したカスタムビューエンジンを実装する必要があります。

public class PosPrecompileEngine : PrecompiledMvcEngine 
{ 
    private IUserProfileService _profileService; 



    public PosPrecompileEngine(Assembly assembly) : base(assembly) 
    { 
     LocatorConfig(); 
    } 

    public PosPrecompileEngine(Assembly assembly, string baseVirtualPath) : base(assembly, baseVirtualPath) 
    { 
     LocatorConfig(); 
    } 

    public PosPrecompileEngine(Assembly assembly, string baseVirtualPath, IViewPageActivator viewPageActivator) : base(assembly, baseVirtualPath, viewPageActivator) 
    { 
     LocatorConfig(); 
    } 

    protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath) 
    { 
     return base.CreatePartialView(controllerContext, partialPath.ReplaceOrderType(CurrentOrderingMode())); 
    } 

    protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath) 
    { 
     OrderType orderType = CurrentOrderingMode(); 
     return base.CreateView(controllerContext, viewPath.ReplaceOrderType(orderType), masterPath.ReplaceOrderType(orderType)); 
    } 

    protected override bool FileExists(ControllerContext controllerContext, string virtualPath) 
    { 
     return base.FileExists(controllerContext, virtualPath.ReplaceOrderType(CurrentOrderingMode())); 
    } 
} 

このクラスでは、ロケータパスを上書きします。 Webアプリケーションの別のアセンブリに「ベース」コンパイル済みのビューがあるため、ビューエンジンはまず、WebアプリケーションのPosViews/{順序付けモード}/{コントローラ}/{ビュー}パスを参照する規約を実装しました。ビューが見つからない場合、従来のビュー/コントローラ/ビューで表示されます。ここでのトリックは、別のクラスライブラリにある仮想パスです。

これにより、アプリケーションの既存のビューを「上書き」することができました。

private void LocatorConfig() 
    { 
     //{0} = View Name 
     //{1} = ControllerName 
     //{2} = Area Name 
     AreaViewLocationFormats = new[] 
     { 
      //First look in the hosting application area folder/Views/ordering type 
      //Areas/{AreaName}/{OrderType}/{ControllerName}/{ViewName}.cshtml 
      "PosAreas/{2}/Views/%1/{1}/{0}.cshtml", 

      //Next look in the hosting application area folder/Views/ordering type/Shared 
      //Areas/{AreaName}/{OrderType}/{ControllerName}/{ViewName}.cshtml 
      "PosAreas/{2}/Views/%1/Shared/(0}.cshtml", 

      //Next look in the POS Areas Shared 
      "PosAreas/{2}/Views/Shared/(0}.cshtml", 

      //Finally look in the IMS.POS.Web.Views.Core assembly 
      "Areas/{2}/Views/{1}/{0}.cshtml" 
     }; 

     //Same format logic 
     AreaMasterLocationFormats = AreaViewLocationFormats; 

     AreaPartialViewLocationFormats = new[] 
     { 
      //First look in the hosting application area folder/Views/ordering type 
      //Areas/{AreaName}/{OrderType}/{ControllerName}/Partials/{PartialViewName}.cshtml 
      "PosAreas/{2}/Views/%1/{1}/Partials/{0}.cshtml", 

      //Next look in the hosting application area folder/Views/ordering type/Shared 
      //Areas/{AreaName}/{OrderType}/{ControllerName}/{ViewName}.cshtml 
      "PosAreas/{2}/Views/%1/Shared/(0}.cshtml", 

      //Next look in the hosting application shared folder 
      "PosAreas/{2}/Views/Shared/(0}.cshtml", 

      //Finally look in the IMS.POS.Web.Views.Core 
      "Areas/{2}/Views/{1}/{0}.cshtml" 
     }; 

     ViewLocationFormats = new[] 
     { 
      "~/PosViews/%1/{1}/{0}.cshtml", 
      "~/PosViews/%1/Shared/{0}.cshtml", 
      "~/PosViews/Shared/{0}.cshtml", 
      "~/Views/{1}/{0}.cshtml", 
      "~/Views/Shared/{0}.cshtml" 
     }; 

     MasterLocationFormats = ViewLocationFormats; 

     PartialViewLocationFormats = new[] 
     { 
      "~/PosViews/%1/{1}/{0}.cshtml", 
      "~/PosViews/%1/Shared/{0}.cshtml", 
      "~/PosViews/Shared/{0}.cshtml", 
      "~/Views/{1}/{0}.cshtml", 
      "~/Views/Shared/{0}.cshtml" 
     }; 
    } 

このエンジンをアプリケーションの起動イベントに登録します。

public static void Configure() 
    { 
     var engine = new PosPrecompileEngine(typeof(ViewEngineConfig).Assembly) 
     { 
      UsePhysicalViewsIfNewer = true, 
      PreemptPhysicalFiles = true 
     }; 
     ViewEngines.Engines.Add(engine); 

     // StartPage lookups are done by WebPages. 
     VirtualPathFactoryManager.RegisterVirtualPathFactory(engine); 
    } 

ここに最終キーがあります。 RazorGeneratorがビューNuGetをインストールされるとき - あなたはデフォルトで起動

[assembly: WebActivatorEx.PostApplicationStartMethod(typeof(Views.Core.RazorGeneratorMvcStart), "Start")] 


public static class RazorGeneratorMvcStart 
{ 
    public static void Start() 
    { 
     var engine = new PrecompiledMvcEngine(typeof(RazorGeneratorMvcStart).Assembly) 
     { 
      UsePhysicalViewsIfNewer = true, 
      PreemptPhysicalFiles = true 
     }; 
     ViewEngines.Engines.Add(engine); 

     // StartPage lookups are done by WebPages. 
     VirtualPathFactoryManager.RegisterVirtualPathFactory(engine); 
    } 
} 

上で実行されます。この起動クラスで終わる - RazorGeneratorは、コレクション内の最初にViewEngineを追加

ViewEngines.Engines.Insert(0,engine); 

あなたがする必要がありますカスタムViewEngineは、ビューを見つけるに最初に使用され、この方法は -

ViewEngines.Engines.Add(engine); 

を追加しますので、それが最後のエンジンに追加されにそれを変更します。

このアプローチを使用すると、複数のアプリケーションでビューを再利用しながら、そのビューをオーバーライドすることができます。

これは、私が質問で言及したように、ほとんどのアプリケーションでは過剰である可能性があります。これは、複数のクライアントアプリケーションを開発するために使用する基本製品です。クライアントごとに柔軟性を維持しながら再利用を試みることは、我々が達成しようとしていたものです。

+0

exitingビューにカスタムコンテンツを追加できますか?私はこれを投稿しましたhttp://stackoverflow.com/questions/38303160/how-to-use-razor-to-process-dynamic-templates-included-in-web-page – Andrus

+0

この方法ではありません。これは、コントローラのアクションに基本的なビューのセットを提供し、必要に応じてオーバーライドするようなコンベンションです。あなたの質問には、カスタムベースビューを使用して独自のプロパティとRazorEngineのようなものを公開し、プロパティを通じてコン​​テンツを注入することがあります。 – JDBennett

関連する問題