27

我有一个使用MEF的复合ASP .NET MVC 3 Razor应用程序。如果我想在应用程序的常规Views文件夹下部署插件作为DLL文件和视图(CSHTML),一切都会顺利。但是这不是很干净,如果我不将视图作为嵌入式资源放入DLL文件(以及控制器和模型),它将不会成为真正的插件。类库中的MEF和Razor视图

我跟着很多文章(其中大部分都是过时的)。事实上,有一个在这里挺好的一个堆栈溢出:Controllers and Views inside a Class Library

我也检查文档为VirtualPathProvider,我已经能够建立一个认定的组装和加载它完美中的文件自定义一个(或至少得到它的流)。为此,我遵循了VirtualPathProviderdocumentation on MSDN

还有一个VirtualFile的实现,但还没有VirtualDirectory的实现。

这是问题所在。我正在使用剃刀视图。我知道他们需要web.config文件中的配置规范来为Razor构建它们。但是如果我将它们嵌入到DLL中,这个配置就会丢失。

我不知道这就是为什么我不断收到错误:

The view at '~/Plugins/CRM.Web.Views.CRM.Index.cshtml' must derive from WebViewPage, or WebViewPage.

也许我只需要添加一些代码,使其工作?有任何想法吗?

+1

需要思考的问题:如果我要在每个cshtml文件中添加“@inherits System.Web.Mvc.WebViewPage”,一切都会很顺利。不过,我不能简单地这样做(对于已经使用常规视图文件自动执行的操作,这将是一项巨大的工作)。那么,有什么想法? – 2011-02-15 18:21:33

+0

这篇文章可能有些帮助,但我现在根本无法测试。我会尽快尝试,并在此发布结果/答案。 http://stackoverflow.com/questions/6465855/a-plugin-framework-with-asp-net-mvc3-and-embedded-razor-views – 2011-11-08 13:02:53

+0

你是否已经尝试将配置文件放入一个合适的虚拟路径,以这种方式来模拟我们在Mvc视图文件夹下的“标准排列”? – 2012-04-07 16:39:07

回答

2

Hossam,

你在谈论的帖子是Darin已经建议的。该方法的主要缺点是使用自定义MvcRazorClassGenerator编译器将CSHTML视图文件转换为类文件。为此,必须将项目中的每个CSHTML视图设置为“内容”,并将“自定义工具”设置为MvcRazorClassGenerator。

我不能为LordALMMa说话,但我确实下载了编译器源代码并给了它一个镜头,它并不像我希望的那样工作。

