Reputation: 39695
I'm trying to find the assembly of a page request during runtime. I have used the code at Get current System.Web.UI.Page from HttpContext? which work for most calls, but there is an issue.
If in my aspx.cs I instantiate a class variable at the top of my class HttpContext.Current.CurrentHandler
is null.
Example
I have one DLL named Business.dll
with the function to get the Page type as per the above SO question.
In my page, default.asp in FrontEnd.dll
I have the following call:
public partial class FrontEnd: Page
{
private readonly Type _t = Business.GetPageType();
The above code return HttpContext.Current.CurrentHandler as null and HttpContext.Current.ApplicationInstance return HttpApplication as the type, and hence System.Web as the assembly.
If I however write it like this:
public partial class FrontEnd: Page
{
readonly Type _t;
protected override void OnInit(EventArgs e)
{
_t = Business.GetPageType();
it works just fine, and I get a reference to CurrentHandler and the page. I could of course refactor all places and move the variable initialization to OnInit, but this requires convention in the app and a higher degree of maintenance.
Using Assembly.GetEntryAssembly()
return null for the example and Assembly.GetExecutingAssembly()
return Business.dll, so I cannot use them either.
Is there possible another way to find the type/dll, perhaps using the Request Url to find the type/dll which it originates from?
[Update]
So far I have this code, as all my dll's are signed with a known key (not including the extra methods for checking the signing key):
StackTrace stackTrace = new StackTrace();
StackFrame[] stackFrames = stackTrace.GetFrames();
Assembly firstAssembly = null;
foreach (StackFrame stackFrame in stackFrames)
{
var method = stackFrame.GetMethod();
Type t = method.DeclaringType;
if (t != null && t.Assembly.Is(SignedBy.Me))
{
firstAssembly = t.Assembly;
}
}
if( firstPzlAssembly != null)
{
return firstPzlAssembly;
}
While it works, it seems wrong and will have a potential performance hit if called often.
Upvotes: 0
Views: 589
Reputation: 7535
When you do it this way:
private readonly Type _t = Business.GetPageType();
it is actually compiled into a field initialization within the constructor. It means that the object (your page) is not constructed yet. It does not exist yet, it is "being born". You are just within the constructor at this stage.
Until your object (the page) is constructed, ASP.NET infrastructure cannot assign it to an HttpContext.Current.CurrentHandler static property. Well, because the handler (your page) does not exist yet and id being constructed.
So you cannot do what you want.
What you can do is to create a PageBase class, override OnInit method and add this code there:
public abstract class PageBase
{
protected Type PageType { get; private set; }
protected override void OnInit(EventArgs e)
{
PageType = Business.GetPageType();
}
}
and now just derive your pages from this base class:
public partial class FrontEnd: PageBase { .... }
(or specify PageBase as a base class directly in ASPX file, whatever you do.
Upvotes: 2
Reputation: 6844
One option, is to define a single base page, with the OnInit function setup as required, and then ensure that all your other pages inherit from that.
For example:
public class CustomBasePage: Page
{
readonly Type _t;
protected override void OnInit(EventArgs e)
{
_t = Business.GetPageType();
}
}
Then alter all your pages to inherit from this instead of the normal Page
class:
public partial class FrontEnd: CustomBasePage
This means you only need to define your logic once and places a minimal overhead on the rest of the applications pages.
If any page need to override OnInit
for another reason, it just needs to include a call to base.OnInit();
which isn't too onerous.
You'll need to ensure that your Business.GetPageType();
return what you expect. I'm not clear on exactly what it is doing and whether it will return the FrontEnd
or CustomBasePage
class, (nor which of those would be acceptable to your application logic).
Upvotes: 0