2011-02-25 14 views
5

就像我可以通過調用ControllerBuilder.Current.SetControllerFactory()設置DefaultControllerFactory我自己在global.asax並提供工廠的自定義實現,是否有可能以某種方式提供應用程序與我自己執行WebPageRazorHostFactory的?定製WebPageRazorHostFactory

我想要實現的是在IoC容器中封裝視圖以提供依賴注入。我已閱讀以下有關Haacked的文章:http://haacked.com/archive/2011/02/21/changing-base-type-of-a-razor-view.aspx,我認爲這可能會增加該解決方案。

下似乎並沒有工作,並拋出一個錯誤:

Unable to cast object of type 'ASP._Page_Views__ViewStart_cshtml' to type 'System.Web.WebPages.StartPage

的Global.asax:(C#項目)

protected void Application_Init() 
    { 
     System.Web.WebPages.Razor.RazorBuildProvider.RegisterBuildProvider("cshtml", typeof(DefaultRazorBuildProvider)); 
    } 

類定義:(VB項目)

Public Class DefaultRazorBuildProvider : Inherits System.Web.WebPages.Razor.RazorBuildProvider 
    Private Shared _factories As New ConcurrentDictionary(Of String, Func(Of IKernel, DefaultWebPageRazorHostFactory))(StringComparer.OrdinalIgnoreCase) 
    Private Shared _kernel As IKernel 

    Friend Shared TypeFactory As Func(Of String, Type) = AddressOf DefaultTypeFactory 

    Public Shared Function GetKernel() As IKernel 
     If _kernel Is Nothing Then Throw New NullReferenceException("_kernel is not set") 

     Return _kernel 
    End Function 

    Public Shared Sub SetKernel(ByVal kernel As IKernel) 
     _kernel = kernel 
    End Sub 

    Public Shared Function CreateHostFromConfig(ByVal virtualPath As String) As WebPageRazorHost 
     Return CreateHostFromConfig(virtualPath, Nothing) 
    End Function 

    Public Shared Function CreateHostFromConfig(ByVal virtualPath As String, ByVal physicalPath As String) As WebPageRazorHost 
     If [String].IsNullOrEmpty(virtualPath) Then 
      Throw New ArgumentNullException("virtualPath") 
     End If 

     Return CreateHostFromConfigCore(GetRazorSection(virtualPath), virtualPath, physicalPath) 
    End Function 

    Public Shared Function CreateHostFromConfig(ByVal config As RazorWebSectionGroup, ByVal virtualPath As String) As WebPageRazorHost 
     Return CreateHostFromConfig(config, virtualPath, Nothing) 
    End Function 

    Public Shared Function CreateHostFromConfig(ByVal config As RazorWebSectionGroup, ByVal virtualPath As String, ByVal physicalPath As String) As WebPageRazorHost 
     If config Is Nothing Then 
      Throw New ArgumentNullException("config") 
     End If 
     If [String].IsNullOrEmpty(virtualPath) Then 
      Throw New ArgumentNullException("virtualPath") 
     End If 

     Return CreateHostFromConfigCore(config, virtualPath, physicalPath) 
    End Function 

    Friend Shared Function CreateHostFromConfigCore(ByVal config As RazorWebSectionGroup, ByVal virtualPath As String) As WebPageRazorHost 
     Return CreateHostFromConfigCore(config, virtualPath, Nothing) 
    End Function 




    Private Shared Function CreateFactory(ByVal typeName As String) As Func(Of IKernel, DefaultWebPageRazorHostFactory) 
     Dim factoryType As Type = TypeFactory(typeName) 
     If factoryType Is Nothing Then 
      Throw New InvalidOperationException("Factory type not valid") 
     End If 



     Dim param = Expression.Parameter(GetType(IKernel)) 

     Dim body = Expression.[New](factoryType.GetConstructor(New Type() {GetType(IKernel)}), param) 
     Return Expression.Lambda(Of Func(Of IKernel, DefaultWebPageRazorHostFactory))(body, param).Compile() 
    End Function 



    Public Shared Sub ApplyConfigurationToHost(ByVal config As RazorPagesSection, ByVal host As WebPageRazorHost) 
     host.DefaultPageBaseClass = config.PageBaseType 

     For Each import As String In config.Namespaces.OfType(Of NamespaceInfo)().[Select](Function(ns) ns.[Namespace]) 
      host.NamespaceImports.Add(import) 
     Next 
    End Sub 


    Friend Shared Function CreateHostFromConfigCore(ByVal config As RazorWebSectionGroup, ByVal virtualPath As String, ByVal physicalPath As String) As WebPageRazorHost 

     virtualPath = EnsureAppRelative(virtualPath) 

     If virtualPath.StartsWith("~/App_Code", StringComparison.OrdinalIgnoreCase) Then 
      Return New WebCodeRazorHost(virtualPath, physicalPath) 
     End If 

     Dim factory As DefaultWebPageRazorHostFactory = Nothing 
     If config IsNot Nothing AndAlso config.Host IsNot Nothing AndAlso Not [String].IsNullOrEmpty(config.Host.FactoryType) Then 
      Dim factoryCreator As Func(Of IKernel, DefaultWebPageRazorHostFactory) = _factories.GetOrAdd(config.Host.FactoryType, CreateFactory(config.Type)) 
      Debug.Assert(factoryCreator IsNot Nothing) 
      factory = factoryCreator(_kernel) 
     End If 

     Dim host As WebPageRazorHost = (If(factory, New DefaultWebPageRazorHostFactory(_kernel))).CreateHost(virtualPath, physicalPath) 

     If config IsNot Nothing AndAlso config.Pages IsNot Nothing Then 
      ApplyConfigurationToHost(config.Pages, host) 
     End If 

     Return host 
    End Function 

    Friend Shared Function GetRazorSection(ByVal virtualPath As String) As RazorWebSectionGroup 
     Return New RazorWebSectionGroup() With { _ 
      .Host = DirectCast(WebConfigurationManager.GetSection(HostSection.SectionName, virtualPath), HostSection), _ 
      .Pages = DirectCast(WebConfigurationManager.GetSection(RazorPagesSection.SectionName, virtualPath), RazorPagesSection) _ 
     } 
    End Function 

    Private Shared Function EnsureAppRelative(ByVal virtualPath As String) As String 
     If HostingEnvironment.IsHosted Then 
      virtualPath = VirtualPathUtility.ToAppRelative(virtualPath) 
     Else 
      If virtualPath.StartsWith("/", StringComparison.Ordinal) Then 
       virtualPath = "~" & virtualPath 
      ElseIf Not virtualPath.StartsWith("~/", StringComparison.Ordinal) Then 
       virtualPath = "~/" & virtualPath 
      End If 
     End If 
     Return virtualPath 
    End Function 

    Private Shared Function DefaultTypeFactory(ByVal typeName As String) As Type 
     Return BuildManager.[GetType](typeName, False, False) 
    End Function 
End Class 

Public Class DefaultWebPageRazorHostFactory : Inherits System.Web.WebPages.Razor.WebRazorHostFactory 
    Private _kernel As IKernel 

    Public Sub New() 
     Me._kernel = Nothing 
    End Sub 

    Public Sub New(ByVal kernel As IKernel) 
     Me._kernel = kernel 
    End Sub 

    Public Overrides Function CreateHost(ByVal virtualPath As String, ByVal physicalPath As String) As System.Web.WebPages.Razor.WebPageRazorHost 
     Return New DefaultWebPageRazorHost(Me._kernel, virtualPath, physicalPath) 
    End Function 
End Class 

Public Class DefaultWebPageRazorHost : Inherits System.Web.WebPages.Razor.WebPageRazorHost 
    Private _kernel As IKernel 

    Sub New(ByVal kernel As IKernel, ByVal virtualPath As String, ByVal physicalPath As String) 
     MyBase.New(virtualPath, physicalPath) 
     Me._kernel = kernel 
    End Sub 
End Class 

回答

8

Yes;在Web.config中:

<system.web.webPages.razor> 
    <host factoryType="MyProject.MyWebPageRazorHost" /> 
    <pages pageBaseType="MyProject.CustomWebPage"> 
     <namespaces> 
      <add namespace="MyProject.SomeNamespace" /> 
     </namespaces> 
    </pages> 
</system.web.webPages.razor> 

編輯

要在代碼中創建主機,可以繼承RazorBuildProvider並覆蓋CreateHost方法,然後註冊CSHTML和VBHTML你繼承的版本。
進行覆蓋時,你需要爲App_Code內頁返回WebCodeRazorHost

你應該下載the source code;這將有極大的幫助。
mvc3-rtm-sources\webpages\src\System.Web.WebPages.Razor

+0

我的意思是將其設置在'global.asax'中,這樣我就可以提供Windsor的內核(我正在使用的IoC框架) – Ropstah 2011-02-25 16:02:11

+1

好問題;讓我看看它。至少,你可以創建一個包裝器,從IoC創建一個內部實例。 – SLaks 2011-02-25 16:03:34

+0

@Ropstah:你在這裏。 – SLaks 2011-02-25 16:12:07