我的另一种方法是包括在外部DLL的CSHTML文件作为嵌入式资源,在文件的原始内容中读取并执行该视图作为字符串(参见CodeProject上RazorEngine为例:http://razorengine.codeplex.com/

我不想完全依赖于企业应用程序中的RazorEngine,因为我不知道它如何与所有Razor语法兼容,所以现在我放弃了这一点。

我来自我在ASP.NET MVC 2.0中构建的原型,它是一个多租户应用程序。在服务器场中,我们有一个运行应用程序的实例,其中所有客户端共享相同的代码库。在我的MVC 2.0原型中,我能够确定正在做什么“客户端”请求,检查一个自定义控制器,它覆盖基础(用于定制核心代码)并检查自定义视图(用于自定义核心观点)。这样做可以让我们为每个客户端部署一个“插件”。该软件检测客户端是否具有与请求匹配的自定义控制器以及与自定义操作相匹配的自定义操作,如果是,则会使用自定义控制器/操作。

当我开始将我的原型迁移到MVC 3时,我遇到了与LordALaMa相同的问题,错误“The view at'... Index.cshtml'必须从WebViewPage或WebViewPage派生”。我会着眼于在我的CSHTML视图中放置“@inherits System.Web.Mvc.WebViewPage”,看看是否让我更接近它的工作。

因为我有一个使用MVC 3的工作MVC 2.0原型Razor不是最重要的,我不会浪费大量时间。如果我们需要利用4.0 Framework,我确信我可以使用WebForms引擎将MVC 2.0移植到MVC 3.0。

7

我在类库中嵌入Razor视图的首选方法是将它们复制到MVC网站的Views/Areas文件夹中,并附带一个后期构建事件。如果您覆盖ViewEngine或VirtualPathProvider,则可以指定自定义视图位置。

对我来说,棘手的部分是让intellisense在这些视图类库中工作。首先,您必须将Web.Config添加到您的视图程序集。请注意,您不必将其包含在组件中。它只需位于程序集根目录(或视图文件夹)中。这是一个例子。关注重要的“装配/编译”部分。

<?xml version="1.0"?> 
<configuration> 
    <configSections> 
    <sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"> 
     <section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" /> 
     <section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" /> 
    </sectionGroup> 
    </configSections> 

    <system.web.webPages.razor> 
    <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> 
    <pages pageBaseType="System.Web.Mvc.WebViewPage"> 
     <namespaces> 
     <add namespace="System.Web.Mvc" /> 
     <add namespace="System.Web.Mvc.Ajax" /> 
     <add namespace="System.Web.Mvc.Html" /> 
     <add namespace="System.Web.Routing" /> 
     </namespaces> 
    </pages> 
    </system.web.webPages.razor> 

    <appSettings> 
    <add key="webpages:Enabled" value="false" /> 
    </appSettings> 

    <system.web> 
    <compilation targetFramework="4.0"> 
     <assemblies> 
     <add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> 
     <add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> 
     <add assembly="System.Data.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/> 
     <add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> 
     <add assembly="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> 
     </assemblies> 
    </compilation> 

    <httpHandlers> 
     <add path="*" verb="*" type="System.Web.HttpNotFoundHandler"/> 
    </httpHandlers> 

    <!-- 
     Enabling request validation in view pages would cause validation to occur 
     after the input has already been processed by the controller. By default 
     MVC performs request validation before a controller processes the input. 
     To change this behavior apply the ValidateInputAttribute to a 
     controller or action. 
    --> 
    <pages 
     validateRequest="false" 
     pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" 
     pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" 
     userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"> 
     <controls> 
     <add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="System.Web.Mvc" tagPrefix="mvc" /> 
     </controls> 
    </pages> 
    </system.web> 
    <system.webServer> 
    <validation validateIntegratedModeConfiguration="false" /> 
    <handlers> 
     <remove name="BlockViewHandler"/> 
     <add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" /> 
    </handlers> 
    </system.webServer> 
</configuration> 

接下来,你需要修改你的类库的vbproj文件,使所有OutputPath元素指向的不是“调试\ BIN \”或“释放\ BIN \”“斌\”。这是我在类库和ASP.Net Web项目类型之间找到的主要区别,这些类型可能导致智能感知错误。

如果您仍然收到必须继承错误,请考虑在您的视图中使用@Inherits System.Web.Mvc.WebViewPage。如果您没有将视图复制到您的网站项目中,则可以使用自定义ViewEngine/VirtualPathProvider从Embedded Resources加载它们。如果是这样,你肯定需要继承,所以剃刀知道你的视图基类是不幸的。

祝你好运。

0

嘿,我怀疑你有充分的理由要DLL内的意见。不过也要考虑到将所有东西打包成一个实体是一种不寻常的方式。

如果你正在开发一个插件,现在人们选择以NUGET格式打包,这也可以解决你的问题。它有一个.nupkg结构,它也是将包作为包和库分发的一种方式。

社区通常遵循的另一个解决方案是(如果他们不想像nuget那样精心制作某些东西),他们编写插件DLL,以便它不使用视图引擎(如剃刀),而是使用旧的原始的Response.Write方式,从而独立于cshtml文件。如果您仍想使用cshtml - 请参阅this blog entry将它们预编译为类。