I have a question regarding the scope of a class that I created in relation to a web application.
My class is CCourseInfo and I create it as a private member of one of my web pages Enrollment.
In the Page_Load method, there is a database call to load the table data in the class member, DataTable. This DataTable is bound to a gridview.
This is the code:
public partial class Enrollment : System.Web.UI.Page
{
private Course CCourseInfo = new Course("Courses");
protected void Page_Load(object sender, EventArgs e)
{
try
{
if (!IsPostBack)
{
//Get the Environment Setting to determine the database to access
txtBoxEnvironment.Text = CurrentEnvironment;
DAL.setCurrentEnvironment(CurrentEnvironment);
//Get Course information from database
CCourseInfo.getData();
CourseGridView.DataSource = CCourseInfo.TableInfo;
CourseGridView.DataBind();
}
}
}
I want to implement Paging.
This method works but I have to get the data again to populate the DataTable in the CCourseInfo class.
protected void CourseGridView_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
CourseGridView.PageIndex = e.NewPageIndex;
CCourseInfo.getData();
CourseGridView.DataSource = CCourseInfo.TableInfo;
CourseGridView.DataBind();
}
My question is: Why do I have to get the data again? I set the DataTable in the Page_Load method and declared the class under the Enrollment class. Shouldn't the data still exists in the DataTable? How can I change my design so that I only have to get the data once?
Thanks,
You have to get the data again because ASP.NET (and in general, web pages) are stateless objects - this means that after each execution of your page, the page is cleaned up and all of its state is deleted. You'll have to recreate all of it when a new request comes in for the same page - the same page class will be instantiated again and you'll go through the page life cycle once more from beginning to end.
If you're not familiar with the page life cycle, here's an SO question / answers with quite a bit of detail - this will help you understand better what's going on during a request.
There are some things you can try (not an exhaustive list):
Cache all your records from the database in a cache server or in session state. If you have a lot of records, this could use a lot of memory (for each user) since all pages are loaded at once - you don't hit your database every time to query data. Caching speeds things up quite a bit but you may showing outdated data to the user - another user may change the data. It's also fairly tricky to properly handle cached data (when to remove it, when to fetch a fresh copy, etc.)
You can query only records for a single page - this results in lower data traffic between the web server and the database. You also have to query data every time the page changes, since you don't have more than the current page.
You can query all data and then send it to the client side and perform all paging in the browser. This generates a lot of traffic, since you have to send all pages to the client, whether the user wants to look at them or not. Paging is much faster this way but the browser uses a lot of memory and getting the data to the client can take a long time, depending on network speed.
The best solution is to get as little data as you can get away with (one page for the grid) - if you have to re-query it, the database will send you as little as needed.
Ok first because Web is using HTTP which is a stateless protocol so that's why you loose a web page's state.
So you have to manage the state your self. there are many ways that you can use to manage state.
Here is how i solved this problem i saved the data that i received from database and stored the entire list in View-state. And every time there is a post-back i retrieve the data from view-state.
if (!Page.IsPostBack)
{
ViewState["data"] = MyDataset;
DataListView.DataSource = ViewState["data"];
DataListView.DataBind();
}
if (Page.IsPostBack)
{
DataListView.DataSource = ViewState["data"];
DataListView.DataBind();
}
you can also use Session state and a few other state management techniques.
Related
I am trying to move the content of a textbox on the from StudentRegistration to the form MyProfile by following a tutorial on YouTube. However when I try to reference the StudentRegitration Page in my code, I get the error that the type or namespace cannot be found.
In the tutorial I can see that in their code they have a namespace, however my website does not. Could anyone tell me what to do in order to be able to reference StudentRegistration without getting an error?
I should have stated that I have a website not a web app. I have found that websites do not have a default namespace. How would I go about accessing the StudentRegistration without referencing a namespace?
public partial class MyProfile : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (PreviousPage != null)
{
StudentRegistration LastPage = (StudentRegistration)Context.Handler;
lblEmail.Text = StudentRegistration.STextBoxEm;
}
}
}
Rather than answer your question directly, I'd like to point out another issue with your code that will probably prevent it from working. You should refer to the documentation on the PreviousPage property at: http://msdn.microsoft.com/en-us/library/system.web.ui.page.previouspage%28v=vs.110%29.aspx
It does NOT work like this:
user visits /StudentRegistration.aspx
user does stuff
user submits the form on /StudentRegistration.aspx
server redirects the user to /MyProfile.aspx
MyProfile class knows that PreviousPage = the class from /StudentRegistration.aspx
Instead, the description from the msdn reference page linked above stipulates that the PreviousPage property only works on this scenario:
user visits /StudentRegistration.aspx
user does some stuff
user submits form on /StudentRegistration.aspx
server transfers request to the MyProfile class
this does not mean that the url has changed to /MyProfile.aspx for the user, this means that the server is going to treat the current request to /StudentRegistration.aspx as if it were actually a request to /MyProfile.aspx
the user ends up seeing the result of what would normally be /MyProfile.aspx on /StudentRegistration.aspx
Now, your code may actually want that, but the fact that you have:
if (PreviousPage != null)
{
StudentRegistration LastPage = (StudentRegistration)Context.Handler;
// this should be
// StudentRegistration LastPage = (StudentRegistration)PreviousPage;
}
makes me think that you have misinterpreted the somewhat misleadingly named PreviousPage property. For a sample of how to persist state across multiple page loads in .NET, I would recommend reading up on SessionState. It has a somewhat complicated name, but does more of what you would want in this scenario:
http://msdn.microsoft.com/en-us/library/ms178581%28v=vs.100%29.aspx
An added bonus is that you do not need to reference one class from another, so you fix your current bug later on. Additionally, even if you did resolve your potential namespace error, the issue that I outlined earlier will cause the value of the text field to be blank if your code is working as I suspect.
You are sending data from a source to a target - e.g. StudentRegistration -> MyProfile
You have options because at the end of the day, it is HTTP. Aside from "persistence" (Session), and the tutorial you are following, a "simpler" way is to use ButtonPostBackUrl.
All it means is that you are POSTing data to the target page. The target page (MyProfile) will have to validate and parse the posted data (Request.Form). This way you don't have to manage things like Session state.
I have one url (/settings) that needs to point to two different pages depending on the users security on login. One page is the existing webforms page the other is a new MVC page. Is this even possible?
Additional Info:
When the user is on either page the url needs to say website.com/settings
Solution:
Convinced the PM to change the requirements.
The short answer, yes. You can do this several ways.
Javascript
Model View Controller (Controller)
ASP.NET Web-Forms (Method)
It is often poor practice to do such an event, as it can expose data. It is indeed possible:
Javascript:
$(document).ready(function () {
if($("#Account").val() != '') {
$(".Url").attr('href', 'http://www.google.com');
}
});
Pretend #Account is a hidden field that is populated from your database. If the field is not null then modify the .Url element to navigate to link. That approach for Web-Forms is the most simple.
Web-Forms:
protected void btnAccount_Click(object sender, EventArgs e)
{
if(User.IsInRole("Account"))
Response.Redirect("~/Admin.aspx");
else
Response.Redirect("~/User.aspx");
}
That would use the default Windows Authentication for the domain, you could bend and contort to use the database to pull data. An example, the Model View Controller would be similar as the Controller will simply handle that capability.
Hope this points in right direction.
This is a redirects based approach. Create a web page mapped to /settings, and have this code run on page load.
if(User.IsAdministrator()) //I take it you have some way of determining who is an Admin, so this is just example code
{
Response.Redirect("~/AdminSettings.aspx");
}
else
{
Response.Redirect("~/UserSettings.aspx");
}
Note that you'll need security on the Admin page to make sure a regular user can't just navigate directly there.
Is there a way to check if page/frame in Windows 8 application exists in cache? Let's assume I have two pages: Home and Clients (navigation cache enabled). When I navigate to clients from home (by button) clients are loaded from database in OnNavigatedTo method. I navigate back to Home by Back button and than again to Clients. Now I see that clients are loaded from cache, which is good, but than again from OnNavigatedTo method. I'd like to load clients from database only once, when I open page for the first time. Later just load clients from cache.
How can I check than if clients were previously loaded or load them only on first page load? Maybe some other method?
Thank you!
Here's a solution to it ...
Sinche no one wants to load from cache in metro app so it's always better to reset the cache size for the respective frame. For pages where you want it to load from the cache. Just keep an if loop. and also check for the forwardStack in the History object.
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
base.OnNavigatingFrom(e);
if (e.NavigationMode == NavigationMode.Back)
{
ResetPageCache();
}
}
private void ResetPageCache()
{
var cacheSize = ((Frame) Parent).CacheSize;
((Frame) Parent).CacheSize = 0;
((Frame) Parent).CacheSize = cacheSize;
}
Here's a blog. Ill recommend you go through this first :)
BLOG
EDIT---------------------
Here are two links. Since i never faced the situation of loading the file from previous cache so I can share some findings :)
Here's the accesscache class
Access cache
and here's for winJS
winJS cache
the access cache might meet your requirement if you set caching to true for the pages you want :)
Ok, I solved my problem. Important is to have NavigationCacheMode enabled. In OnNavigatedTo method I just check whether list which to I saved data from database contains any elements. At first page opening it is empty so I load data from database to my list. Thus enabling NavigationCacheMode, data in variables are stored in cache, and loaded while navigating to this page. Some flags may be required.
I am currently using session to hold the user ID at my web application. And i read a lot about sessions is evil, so my plans is to find another solution.
So my next step is to use encrypted cookie.
Something like:
userInformation: ENCRYPT(UserID,subdomain,someComputerUniqueValue,hashvalueOftheString)
each user has their own subdomain, so the UserID and Subdomain must match.
But. Now at almost every page i call the session value to get the userID.
I want to change this to some kind of variable, but what kind of variable?!
I am now setting the session value inside a httpmodule. in the
public void Application_PreBeginRequest
Is it possible to create a variable within application_prebeginRequest and read it somewhere else during the creation of the page. for example in the masterpage, och the contentpage. or the classes that is used at that specific page.
WHen the page is created and sent to the client, the variable should die.
What kind of variable am i looking for? is it global variable? if not, what is global variable?
Thanks for reading!
Mattias R.
Edit:
This cookie is not for authentication. I want to save the ID of the user connected to the subdomain, so i dont have to run the "SELECT ID from account where subdomain='somethin'" query each time a page is visited.
You can store what you need inside the HttpContext.Current.Items. Items put inside that will live only during the current web request and will be available globally in your web application.
// Global.asax
void Application_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.Items["hello"] = DateTime.Now;
}
// Default.aspx
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Label1.Text = HttpContext.Current.Items["hello"].ToString();
}
}
By the way, at Application_BeginRequest event, the Session object isn't available.
For more information about HttpContext.Current.Items, look at https://web.archive.org/web/20201202215202/https://www.4guysfromrolla.com/articles/060904-1.aspx.
Once the user is authenticated, why don't you log them in with FormsAuthentication.SetAuthCookie?
You can then retrieve the currently logged in user using HttpContext.Current.User.Identity.Name.
Session is not "evil" Session is stored on the server, and for small amounts of data such as what you suggest, it scales very well.
I've got a client that, during testing, is giving me conflicting information. I don't think they are lying but more confused. So, I would like to setup some simple auditing in my ASP.Net application. Specifically, right when any page is called, I want to immediately insert the Querystring and/or form POST data into a log table. Just the raw values.
Querystring is easy. But there doesn't seem to be a way to get the raw form POST'ed data without using BinaryRead, and if I do that, then I screw myself out of using the Request.Form collection later on.
Does anyone know a way around this?
EDIT: tvanfosson suggested Request.Params. I was looking for something that was easier to use (like Request.Querystring, only for POST), but I guess I could just as easily loop through all params and build a string of name=value&, etc).
You can create a custom HttpModule to capture all request made to your application so you don't need to touch every page and you can use it only during testing just not to slow down performance in production.
A sample implementation would be:
public class CustomModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.EndRequest += new EventHandler(context_BeginRequest);
}
private void context_BeginRequest(object sender, EventArgs e)
{
HttpContext context = ((HttpApplication)sender).Context;
// you can use the context.Request here to send it to the database or a log file
}
}
You need to add the module to your web.config
<httpModules>
<add name="CustomModule" type="CustomModule"/>
</httpModules>
All of the form data should be in Request.Params. You'd need to do this on every page, though or maybe use an HttpModule.
[EDIT] If you want to get the form parameters separately use Request.Form, along with Request.QueryString
I would recommend implementing and HttpHandler or an HttpModule for this type of scenario. You can get to the POST Data from the Page_Load event but implementing this logging facility here is not as maintainable.