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.
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.
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).
Related
The function below is found in a class called page.cs
public static List<string> MyFunction()
{
var retList = new List<string>();
retList.Add("xzy");
retList.Add("abc");
return retList;
}
On page load how to call the function and check if the list contains
xzy and abc?
protected void Page_Load(object sender, EventArgs e)
{
//call MyFunction()
}
You don't really show enough code for us to see your problem. As I read it, you have a class Page in a file named page.cs and it looks like this in part:
public class Page {
public static List<string> MyFunction()
{
var retList = new List<string>
{
"xyz",
"abc",
};
return retList;
}
protected void Page_Load(object sender, EventArgs e)
{
var list = MyFunction();
}
}
(Note that I've simplified your initialization of the list - my code is equivalent to yours)
The code I show compiles. Assuming that MyFunction and Page_Load are in the same class, then you can directly call MyFunction from Page_Load (static functions can be called from instance function (within the same class)).
If they are not in the same class, let's say that MyFunction was a static function in another class (say OtherClass). Then Page_Load could call it in the way #joelcoehoorn describes:
OtherClass.MyFunction();
The reverse is not true. A static function cannot directly call an instance function (one without the static keyword) in the same class. You'll get an error complaining that you need an instance. For example, if MyFunction wanted to call Page_Load, it would need to do something like this:
var page = new Page();
//possibly do something with page
page.PageLoad(new object(), EventArgs.Empty);
//possibly do more stuff with page
If this doesn't answer your question, you need to add more to your question. In particular:
Show the class declarations around your method definitions. It's not clear (but it is important) which class(es) have which methods
Show us the code you have and any error messages you get (compile time and runtime)
Also note that I don't believe you should be getting Non-invocable member 'page' cannot be used like a method. if you did what #joelcoehoorn describes.
You have to reference the function using the type name. However, a file named page.cs likely had a class named Page, which will conflict with the base ASP.Net Page class. Therefore you must either fully-qualify the name (MyNamespace.Page.MyFunction()) or change the name of the class.
In our Page Object Model for Page we initialize a Container in the constructor and we define a HtmlEdit called MyTextBox and a method that uses this text box to search.
public class Page
{
private readonly UITestControl _container;
private HtmlEdit _myTextBox;
private const string MyTextBoxId = "MyTextBoxHtmlId";
protected Page()
{ }
protected Page(Process process)
{
CurrentBrowser = BrowserWindow.FromProcess(process);
_container = CurrentBrowser;
}
public UITestControl Container
{
get { return _container; }
}
protected HtmlEdit MyTextBox
{
get
{
if (_myTextBox == null)
{
_myTextBox = Container.FindHtmlEditById(MyTextBoxId);
}
return _myTextBox;
}
}
public Page SearchMethod(string accountId)
{
MyTextBox.CopyPastedText = accountId;
// Do the search
return this;
}
}
Here we want to use a UITestControl as container so that we can search within a specific area of the page. The FindHtmlEditById extension method in the getter finds the element by its html id as follows:
public static class Extensions
{
public static HtmlEdit FindHtmlEditById(this UITestControl control, string id)
{
return new HtmlEdit(control).FindById(id);
}
public static TUIControl FindById<TUIControl>(this TUIControl control, string id)
where TUIControl : HtmlControl
{
control.SearchProperties.Add(HtmlControl.PropertyNames.Id, id,
PropertyExpressionOperator.Contains);
return control;
}
}
So FindHtmlEditById searches for an element with a certain id within the scope of the Container.
When we execute the code and executions arrives at pasting text into MyTextBox we get the following error:
MyTextBox.CopyPastedText = 'MyTextBox.CopyPastedText' threw an exception of type 'System.NotSupportedException'
Furthermore, the ControlType of MyTextBox is Window as can be seen here:
When the type of the Container field in the the Page is changed to BrowserWindow as follows:
private readonly BrowserWindow _container;
public BrowserWindow Container
{
get { return _container; }
}
MyTextBox is properly recognized as a HtmlEdit:
BrowserWindow inherits from UITestControl. Why then does the Container needs to be specified as a BrowserWindow to work? Why does it not work as a UITestControl?
Can you provide a zip with a repro so I can have a closer look? It is obvious from the screenshots that in the one case you get a Window control back in stead of the HtmlEdit you are searching for, but as the reason why I can not give a conclusive answer. There might be a bug in your code with the CurrentBrowser since that seems to be a construct that is not correct, but also can be a flaw in the pasted code only. I copied the code and tried to reproduce using the bing homepage as the page to past the text in, and that works like a charm. So I suspect the search results in something different in your target website. One thing that might be causing this is the contains operator you use on the search, since this could potentially result in multiple matches depending on the page you are conducting the search on. When it returns multiple controls your call wil also fail, but looking at the whatch you shoed you did not get multiple controls but a window with a windows class edit, which much more looks like a WinEdit control then a HtmlEdit control.
BrowserWindow does not inherit from UITestControl, but is its own class under UITesting namespace. As such, it will have its own properties, methods, etc. Create your object as a BrowserWindow object to solve your exception.
However, to answer your more general inheritance question, even if BrowserWindow inherited from UITestControl, when dealing with inheritance: While the child will inherit all properties and methods from the parent, the parent will not have any of the methods that are created or overridden in its children. Thus, BrowserWindow can have a method .FindMyHtmlById(), but that wouldn't be available if your object was a UITestControl type.
I always get tied up with small things like this... I need to access an objects properties created in class 'Login' from my welcome page class 'Default'. When I try to reference the class so that I may access the object, VS 2010 doesn't list it as available like it normally would, and forcing the request just returns an error.
My Login Class is defined like so:
public abstract class Login : System.Web.UI.UserControl
{
...
private void Login_click(object sender, EventArgs e)
{
MyObject myObject = new MyObject();
myObject.property1 = "something";
}
}
And then i wish to access myObject from my default class, like this:
public class Default : System.Web.UI.Page
{
...
private void Page_load(object sender, System.EventArgs e)
{
string someLocalVar = Login.myObject.property1;
}
}
Where property1 is a property set in the Login class. This does not work, however, and VS doesn't even recognize the Login class; instead it treats it as a reserved word of some sort. These two files are in the same project, so that shouldn't be an issue in the using section. I've accessed variables in this manner between other classes before, just not this time for some reason.
Thanks!
2 things:
Your class is abstract
Your property is probably not static
You don't actually have a property, it's a local variable
You can't instantiate an instance of an abstract class. The point of an abstract class is to create a class with some shared code that other, similar child classes can inherit. Is there a reason your class is abstract?
If your property is not static you have to create an instance of your class in order to access the property. (Which, as I describe above, you can't because it's abstract). If you make your property static, you could then do Login.MyObject without creating an instance.
In the code you supplied, your variable is local to the Login_click method, which means even if you created an instance of your class you wouldn't be able to access it.
I suggest you pick up a C# book and read up on the fundamentals.
There's a number of issues here. First, you're accessing myObject like it's a member of Login, which it isn't. It's a local variable to your Login_click method. Second, you never create an instance of Login in your Default class, so unless it's a static class or you actually create an instance of it, you're not going to be able to access any members of it.
Here's something more like what you want (I think). I've left out your class inheritance for now.
public class Login
{
MyObject object;
public Login() {
object = new MyObject();
object.property1 = "something";
}
}
public class Default {
private void Login_click(object sender, EventArgs e)
{
Login _login = new Login();
string someLocalVar = _login.object.property1;
}
}
Like others have said, you need to more carefully plan this out and strengthen your programming skills before attempting this. This is basic stuff so it shouldn't take an exorbitant amount of time -- don't worry though, we all started here.
You can put your object into a Session variable, and then Cast it back.
//in Login.aspx
MyObject myObject = new MyObject();
myObject.property1 = "something";
Session["UserObject"] = myObject;
//in default.aspx
MyObject obj = (MyObject)Session["UserObject"]
string variable = obj.property1;
In my SharePoint 2010 c# / asp.net site, I have a class defined like
namespace PDF_Library.VisualWebPart1
{
public partial class PDF_Library : Usercontrol
{
public static PDF_Library current;
protected void Page_Load(object sender, EventArgs e)
{
current = (PDF_Library)this;
}
}
}
public static class Page_State
{
public static Page is_display()
{
return PDF_Library.current.Page; // didn't work...
}
}
It doesn't have a constructor.
How can I get the reference to the current instance of this class?
I tried something like this in the top
public static PDF_Library current;
Then in a function it had
current = (PDF_Library)this;
But that didn't work...
You need to understand that it does not work this way. Your question is tagged with asp.net - multi-user, multi-threaded environment where multiple instances of PDF_Library user control will be created all the time. It is absolutely uncertain which one of them will be hanging off PDF_Library.current. You need to rethink your design.
More on this: Page instance is disposed of when the request processing is finished. Normally this instance with all its controls and things such as Response, Request, Context etc will be set for garbage collection. Because you keep a reference to a UserControl instance in a static field, all these objects (including Page) will be kept in memory until this current reference is replaced with something else.
It is the fact that you used static in the function that was assinging current that this did not work. static is a method that is not tied to any instance of the class, therefor you can not use this.
Your only options are either make the method non-static or pass in a instance of the class as a parameter to the static function.
From what I can tell you are trying to create a "Singleton Pattern". See the link to the previous MSDN article for examples on how to create a singleton class.
This looks like it will have an instance. If the class is marked as static (which it doesn't appear to be) then you can just reference it by name "PDF_Library". Other wise, use ILSpy or reflector to look at the end result. I bet it has a constructor; just because you don't see one, doesn't mean it isn't there. Override the default ctor and set your instance there.
namespace PDF_Library.VisualWebPart1
{
public partial class PDF_Library : Usercontrol
{
public static PDF_Library Current;
public PDF_Library() : base() {
Current = this;
}
}
}
The problem you might be having with your Page_Load code is that it's being called too late in the lifecycle and that's why your reference call isn't working.
I have a number of UserControls that I want to each have some basic functionality. Below is my implementation :
public interface IMyTabInterface
{
void LoadData();
}
public partial class MyFirstTab : System.Web.UI.UserControl, IMyTabInterface
{
public void LoadData()
{
...
}
}
Then, in another page's code behind, I try :
protected void LoadFirstTab()
{
Control uControl1 = Page.LoadControl("/Controls/MyFirstTab.ascx");
Control uControl2 = Page.LoadControl("/Controls/MySecondTab.ascx");
// Want to do something like this, but don't get this far... :
var myFirstTab = (IMyTabInterface)uControl1;
var mySecondTab = (IMyTabInterface)uControl2;
myFirstTab.LoadData();
mySecondTab.LoadData();
Panel1.Controls.Add(myFirstTab);
Panel1.Controls.Add(mySecondTab);
}
I know much of this is not correct yet, but I am getting an error on the LoadControl() line :
'MyFirstTab' is not allowed here because it does not extend class 'System.Web.UI.UserControl'
even though the class clearly extends the UserControl class. Whats going on here? Is there a better way to do this?
This will work:
var myFirstTab = (IMyTabInterface)uControl1;
var mySecondTab = (IMyTabInterface)uControl2;
myFirstTab.LoadData();
mySecondTab.LoadData();
Panel1.Controls.Add((Control)myFirstTab);
Panel1.Controls.Add((Control)mySecondTab);
What is going on?
Your myFirstTab and mySecondTab variables are of type IMyTabInterface, since this is what you declared them as (this is what allows you to call LoadData on them).
However, in order to add an item to the controls collection, these need to be of type Control (or one that inherits from it) - this is achieved by the cast.
Another option:
var myFirstTab = (IMyTabInterface)uControl1;
var mySecondTab = (IMyTabInterface)uControl2;
myFirstTab.LoadData();
mySecondTab.LoadData();
Panel1.Controls.Add(uControl1);
Panel1.Controls.Add(uControl2);
Here you use the original Control types you started with, so no need to cast.