如何拦截视图渲染以在所有局部视图上添加HTML/JS?

ley*_*cua 11 asp.net-mvc razor

我需要从约定驱动的位置编写js文件的内容(如〜/ ClientApp/Controllers/Home/Home.js,如果加载位于〜/ Views/Home/Home.cshtml的视图).我该怎么做呢?

示例:如果文件〜/ Views/Home/Home.cshtml如下所示:

<div id="some-partial-view">
   <!-- ... -->
</div>
Run Code Online (Sandbox Code Playgroud)

文件〜/ ClientApp/Controllers/Home/Home.Controller.js看起来像

function HomeController() {
  //some code
}
Run Code Online (Sandbox Code Playgroud)

然后,Web服务器返回的渲染视图应该看起来像(如果使用fiddler)

<!--ommitted <html> <body> tags -->

<div id="some-partial-view">
   <!-- ... -->
</div>

<script type="text/javascript">
   function HomeController() {
       //some code
   }
</script>
Run Code Online (Sandbox Code Playgroud)

一种方法是添加一个HTML Helper,它将执行此操作,例如:

<div id="some-partial-view" ng:Controller="HomeController">
   <!-- ... -->
</div>
@Html.IncludeController("HomeController") 
Run Code Online (Sandbox Code Playgroud)

但是,我不想在所有部分视图中重复这一点.

有任何想法吗?

Dar*_*rov 15

您可以编写自定义视图:

public class MyRazorView : RazorView
{
    public MyRazorView(ControllerContext controllerContext, string viewPath, string layoutPath, bool runViewStartPages, IEnumerable<string> viewStartFileExtensions, IViewPageActivator viewPageActivator)
        : base(controllerContext, viewPath, layoutPath, runViewStartPages, viewStartFileExtensions, viewPageActivator)
    {

    }

    protected override void RenderView(ViewContext viewContext, TextWriter writer, object instance)
    {
        base.RenderView(viewContext, writer, instance);

        var view = (BuildManagerCompiledView)viewContext.View;
        var context = viewContext.HttpContext;
        var path = context.Server.MapPath(view.ViewPath);
        var viewName = Path.GetFileNameWithoutExtension(path);
        var controller = viewContext.RouteData.GetRequiredString("controller");
        var js = context.Server.MapPath(
            string.Format(
                "~/ClientApp/Controllers/{0}/{0}.{1}.js",
                viewName,
                controller
            )
        );
        if (File.Exists(js))
        {
            writer.WriteLine(
                string.Format(
                    "<script type=\"text/javascript\">{0}</script>",
                    File.ReadAllText(js)
                )
            );
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

和一个自定义视图引擎,它将在请求部分视图时返回此自定义视图:

public class MyRazorViewEngine : RazorViewEngine
{
    protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
    {
        return new MyRazorView(
            controllerContext, 
            partialPath, 
            null, 
            false, 
            base.FileExtensions, 
            base.ViewPageActivator
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

将注册Application_Start:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);

    ViewEngines.Engines.Clear();
    ViewEngines.Engines.Add(new MyRazorViewEngine());
}
Run Code Online (Sandbox Code Playgroud)

你可能可能需要调整一些路径,因为在你的问题中不太清楚js究竟应该在哪里,但通常你应该在答案中有足够的细节.