Transferring data between ASP.NET MVC 3 view hierarchy

Motivation

I want to create a tree-like hierarchy of objects in Javascript that matches the ASP.NET MVC 3 Razor views on the page. The plan is to have a one-to-one correspondence between the Razor representation and the Javascript file, where its logic is defined (in the form of a constructor function that will take some initialization parameters). A simple example might look like this:

  • _Layout.cshtml <-> Global.js
    • SplitterPane.cshtml <-> SplitterPane.js
      • Grid.cshtml <-> Grid.js
      • Tree.cshtml <-> Tree.js

I would use constructors to build a hierarchy, for example.

 var page = new Global(global_options); var splitter = new SplitterPane(splitter_options); var grid = new Grid(grid_options); var tree = new Tree(tree_options); page.addChild(splitter); splitter.addChild(grid); splitter.addChild(tree); 

All this code should, of course, be automatically generated in the context of the root view (layout) from metadata collected from partial views. The metadata provided by the view contains the parameters needed to initialize the Javascript object and the loaded Javascript files.

Problem

Unlike WebForms, MVC views do not have any natural hierarchy that I would know about, and transferring information between a view and its partial (sub) views seems rather complicated. When using helpers, such as Html.Action , in the view, all processing of "subview" occurs independently, so they don’t even share the Page object. I need some kind of central place where views can lay off their metadata as they are rendered so that they can be used in the layout to combine and output the full script.

Decision?

One way I could think of is to use HttpContext.Current.Items to temporarily store a collection of view metadata objects. All views will contain metadata, and the layout will use it. The order of execution seems to meet my expectation, however, I still cannot restore the hierarchy of tree views. To be able to do this, I will need to use a stack where the view will register at the beginning of its rendering and unregister at the end so that the parent can be found on top.

  • Is there a way to have some pre / post-rendering hooks where I could put this logic?
  • Is that even a good idea in the first place?
  • Is there a completely different solution that I don't see?
+4
source share
2 answers

You can write your own viewing engine:

 public class MyViewEngine : RazorViewEngine { private class MyRazorView : RazorView { public MyRazorView(ControllerContext controllerContext, string viewPath, string layoutPath, bool runViewStartPages, IEnumerable<string> viewStartFileExtensions, IViewPageActivator viewPageActivator) : base(controllerContext, viewPath, layoutPath, runViewStartPages, viewStartFileExtensions) { } protected override void RenderView(ViewContext viewContext, System.IO.TextWriter writer, object instance) { var stack = viewContext.HttpContext.Items["stack"] as Stack<string>; if (stack == null) { stack = new Stack<string>(); viewContext.HttpContext.Items["stack"] = stack; } // depending on the required logic you could // use a stack of some model and push some additional // information about the view (see below) stack.Push(this.ViewPath); base.RenderView(viewContext, writer, instance); } } protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath) { return new MyRazorView(controllerContext, viewPath, masterPath, true, base.FileExtensions, base.ViewPageActivator); } protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath) { return new MyRazorView(controllerContext, partialPath, null, false, base.FileExtensions, base.ViewPageActivator); } } 

so you sign up for Application_Start :

 ViewEngines.Engines.Clear(); ViewEngines.Engines.Add(new MyViewEngine()); 

and now you can write your own HTML helper that will select the stack that was saved in the HttpContext and do something useful:

 public static class HtmlExtensions { public static IHtmlString BuildTree(this HtmlHelper htmlHelper) { var stack = htmlHelper.ViewContext.HttpContext.Items["stack"] as Stack<string>; if (stack == null) { return MvcHtmlString.Empty; } // TODO: your custom logic to build the tree ... } } 

and at the end of your _Layout:

  ... <script type="text/javascript"> @Html.BuildTree() </script> </body> 
+2
source

If you just want to link the view to a Javascript file, define a section in your layout.cshtml (before closing the body tag):

 @RenderSection("scripts", false") 

Then on your pages and views:

 @section scripts { <script type="text/javascript" src="path to script"></script> } 

However, this will not work when you move on to partial views. To handle partial views, I used a custom Html extension. @ Html.RenderResource ("{sectionname}," ~ / {resource path} ")

-2
source

Source: https://habr.com/ru/post/1392337/


All Articles