Programatically Examining Page Controls Options

Posts   
 
    
psandler
User
Posts: 540
Joined: 22-Feb-2005
# Posted on: 12-Jun-2008 15:41:52   

This is not LLBL-related, but I thought someone here might have an idea of how to do it. I posted on microsoft.public.dotnet.framework.aspnet , but got no helpful replies.


I am trying to build a program that collects some metadata from my Asp.net application. I want to collect properties of a few specific types of controls that are used on a number of pages. The properties are set declaratively (on the aspx page itself), so just creating an instance of the class (code-behind) won't do it.

I was able to get all pages in the application using reflection, but using CreateInstance resulted in pages that did not have any controls.

As a basic example, assume I want to collect information about all label controls on all pages of my application. I want to collect each of their "Text" properties, which are set on the aspx page.

So I guess the first step is being able to create an instance of a page as if it were created via the asp.net framework (i.e. it is created using the declarative info on the aspx page), then drill into the controls and find controls of a given type(s) and collect the information.

Any idea if this is possible, and how to go about it?

Thanks for any insight.

Phil

Jez
User
Posts: 198
Joined: 01-May-2006
# Posted on: 12-Jun-2008 20:21:39   

Hmm. This is a little tricky becasuse the controls collection is not instantiated until the page lifecycle begins.

If you can instantiate your page type using BuildManager, then what you could do is feed it a 'fake' Http Context and let it run through the page lifecycle without actually rendering anything to the response stream. Now, this may have side effects depending on what your page is doing, but it would give you access to the control collection.

This works, but its a bit hacky...


var page = (Page)BuildManager.CreateInstanceFromVirtualPath("~/Test.aspx", typeof(Page));

var fakeResponse = new HttpResponse(new StringWriter());
var nextContext= new HttpContext(HttpContext.Current.Request, fakeResponse);

page.Init += delegate {
    //Controls collection is now fully populated.
    int count = page.Controls.Count;
};
        
page.ProcessRequest(newContext);

There may be a better way to do this, but it was the first thing that came to mind wink

psandler
User
Posts: 540
Joined: 22-Feb-2005
# Posted on: 12-Jun-2008 22:08:37   

Thanks for your response!

This didn't work for me. Here is the code translated to C#. Not sure if I did everything correctly:


            Page page = (Page)BuildManager.CreateInstanceFromVirtualPath("~\\Delays\\DelayAddEdit.aspx", typeof(DelayAddEdit));

            HttpResponse fakeResponse = new HttpResponse(new StringWriter());
            HttpContext nextContext = new HttpContext(HttpContext.Current.Request, fakeResponse);

            page.Init += delegate{
                //Controls collection is now fully populated.
                int count = page.Controls.Count;
            };

            page.ProcessRequest(nextContext);


I'm not clear on what the code inside the curly braces ({}) should do? Also, "newContext" was a typo? I changed it to "nextContext".

Should the controls be activated before the page.ProcessRequest line?

Thanks again for your help.

Phil

psandler
User
Posts: 540
Joined: 22-Feb-2005
# Posted on: 12-Jun-2008 22:25:22   

I should clarify what didn't work. Saying "it doesn't work" isn't helpful.

The controls.count is still 0 after this runs, and the page.ProcessRequest line actually causes the page to process, which thows an error when the page tried to access the Session object.

"Session state can only be used when enableSessionState is set to true, either in a configuration file or in the Page directive. Please also make sure that System.Web.SessionStateModule or a custom session state module is included in the <configuration><system.web><httpModules> section in the application configuration."

So maybe the code is working, but the session is not configured right for the fake handler?

Jez
User
Posts: 198
Joined: 01-May-2006
# Posted on: 12-Jun-2008 23:15:54   

psandler wrote:

Here is the code translated to C#

Um...it is C# wink

psandler wrote:

I'm not clear on what the code inside the curly braces ({}) should do?

The code inside the delegate runs on the Page_Init event...so any code inside this block will be able to access the control tree.

psandler wrote:

Also, "newContext" was a typo? I changed it to "nextContext".

Whoops frowning Yes, that was a typo. They were both supposed to be newContext.

psandler wrote:

Should the controls be activated before the page.ProcessRequest line?

No - ProcessRequest will cause the page lifecycle to execute. Then, as part of Page_Init the code defined in the anonymous delegate above will fire, and its inside the delegate that you need to put any code that will access the controls.

psandler wrote:

the page.ProcessRequest line actually causes the page to process, which thows an error when the page tried to access the Session object.

Yeah...that's the downside of using this approach...as we're building up a new httpcontext its likely there will be some issues. When I'm back in the office tomorrow I'll have a play with this and see if I can get it working.

psandler
User
Posts: 540
Joined: 22-Feb-2005
# Posted on: 12-Jun-2008 23:37:43   

Jez wrote:

psandler wrote:

Here is the code translated to C#

Um...it is C# wink

Hmm, I'm not familiar with "var". Is it a variant? It wouldn't compile in my IDE in any case. simple_smile

Jez wrote:

psandler wrote:

I'm not clear on what the code inside the curly braces ({}) should do?

The code inside the delegate runs on the Page_Init event...so any code inside this block will be able to access the control tree.

Ah, so this is a way of creating a delegate on the fly?

Jez wrote:

psandler wrote:

the page.ProcessRequest line actually causes the page to process, which thows an error when the page tried to access the Session object.

Yeah...that's the downside of using this approach...as we're building up a new httpcontext its likely there will be some issues. When I'm back in the office tomorrow I'll have a play with this and see if I can get it working.

Awesome, thanks!

Jez
User
Posts: 198
Joined: 01-May-2006
# Posted on: 13-Jun-2008 07:47:22   

psandler wrote:

Hmm, I'm not familiar with "var". Is it a variant? It wouldn't compile in my IDE in any case. simple_smile

Ah, I keep forgetting not everyone has upgraded to VS2008 simple_smile Var isn't variant, but rather tells the compiler to use type inference, so "var i = 1" is exactly the same as "int i = 1" etc. There's some info on it here if you're interested: http://msdn.microsoft.com/en-us/library/bb384061.aspx

psandler wrote:

Ah, so this is a way of creating a delegate on the fly?

Yes simple_smile

Jez
User
Posts: 198
Joined: 01-May-2006
# Posted on: 13-Jun-2008 09:32:25   

I'm not sure how you can create a new HttpSessionState and associate it with the new httpcontext - the Session property has no setter and HttpSessionState doesn't have a public constructor. Hmm.

Thinking about it, if all you need is the values of controls that are defined in the ASPX markup, could you not read in the contents of the aspx file and find the controls/attributes you're looking for with a regex?

psandler
User
Posts: 540
Joined: 22-Feb-2005
# Posted on: 13-Jun-2008 16:06:26   

Jez wrote:

I'm not sure how you can create a new HttpSessionState and associate it with the new httpcontext - the Session property has no setter and HttpSessionState doesn't have a public constructor. Hmm.

Thinking about it, if all you need is the values of controls that are defined in the ASPX markup, could you not read in the contents of the aspx file and find the controls/attributes you're looking for with a regex?

Hmmmmmmmmm, that actually might be a much better route to go. Will explore it and post back on how it goes.

Thanks for your help!

Phil