What is the best way to intercept the analysis of all elements in a subtree of an ASP.NET user control

I would like to intercept the parsing of each control in the entire subtree of my own User Control.

I have currently overridden the protected method Control.AddParsedSubObject in my user control. It is limited to intercepting parsing on immediate child controls in declarative syntax because each of these controls has its own AddParsedSubObject method for further analysis of its own child controls.

From the user control, I cannot get into child children to intercept these collapsible calls.

In the following declarative example of my user control, I can access the tv object from an override of User Control AddParsedSubObject.

 <asp:TreeView runat="server" id="tv" /> 

However, I cannot access the tv object in the following example (or other children of the first panel), because this parsing is handled by Panel or its children.

 <asp:Panel runat="server"> <asp:TreeView runat="server" id="tv" /> <asp:Panel runat="server"> <asp:TextBox runat="server" /> </asp:Panel> </asp:Panel> 

My code in a user control is as follows

  // User control interception of its parsed children protected override void AddParsedSubObject(object obj) { // Do some custom work with the control object. if (obj is Control && ((Control)obj).ID == "tv") { TreeView tv = (TreeView)obj; DoSomethingWithParsedObject(tv); } // Let ASP.NET continue and put the control in the page hierarchy base.AddParsedSubObject(obj); } 

Looking for ideas on how I can intercept the parsing of each control in the entire subtree of my user control. For example, I want to write out user information at each step of the analysis.

+7
webforms user-controls
source share
1 answer

If you are using .Net 4.5, there is a good way to achieve it. Asp.Net uses ControlBuilder to create temporary cs files from aspx layouts. Prior to .Net 4.5, you can only intercept it by reflecting and switching some internal static variables in the ControlBuilder class.

But in .Net 4.5, they added a new ControlBuilderInterceptor class. Then you can write code like this:

 namespace TestInterceptApp { public class BuilderInterceptor : ControlBuilderInterceptor { public override void OnProcessGeneratedCode(ControlBuilder controlBuilder, CodeCompileUnit codeCompileUnit, CodeTypeDeclaration baseType, CodeTypeDeclaration derivedType, CodeMemberMethod buildMethod, CodeMemberMethod dataBindingMethod, IDictionary additionalState) { base.OnProcessGeneratedCode(controlBuilder, codeCompileUnit, baseType, derivedType, buildMethod, dataBindingMethod, additionalState); buildMethod.Statements.Insert( buildMethod.Statements.Count - 1, new CodeSnippetStatement("TestInterceptApp.ControlInterceptor.Intercept(@__ctrl);")); } } } 

Then you need to change the compilation section in web.config to register this class in Asp.Net:

  <system.web> <compilation debug="true" targetFramework="4.5" controlBuilderInterceptorType="TestInterceptApp.BuilderInterceptor"/> </system.web> 

And then you can write this interceptor class as follows:

 namespace TestInterceptApp { public static class ControlInterceptor { public static void Intercept(TreeView control) { // Do some custom work with the control object. if (control.ID == "tv") { control.Nodes.Add(new TreeNode("Test")); } } public static void Intercept(object obj) { // just ignore all others controls } } } 

Basically, when ControlBuilder creates new cs files, it inserts this line

  "TestInterceptApp.ControlInterceptor.Intercept(@__ctrl);" 

to the end of each control generation block. You can define one method in the ControlInterceptor class with an object parameter, or you can do a couple of necessary overloads with certain parameters. And plus one basic method with an object parameter. When the CLR executes it, if the TreeView control, then it will send it to fix the method. For all other controls such as Literal, Button, HtmlHead, Page, etc. The CLR will use the method with the signature of the object.

My sample will simply add a new TestNode to each TreeView in the current application that has ID = "tv". And the code generated by ControlBuilder is this:

  [System.Diagnostics.DebuggerNonUserCodeAttribute()] private global::System.Web.UI.WebControls.TreeView @__BuildControltv() { global::System.Web.UI.WebControls.TreeView @__ctrl; #line 32 "c:\users\someuser\documents\visual studio 11\Projects\TestInterceptApp\TestInterceptApp\Default.aspx" @__ctrl = new global::System.Web.UI.WebControls.TreeView(); #line default #line hidden this.tv = @__ctrl; @__ctrl.TemplateControl = this; @__ctrl.ApplyStyleSheetSkin(this); #line 32 "c:\users\someuser\documents\visual studio 11\Projects\TestInterceptApp\TestInterceptApp\Default.aspx" @__ctrl.ID = "tv"; #line default #line hidden #line 32 "c:\users\someuser\documents\visual studio 11\Projects\TestInterceptApp\TestInterceptApp\Default.aspx" this.@ __BuildControl__control3(@__ctrl.Nodes); #line default #line hidden // here is that line that we added via ControlBuilderInterceptor TestInterceptApp.ControlInterceptor.Intercept(@__ctrl); this.@ __PageInspector_SetTraceData(new object[] { @__ctrl, null, 1838, 368, false}); return @__ctrl; } 
+4
source share

All Articles