I am a VB.net winforms programmer attempting to build an ASP.Net app. I use data classes(objects) through reflection in most of my vb projects and was trying to adapt it to ASP.net using the VB code behind. I have a webpage that serves as an add/edit page for contact info. I instatiate my class which grabs the contact data from the data base then I have a process that loops through the controls on the form and matches up with a property in the data class. I can display data no problem. When I edit data and click the submit button my code calls a then loops through the controls on the form again and matches the control to the property of the data class to update the property of the class. However, my data class is no longer valid. I know web programming is different then winforms but I can't seem to get over the hump on this one. Is this the wrong way to go about this? Is my data class only available on the server side? Do I just reinstantiate the initial class and then loop through the propeties and change what the user changed and then call the update method (see redundant)? How can I get data class into a session object (I made an attempt in the past but was under tight deadlines and had to abandon it, maybe I need to revisit it?)?
Thanks
If you decide to keep some of your data in Session, you owe it to yourself to look at this post. Your code will be much cleaner and easier to maintain.
Yes, you need to reload the data class from the database as one option, or use an alternative approach. The reason is web is stateless, so all local variables are destroyed then the server side page unload process occurs. This means that in between requests, you need something to store your data.
You can read/write an object via the Session colleciton, as so:
Session["A"] = myobj;
myobj = (ObjType)Session["A"];
And so session stores an object for a specific user. Alternatively, cache stores application level data, so one instance of an object is available to all users (where session is unique to each user). You can make cache unique to a user by appending a user ID to the cache string.
var o = Cache.Get("A");
if (o != null) { .. }
Cache.Add("A", o, ...);
And so these mechanisms help you temporarily retain data.
You need to save your data class somewhere, usually in a session variable, otherwise it goes away as soon as the page gets sent back the user. Or else you need to recreate the data class again upon posting.
Related
I am totally new to classes and OOP, so please bear with me.
I am creating a large scale web app which I'm trying to keep tidy by creating my own classes.
For instance I have a Public Class Product which has several properties. One way I am using it is on page load a product ID is assigned to the ID property which in turn gets the details for that product and assigns the various data to the other properties. So within my code I can used for example product.price or product.description and get the appropriate values. This has worked fine, but I found that because the class was initiated on page load it was getting the data from the DB each time that the page refreshed. I stopped this by using an If Not IsPostback to initiate the class. This meant that the data was pulled in only on the initial page load. So far so good.
I then needed to compare a value in a textbox with a property of the product. I have a textchanged event with
If textbox1.Text <> product.description Then....
but here I get a wavy line under product.description and VS2010 is saying that the object is not defined. Its Dim'd in the page.load so I moved the Dim statement outside the page class so that it will be accessible to all events on the page.
The dim statement is Dim product as New product
In my not ispostback chunk of code I have for example product.ID = 1 which will get all the product properties for product 1
The wavy line has gone but when I run the page all works fine on page load. Data is displayed so my product class is working fine. As soon as I make a change in textbox1 and the event triggers product.description is nothing. It got reinitalised.
How do I stop this from happening...
Your "Product" is not persisted between postbacks.
Only control objects in aspx page are persisted/restored automatically.
To remedy this there are multiple approaches.
If Product is loaded via setting "Product.id=1" then what I woudl do is have a hiddenfield that receives the value of the product.id during prerender event (to save it in the page) and in an init event I would restore the "Product.id=hiddenfield.value" but only when it is a postback to reload your object.
EDIT
Thanks for picking my answer. I'll elaborate a little on the various ways to deal with this and why I suggested my answer.
Store Key in HiddenField Reload from DB:
PROS: Product is always Fresh/Correct/Current values. Corresponding to the database. Databases are very efficient to return a record based on a primary key. Very little data is sent to and posted back from the client browser. Low complexity. Each page opened by the client is safely isolated.
CONS: Multiple database transactions. If the DB is already strained or extremely massive you may need to consider even the smallest efficiency gain, but this is not common or likely on a primary key based record
Session State (store entire object):
PROS: Lowest time to "load" object since it's available in memory already once loaded. Less DB Transactions. No data piggy backed to the client and back again.
CONS: Object can become "out-of-date" if altered in the DB. Users who open multiple pages of your application can end up getting the wrong object if both require a different "Product", so instead to be totally safe you need a more complex structure in place to store more then one product or store them based on some kind of key (such as the product ID). Server Memory is used, if serving thousands of users or your product data is large it can become an issue, especially if you do this in many pages with many objects.
Serialization (store the entire object in the page in a field, similar to event state):
PROS: Once loaded, the Database is accessed only once for a specific product, then the product is held, in it's entirety inside the page, it is recreated by the server from the data in the field or via viewstate. Each page opened by the client is safely isolated. Is fairly easy to implement storing in ViewState of the Page.
CONS: Object can become "out-of-date" if altered in the DB. ALLOT more data is added to your page responce and the users next page request. Is more complex to implement because the object needs to be designed to be serialized correctly. Complex objects require allot of manual code to be serialized successfully.
again, there are many other ways to deal with this, such as storing items in a synclocked dictionary style object global to the application, but is considerablby more and more complex as you go.
This is likely the standard ASP.NET page life cycle problem.
After you initialize the page, it gets sent to the user's browser. When the user clicks on something, the browser sends a postback request back to your application. The view state allows the textbox1 object to remember what was in its Text property. However, your Page_Load ran from scratch, and, yes, everything including your product object got recreated from scratch.
If you want your product object to "remember" what it knew before the postback, you'll have to remind it. One way would be to store the initialized value in Session state, and then refresh your product object during the postback section of the Page_Load method.
Every time you do a postback, you're working with a new instance of your page class. The prior copy of your class was thrown away and probably disposed before your browser even rendered the page to the screen.
If you want to persist a value across http requests (of which postbacks are just one type), then you need to put it somewhere like the Session.
I need to pass a Infragistics ultrawebtree from a page to another. I used Session("data") for this and then I just access it from another page. But when I assign the session value after casting to a Infragistics ultrawebtree control in my second page, it doesnot build the tree structure and it is invisibile. Is I am wroung in this approach, is there any other way to pass the entire tree structure from one page and display it into another page. Any help is appreciated
If anything, I would store the datasource in session instead of the tree. Storing the entire control in session creates a lot of unnecessary overhead, and limits your options per implementation on the next page.
EDIT: You should be able to export the tree structure to XML format, and store the XML in session. According to the documentation there should be WriteXmlDoc() and WriteXmlString() functions available. There's also ReadXmlDoc() and ReadXmlString() functions you can use to repopulate the tree on the next page.
Here's the documentation for the UltraWebTree. You'll see these methods under the Public Methods section:
Only the data should be stored in session. Storing controls in session is likely to cause issues because the control will be disposed during page unload and controls shouldn't be accessed after being disposed which is what would happen when accessing the control from session. See Why Controls Shouldn't be Stored in Session for more details.
Say I have a page in my web application that lets a user update their contact information. Pretend in order to retrieve or save this information I have the following class:
public class User
{
DataAccesClass dataAccesClass = new DataAccesClass()
public string UserName {get;set;}
public string Address {get;set;}
public string EmailAddress {get;set;}
public User(){}
public static User GetUser(int userID)
{
User user = dataAccesClass.GetUser(userID); //
return user;
}
public void Save()
{
dataAccesClass.SaveUser(this);
}
}
Say that on my Page_Load event I create a new instance of my User class (wrapped in a !isPostBack). I then use it's public properties to populate text fields on said page in my web application. Now the question is... When the page is posted back, what is the correct way to rebuild this class to then save the updated information? Because the class was created on Page_Load !isPostBack event it is not available. What is the correct way to handle this? Should I store it in a Session? ViewState? Should I simply rebuild it every post back? The User class in this example is small so that might influence the correct way to do it but I'd like to be able to take the same approach for much larger and more complex classes. Also, would this class be considered an acceptable business object?
what is the correct way to rebuild this class to then save the updated information?
I would say the best practice would be do not rebuild the class on every postback. You should build the data on the first request, set values on controls, then let the viewstate on those controls persist the data.
If there is a potential for the data to need to be updated, tie re-generation of the object to an event indicating there is actual need to update.
Should I store it in a Session? ViewState? Should I simply rebuild it every post back?
Selecting whether to store the value in session or re-pull from the data layer should be based on the memory footprint of the object, the scalability requirements of the application, the costliness of the database operation, and the likelihood that the object will need to be accessed on any particular request. So I believe that is highly situational.
Also, would this class be considered an acceptable business object?
I don't have a lot of experience with BLL's but it looks like you're on the right track.
Unless profiling indicates otherwise, it's okay to just reconstruct the object with every request. You can also implement some kind of caching in your data access code. Your class is an acceptable business object.
Given that User object might have info you wouldn't want to expose through ViewState, it can be stored in Session.
This is the "standard" way of doing this in ASP.NET.
In the case of your example, reconstructing the object looks fine as it is small. But if you have a small object you inevitably store for a while, I would use session. If the object is large, I would directly use database or session with database connection.
Depending how complex you are thinking of getting a JavaScript framework called knockout.js might be a good fit. You could create a json object to bind to a jQuery template that would build the HTML depending on the object, it handles complex objects very well.
I have an ASP.NET c# project.
I have to pass a list of values (id numbers such as "23,4455,21,2,765,...) from one form to another. Since QueryString is not possible because the list could be long, which is the best way to do it?
Thanks in advance.
Thanks for all your answers, you are helping a lot !!!
I decided to do this:
On the first form:
List lRecipients = new List();
.....
Session["Recipients"] = lRecipients;
On the final form:
List lRecipients = (List)Session["Recipients"];
Session.Remove("Recipients");
You could use Session collection.
In the first page, use:
List<int> listOfInts = new List<int>();
...
Session["someKey"] = listOfInts
And in the second page, retrieve it like this:
List<int> listOfInts = Session["someKey"] as List<int>;
If your using asp.net webforms you can put it into a session variable to pass stuff from page to page. You've got to be concise of the potential performance issues of putting lots of stuff into session mind.
Session["ListOfStff"] = "15,25,44.etc";
There are any number of ways to pass this data. Which you choose will depend on your environment.
Session state is useful, but is constrained by the number of concurrent users on the system and the amount of available memory on the server. Consider this when deciding whether or not to use Session state. If you do choose session state for this operation, be sure to remove the data when you're done processing the request.
You could use a hidden input field, with runat="server" applied to it. This will make its data available server-side, and it will only last for the duration of the request. The pros of this technique are that it's accessible to both the server code and the client-side JavaScript. However, it also means that the size of your request is increased, and it may take more work to get the data where you want it (and back out).
Depending on how much data's involved, you could implement a web service to serialize the data to a temporary storage medium (say, a database table), and get back a "request handle." Then, you could pass the request handle on the query string to the next form and it could use the "handle" to fetch the data from your medium.
There are all kinds of different ways to deal with this scenario, but the best choice will depend on your environment, time to develop, and costs.
For Asp.NET MVC you can use ViewData.
ViewData["ID"] = "";
Just trying to gather thoughts on what works/doesn't work for manipulating Business/Domain objects through an ASP.NET (2.0+) UI/Presentation layer. Specifically in classic ASP.NET LOB application situations where the ASP.NET code talks directly to the business layer. I come across this type of design quite often and wondering what is the ideal solution (i.e. implementing a specific pattern) and what is the best pragmatic solution that won't require a complete rewrite where no "pattern" is implemented.
Here is a sample scenario.
A single ASP.NET page that is the "Edit/New" page for a particular Business/Domain object, let's use "Person" as an example. We want to edit Name and Address information from within this page. As the user is making edits or entering data, there are some situations where the form should postback to refresh itself. For example, when editing their Address, they select a "Country". After which a State/Region dropdown becomes enabled and refreshed with relevant information for the selected country. This is essentially business logic (restricting available selections based on some dependent field) and this logic is handled by the business layer (remember this is just one example, there are lots of business situations where the logic is more complex during the post back - for example insurance industry when selecting certain things dictates what other data is needed/required).
Ideally this logic is stored only in the Business/Domain object (i.e. not having the logic duplicated in the ASP.NET code). To accomplish this, I believe the Business/Domain object would need to be reinitialized and have it's state set based on current UI values on each postback.
For example:
private Person person = null;
protected void Page_Load()
{
person = PersonRepository.Load(Request.QueryString["id"]);
if (Page.IsPostBack)
SetPersonStateFromUI(person);
else
SetUIStateFromPerson(person);
}
protected void CountryDropDownList_OnChange()
{
this.StateRegionDropDownList.Enabled = true;
this.StateRegionDropDownList.Items.Clear();
this.StateRegionDropDownList.DataSource = person.AvailableStateRegions;
this.StateRegionDropDownList.DataBind();
}
Other options I have seen are storing the Business object in SessionState rather than loading it from the repository (aka database) each time the page loads back up.
Thoughts?
I'd put your example in my 'UI Enhancement' bucket rather than BL, verifying that the entries are correct is BL but easing data entry is UI in my opinion.
For very simple things I wouldn't bother with a regular post back but would use an ajax approach. For example if I need to get a list of Cities, I might have a Page Method (Or web service) that given a state gives me a list of cities.
If your options depends on a wide variety of parameters, what your doing would work well. As for storing things in Session there are benefits. Are your entities visible to multiple at the same time? If so what happens when User A and User B both edit the same. Also if your loading each time are you savign to the database each time? What happens if I am editing my name, and then select country, but now my browser crashes. Did you update the name in the DB?
This is the line I disagree with slightly:
this.StateRegionDropDownList.DataSource = person.AvailableStateRegions;
Person is a business/domain object, but it's not the object that should be handling state/region mapping (for example), even if that's where the information to make the decision lives.
In more complicated examples where multiple variables are needed to make a decision, what you want to do in general is start from the domain object you're trying to end up with, and call a function on that object that can be given all the required information to make a business decision.
So maybe (using a static function on the State class):
this.StateRegionDropDownList.DataSource = State.GetAvailableStateRegions(person, ipAddress);
As a consequence of separating out UI helper concerns from the Person domain object, this style of programming tends to be much "more testable".