I am writing my very first asp.net application and am trying to use the PreviousPage property to access data between pages. Visual 2010 is giving me an error which I don't understand, so I need some help to understand what I am doing wrong.
I have an application where I will bounce between all the pages using Transfer. That way, from a user perspective there is only ever one url that he sees. This url will be the one that makes him log in to the application (a application controlled function for now) and connect to the database. I therefore have an sqlclient.sqlconnection object that I wish to hand off to the next page called _dbConnection this is a private variable in my page class declared ...
Partial Class Protocol
Inherits System.Web.UI.Page
Private _dbconnection As SqlClient.SqlConnection
Public ReadOnly Property dbConnection As SqlClient.SqlConnection
Get
Return _dbConnection
End Get
End Property
...
Later down the code, in reponse to a click event on a button
Server.Transfer("PSetup.aspx")
In PSetup.aspx I have the following
<%# Page Title="" Language="VB" MasterPageFile="~/MasterPage.master" AutoEventWireup="True" CodeFile="PSetup.aspx.vb" Inherits="PSetup" %>
<%# PreviousPageType VirtualPath="~/Protocol.aspx" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
Which should declare the Protocol class as the previous page
However in PSetup's Page_Load Sub I attempt this
_dbConnection = PreviousPage.dbConnection
where in this use _dbConnection is a private variable in the new page class.
Visual Studio is giving me an error 'dbConnection' is not a member of 'System.Web.UI.Page'
I have read through the documentation about this several times and I just don't understand what I am doing wrong. Could someone help me please.
I guess the first thing you need to understand is that ASP.NET is stateless. That means that no data is "saved" between pages. What the PreviousPage property does is it allows the request information persist through the use of a Transfer method, and the request information will be the GET or POST variables.
IMHO, the best way to do what you desire, is to have a shared public class that is not related to either page, and have a public function for getting the SqlConnection. Remember though, it is stateless, so you will have to create the connection each time.
Another alternative would be to save the dbConnection in the session (which I don't recommend, since it is possible to view the session information).
Otherwise, you can't have a variable persist with information between pages. Thats what is means to be stateless.
ALSO, for PreviousPage, keep in mind that it is creating an instance of System.Web.UI.Page, not an instance of Protocol. That means public properties won't exist from Protocol, only native features of Page will be there.
edit
From msdn
Note
Properties on the source page that are created primarily to expose values for cross-page posting are usually read-only properties. Although the source page can contain public read/write properties, setting a source page property from the target page property generally has no purpose, because the value will not be persisted.
try to make the dbConnection variable as Shared
Partial Class Protocol
Inherits System.Web.UI.Page
Private Shared _dbconnection As SqlClient.SqlConnection
Public Shared ReadOnly Property dbConnection As SqlClient.SqlConnection
Get
Return _dbConnection
End Get
End Property
But I'm not sure if it is a good practice passing data between pages that way
Related
For my webpages, I decided to create a reusable, external (that is, the code is a separate class outside of the page's own classes), class to deal with managing cookies in a certain fashion.
So in my class constructor, I did something like this:
private property cookiepageas Page
Public Sub New(whatpage as Page)
cookiepage= whatpage
End Sub
This allows me to pass the page context to my external class.
This way, I can get intellisense to allow me to do this:
private property cookie as httpcookie
cookie = cookiepage.Request.Cookies.Get(cookiename) 'get the current cookie
That compiles. The problem is that when I run it in the browser, I get this error:
Request is not available in this context
How, then, can I request the cookie from my external class?
(you can post vb or c# - I like both)
Ah, instead of passing the Page, I did this:
cookie = HttpContext.Current.Request.Cookies.Get(cookiename)
Got an asp.net 3.5 app - compiles fine, but when browse to page I get the error below.
Searches for this all seem to indicate it is a namespace problem, but all of my pages seem to declare the proper namespace.
Any assistance appreciated!
Phil J.
Server Error in '/Internet/bm2/bm2' Application.
Parser Error
Description: An error occurred during the parsing of a resource required to service this request. Please review the following specific parse error details and modify your source file appropriately.
Parser Error Message: 'bm2.PolicyLookup' is not allowed here because it does not extend class 'System.Web.UI.Page'.
Source Error:
Line 1: <%# Page Language="vb" AutoEventWireup="false" CodeBehind="PolicyLookup.aspx.vb" Inherits="bm2.PolicyLookup" validateRequest="false" aspcompat="true"%>
Line 2:
Line 3:
Source File: /internet/bm2/bm2/policylookup.aspx Line: 1
=======
The System.Web.UI.Page is indeed inherited from in the code-behind:
Namespace bm2
Public Class PolicyLookup
Inherits System.Web.UI.Page
Protected WithEvents lblResponse As Label
Protected WithEvents btnSubmit As System.Web.UI.WebControls.Button
Dim myModel As New bm2.Model
Dim postData
Public objMessage
If this is a namespace problem (very unlikely), you'll either need to add an #import statement to your page:
<%# Import namespace=”My.Namespace.Where.bm2.PolicyLookup.Exists” %>
or modify your #Page directive to include the fully-qualified class name
....inherits="My.Namespace.bm2.PolicyLookup"
Of course, this only works if bm2.PolicyLookup descends from System.Web.UI.Page.
The #Page attribute
inherits="bm2.PolicyLookup"
tells ASP.NET that the class bm2.PolicyLookup inherits from System.Web.UI.Page, and that it should be instantiated when processing the page to handle on_load(), render(), etc events. However, ASP.NET believes that your class bm2.PolicyLookup does not inherit from System.Web.UI.Page, thus the error.
In order for the webforms engine to be able to process your page, it has to descend from the existing Page class. That class provides all of the event handlers, rendering methods etc. that are required.
Also, a bit of unrelated advice: Visual Studio hides a lot of functionality when working with a VB.Net site. Consider moving to C#, and to a web application project instead of a website project.
I don't know if there is a PolicyLookup class in System.Web (I don't think there is), but I ran into a similar problem when I tried to name a page SiteMap.aspx, since there was a type named SiteMap (though it was in a different namespace, it still seemed to cause a problem). The fix was to either rename completely, or have the code behind class name be prefixed with an underscore (you may have to update the Page directive in your aspx to match the new type name.
Here's my control's code behind:
<PartialCaching(60, Nothing, "UsrCtl_WebUserControl.CacheString", Nothing, True)> _
Partial Class UsrCtl_WebUserControl
Inherits System.Web.UI.UserControl
Private _CacheString As String
Public Property CacheString() As String
Get
Return _CacheString
End Get
Set(ByVal value As String)
_CacheString = value
End Set
End Property
End Class
Here's the Control's Markup:
<%# Control Language="VB" AutoEventWireup="false" CodeFile="WebUserControl.ascx.vb" Inherits="UsrCtl_WebUserControl" %>
<span>Control Generated <%=DateTime.Now%></span>
It just outputs the current time.
Here's the user control embedded in a page:
<uc:wuc ID="wuc" runat="server" CacheString="A" />
And in another page:
<uc:wuc ID="wuc" runat="server" CacheString="B" />
According to the docs this control should maintain a different, 60 second cached version for each value of the CacheString property.
It doesn't work - it caches for 60 seconds, but only one cached copy is created regardless of what I put in the CacheString property.
Anyone any ideas what i'm doing wrong? - After 4 hours of this I have no hair or nails left - please save my monitor from the brick.
OK it's taken me a little while but I just replicated your problem. The problem crops up when the two controls have the same ID across multiple pages and in the constructor for the PartialCaching attribute, you set Shared to True. According to the documentation here the Shared property in the constructor is 'true to indicate that the user control output can be shared with multiple pages', which means, as you've seen, the first control to get loaded sets it and subsequent controls can only read what's already there. Under the covers it seems the control gets cached based on the ID of the control only without any regard to the page the control is on.
So, there are two potential solutions:
Change the ID of the control on the
page
In the PartialCaching constructor,
set Shared to false.
It seems that CompilationMode=Never doesn't permit Sessions to be properly wired.
It first complains that the EnbaleSessionState directive is not allowed on this page.
Explicitly assigning the System.Web.SessionState.IRequiresSessionState to the Page [1] avoids the null reference exceptions (around .Session access) but still doesn't persist or wire-up sessions correctly.
Has anyone successfully used ASP.NET Sessions with CompilationMode=Never?
Conceptually, why should these be disjoint??
[1] -
http://msdn.microsoft.com/en-us/library/system.web.ui.compilationmode.aspx
I don't know the exact situation you are in but what you say is correct - Page + IRequiresSessionState = Session Available. Here is what you do. First define a base class for your pages which will receive session state:
public class BasePage : Page, IRequiresSessionState
{
}
Then in your NoCompile Page you do the following declaration:
<%# Page Language="C#" CompilationMode="Never" Inherits="BasePage" %>
Works as expected. Session state is available. Now little more about your second question: "Conceptually, why should these be disjoint??". By default the Page
public class Page : TemplateControl, IHttpHandler
{
}
class doesn't implement IRequiresSessionState and thus have no session state. What ASP.NET does for you is compiling a class for you at runtime through which it provides the session - i.e. if I define a page called Default.aspx, with code behind class that implements Page, nowhere I explicitly implement IRequiresSessionState. But ASP.NET compiles ours Default.aspx UI into a class called:
public class default_aspx : Default, IRequiresSessionState, IHttpHandler
{
}
which now explicitly says that it wants session state to be delivered. This is because "EnbaleSessionState" in the #Page directive is by default set to True. Now when you say that default.aspx is a non compile unit by specifying CompilationMode="Never", then this class is never generated and you never get the Session State, which makes the use of "EnbaleSessionState" not meaningful and thus disabled.
If I have a inline user control page, are public properties... properties on the control?
<%# Control language=C# %>
<script runat=server>
public string Title {get;set;}
</script>
ie. if someone loads the control by tag or programatically, they will see those public properties?
Yes.
However, if your user control is cached (with the #OutputCache directive), they won't, as ASP.NET will treat your control as a PartialCachingControl (even casting to UserControl won't work here). If you want to parameterize your user control, don't cache it. (But cache the page entirely for instance.)
Also note that if you're using LoadControl, you'll first need to cast the instance you receive to the proper user control type, otherwise the only way to use the properties is by using a) reflection, or b) late binding (VB.NET can do that for you IIRC).