我正在将ASP.NET webforms应用程序升级/修改为MVC5 - 理想情况下是Razor引擎(允许自动移动布局页面切换,并利用MVC功能)。< / p>
我们有数百个服务器端包含,全部名为* .inc。他们的绝对gobs。应用程序非常庞大,以至于我们必须逐页转换页面 - 没有办法一次完成所有操作。 (为了了解这个项目有多大以及它已经存在了多长时间,我们迁移到TFS时VSS中的整个源代码控制历史记录大约是10GB。这包括很多媒体文件,但仍然是。&#39 ;大,但它不会消失。)
有没有办法可以转换这些#!include调用RenderPartial()或RenderAction()调用而不用将每个文件重命名为.cshtml?
复制包含文件是一个不好的建议,因为这会破坏DRY。
理想情况下,我希望一个部分视图可以处理这个问题 - 我想它会将文件名作为参数,而且这是一个单行的内容,所以我可以培养每个人轻松转换这些。
我还想要一些文件级缓存。只需加载磁盘和输出;将它转储到输出流中对小型网站来说很不错......但这不是一个小网站。
我们有一个ascx文件,现在可以为许多这些包含进行缓存 - 但我不知道如何在Razor中编写相应的文件。
编辑1:这些大部分都是非代码包含的,但我确定用户控件定义已经陷入了一些困境。我必须重写那些,所以假设答案是&#34;这些是纯HTML,没有代码&#34;
编辑2:我们遇到包含文件嵌套的情况(我发誓不是这样)。包含文件可以包含其他文件。我有一个缓存ASCX控件来递归处理这个,所以这是移植代码的问题。
编辑3:任何可能的解决方案也必须适用于布局cshtml文件。我们已经包含在现有的母版页中。
答案 0 :(得分:6)
在我的头脑中,我可以想到解决这个问题的四种方法。
注意:我没有过多地使用缓存机制,因为这个设计决定超出了这个问题。
创建一个控制器/动作来为您呈现包含:
public class IncludeController : Controller
{
// GET: Render
public ActionResult Render(string path)
{
return new IncludeResult(path);
}
}
public class IncludeResult : ActionResult
{
private string _path { get; set; }
public IncludeResult(string path)
{
_path = path;
}
public override void ExecuteResult(ControllerContext context)
{
// possibly check the cache here, or let MVC handle cache at the action level
// get the contents of the include file output to the response
context.HttpContext.Response.Write(File.OpenRead(_path));
}
}
在视图中
@Html.Action("Render", "Include", new {path = "~/Includes/test.inc"})
注意:尝试使用FilePathResult,它似乎返回奇数字符,因此自定义IncludeResult
创建HtmlHelper扩展程序:
public static class HtmlExtension
{
public static MvcHtmlString RenderInclude(this HtmlHelper helper, string path)
{
// check the cache
string output = File.ReadAllText(path);
return new MvcHtmlString(output);
}
}
在视图中
@Html.RenderInclude("~/includes/test.inc")
我认为这个选项适合你想要做的最好,但是从最纯粹的方法来看,这可能不符合MVC做事的方式&#39;
扩展RazorViewEngine以查找包含文件:
我没有对这个问题进行过深入探讨,并且可能对你想要达到的目标有点过分,但以下博客中有一些代码示例可以帮助你:http://weblogs.asp.net/imranbaloch/view-engine-with-dynamic-view-location
然后您可以在视图中使用标准Html.Partial
代码
@Html.Patial("~/includes/test.inc");
将包含内容公开在视图模型的属性中:
这似乎是最麻烦的,但它仍然是一种选择。
public class ViewModel
{
public MvcHtmlString IncludeContents { get; set; }
....
private GetIncludeContent(string path)
{
IncludeContents = new MvcHtmlString(File.ReadAllText(path));
}
}
然后在视图中
@model.IncludeContents
答案 1 :(得分:2)
我强烈推荐:
编辑您的网络配置并添加(BuildProviders信息):
<system.web>
<compilation debug="true" targetFramework="4.5">
// Start (Build Provider Information)
<buildProviders>
<add extension=".inc"
type="System.Web.WebPages.Razor.RazorBuildProvider, System.Web.WebPages.Razor"/>
</buildProviders>
// End (Build Provider Information)
</compilation>
</system.web>
这为运行时引擎提供了构建INC文件的构建提供程序。如果它们是纯HTML,那么我们只需要注册一些东西,这样MVC就会包含它们。
创建新的视图引擎:
public class CustomViewEngine : RazorViewEngine
{
public CustomViewEngine()
{
PartialViewLocationFormats = new[]
{
"~/Views/{1}/{0}.cshtml",
"~/Views/{1}/{0}.vbhtml",
"~/Views/Shared/{0}.cshtml",
"~/Views/Shared/{0}.vbhtml",
"~/Include/{0}.inc" // Path to your include files
};
FileExtensions = new[]
{
"cshtml",
"vbhtml",
"inc",
};
}
}
注册您的视图引擎:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
// Need to let the RazorCodeLanguage it can compile .inc files
RazorCodeLanguage.Languages.Add("inc", new CSharpRazorCodeLanguage());
// Need to register the extension with the WebPage Http Handler
WebPageHttpHandler.RegisterExtension("inc");
// Create the engine
var viewEngine = new CustomViewEngine();
// Clear unused Engines
ViewEngines.Engines.Clear();
// Add only the modified razor engine
ViewEngines.Engines.Add(viewEngine);
}
}
将 \Views\Web.config
复制到\Include\Web.Config
,让视图引擎了解视图的来源。
文件\Include\Test.inc
包含:
<div>Some Data</div>
现在您只需添加:
@Html.Partial("Test")
或(更高效)
@{Html.RenderPartial("Test");}
现在您的INC文件已完全MVC化。这意味着任何MVC缓存控制等都可以像任何.cshtml
文件一样正常工作。
<强>加成强>
由于我们将您的\Include\*.inc
迁移到\Views\Shared\*.cshtml
文件,因此我们直接绑定到RazorViewEngine,您不必须修改任何{ {1}}因为它先查看共享然后包含。一旦你没有更多的包含文件并且网站继续工作,你最终可以删除所有内容(我推荐)。
答案 2 :(得分:0)
根据Brent的第二个选项,我使用WebClient
下载HTML字符串,而不是从磁盘加载它。我们有一些嵌套的SSI,因此从磁盘加载并不是那么容易。
public static HtmlString RenderInclude(this HtmlHelper helper, string path)
{
WebClient client = new WebClient();
string url = string.Format("{0}://{1}{2}{3}",
HttpContext.Current.Request.IsSecureConnection ? "https" : "http",
HttpContext.Current.Request.Url.Host,
HttpContext.Current.Request.Url.Port == 80 ? "" : ":" + HttpContext.Current.Request.Url.Port.ToString(),
path);
string html = client.DownloadString(url);
return new HtmlString(html);
}
然后在剃刀中:
@Html.RenderInclude("/includes/test.inc")
也许没那么快,但我需要一个临时解决方案来让我们的嵌套SSI在迁移时工作。