Fetch data via ajax+webmethod or via traditional codebehind? - asp.net

I'm going to display a product detail from a database. But I can't decide whether to use an $.ajax post to a WebMethod that returns a JSON string, or a traditional Page.Load with sqldatareader in codebehind.
I know how to do both, coding is not the issue. I'm wondering what would be faster and more secure?

It depends on what kind of data you are showing on the page. (more of howmuch data)
Lets say if you are showing a fixed amount of data like, summary, product detail then its better to fetch data from server side and bind in label in Page Load event.
But if you are about to display the list of item (which may vary depending on the user input) for example product list, order list, employee list. in that case it is good to fetch the rows using ajax. reason is to display the fixed number of rows on the page (lets say 10) and there should be a pagination to jump to the next/pre page. now when user click next or previous it should not post back the page and should get the rows using ajax.

Each method has its advantages and disadvantages.
AJAX advantages and disadvantages
Advantages:
Forces you to separate the concerns in the code a bit more, you will have the data gathering and the data display in different places
The code will be more testable due to this additional modularity
Disadvantages:
Slower due to the additional HTTP request
Harder to deal with the back button and with bookmarking
Search engine optimization will be harder due to data not being right in the html

Related

gridview sorting: need to re-read every time?

I'm populating a GridView with code, setting datasource to the dataset returned by a query. So apparently sorting and paging don't just work magically like if I use a datasourceid= some sqldatasource.
I've found a number of examples of how to do this on the web, but they all appear to re-execute the query every time. Shouldn't the contents of the query be saved in the view state? Is there some way to just get the previous query results and re-sort without having to go back to the database? (Is it saving all the data in the view state? If so, why can't I get to it? It seems pretty dumb to send it all to the user's browser and send it all back, wasting all the bandwidth, if there's no way to get to it.)
Also, if I try to allow paging, it appears I again have to re-execute the query every time the user goes to another page. And if the user sorts and then pages, then I have to remember what the sort order was in a hidden field or some such, so I can re-read the data, re-sort, and then go to the right page.
Given that when you use a data source control all this behavior is built in, I think I'm missing something here. But given all the examples out there that do it this slow, hard way, if I'm missing something, a lot of other programmers are missing it, too.
If you're using an ASP.NET GridView control every time you sort a column or page through the data set then you're making a server postback. Sorting and paging with this particular control has never worked 'magically' and has long been a bugbear of mine.
You can speed things up by storing the data source that you're building the grid from in memory, either as a session or through the ViewState. Both have pros and cons and I suggest you read up.
If at all possible I suggest forgetting the ASP.NET GridView and looking at a client side solution such as the jQuery jqGrid. It uses AJAX calls to sort and page and is much, much faster and less of a headache. The only drawback is the learning curve but believe me it's worth it in the long run.
Yes the gridview re-execute the query every time.
If the query takes too long, you can manually store data in the session, or ViewState. And in the Algorithm that populates the grid just read them directly for it, instead of running the query.
you can, in the page load event, run the query one time when there is no postback (you can check for postback with
if (!Page.IsPostBack){
//Run the query and save it to the session
}
and the the method that populate the grid, should read from the session directly. no need to run the query again

Client side pagination on ASP.NET GridView

I have a client who wants to return an ENORMOUS query from a web service, and will not budge. They are adamant that the query must be able to return absolutely everything, and they also will not allow us to do any sort of server side paging.
We have it working so that it returns all the data just fine, and we have it displayed in an ASP.NET GridView. In order to speed up the rendering of the huge grid, we decided to implement client-side paging, but I'm not exactly sure how to go about this.
Currently, we store the whole of the data in the ViewState, and then page and sort based off of that so as to avoid hitting the server again.
However, with the default set up, when trying to select any page but the first, it returns a 404 error. I'm guessing this is because it times out while trying to send the enormous data set via the ViewState.
Is there any sort of way to return the data set, and then do all of the paging and sorting all on the client without having to do any sort of post back? Or is there some other way to do this that we haven't thought of? (besides server side paging. We would LOVE to do it this way because it is so obviously the right way, but the client won't budge...)
EDIT: I would like to stick to the ASP.NET GridView control if at all possible. We've found a couple different options like jQuery and the like, but we have a lot of things to change if we change to a different type of control. So I'd like to avoid changing that if at all possible.
If the time is not a big problem for you the time it takes to get all the records from the database and I believe that on the client side the grid is typically renders as an HTML table than you can use a jquery plugin that will paginate the table on the client side.
http://www.codeproject.com/KB/webforms/clientside_gridviewpaging.aspx
We've run into situations where the Viewstate itself becomes a performance issue, and had to come up with ways to address a similar situation...
Your options depend greatly on some details which aren't included in the question.
For example? How often does the data from the webservice change? You may be able to do one of the following:
Save the results in Cache or Session (not a good idea if the results are that large...)
Serialize the result to an Xml file and read from that while paging
Import the data periodically into a SQL database, or into a temp table in a SQL database, with some identifier to tie the data to the user.
I've had good luck using the jquery tablesorter plugin. It gives some great options.
http://tablesorter.com/docs/

Binding Programatically Vs. Object Data Source for Performance

I used bind all GridViews, DetailViews etc. on my page using an ObjectDataSource (unless it wasn't possible to do so). Recently, I've started binding all my contols programatically. I find this a lot cleaner and easier, though some may disagree.
Binding with a ObjectDataSource obviously has it advantages and disadvantages, as does doing it programatically.
Say I bind a GridView programatically (e.g. GridView1.DataSource = SomeList), when I change page on the GridView, I have to also code this. Each time the page changes I have to call GridView1.DataSource = SomeList again. Obviously with a ObjectDataSource I don't need to do this. I normally stick my SomeList object into the ViewState so when I change page I don't need to hit the database each and every time.
My question is: Is this how the ObjectDataSource works? Does it store it's data in the ViewState and not hit the database again unless you call the .Select method? I like to try and get the best performance out of my applications and hit the database as few times as possible but I don't really like the idea of storing a huge list in the ViewState. Is there a better way of doing this? Is caching per user a good idea (or possible)? Shall I just hit the database everytime instead of storing my huge list in the ViewState? Is it sometimes better to hit the database than to use ViewState?
Does it store it's data in the ViewState and not hit the database again unless you call the .Select method?
No its not save the data in ViewState. In the view state gridview and other similar lists, saves the General Status, eg the sort column, the page, the total pages, the control state, but not the Data.
Is caching per user a good idea
The caching per user on server side is not so good idea except if the caching is last for few minutes only or/and the data that you going to cache is very small. If you cache per user large amount of data for long time they going to grow too much especial if a user starts to read a lot of pages, that at the end you have the same problem.
Now you have to show a large amount of data that come from the relation of many tables, then maybe is better to cache the full relation of the tables to "one flat table".
Shall I just hit the database everytime instead of storing my huge list in the ViewState?
This is also depend from how fast you have design the reading of your data. For me is better to keep the ViewState small, and keep there only informations that you need to make the actions on your page, and not data.

very large viewstate breaking web app

I have a web app, that consumes a web service. The main page runs a search - by passing parameters to a particular web service method, and I bind the results to a gridview.
I have implemented sorting and paging on the grid. By putting the datatable that the grid is bound to in the viewstate and then reading / sorting / filtering it as necessary - and rebinding to the grid.
As the amount of data coming back from the web service has increased dramatically, when I try to page/sort etc I receive the following errors.
The connection was reset
The connection to the server was reset while the page was loading.
I have searched around a bit, and it seems that a very large viewstate is to blame for this.
But surely the only other option is to
Limit the results
Stick the datatable in the session rather than the viewstate
Something else I am unaware of
Previously I did have the datatable in the session, as some of this data needed to persist from page to page - (not being posted however so viewstate was not an option). As the amount of data rose and the necessity to persist it was removed, I used the viewstate instead. Thinking this was a better option than the session because of the amount of data the session would have to hold and the number of users using the app.
It appears maybe not.
I thought that when the viewstate got very big, that .net split it over more than one hidden viewstate field, but it seems all I'm getting is one mammoth viewstate that I have trouble viewing in the source.
Can anyone enlighten me as to how to avoid the error I'm getting? If it is indeed to do with the amount of data in the viewstate?
It sounds like your caching the whole dataset for all pages even though you are only presenting one page of that data. I would change your pagination to only require the data for the current page the user is on.
If the query is heavy and you don't want to have to be constantly calling it over and over because there is a lot of paging back and forth (you should test typical useage pattern) then I would implement some type of caching on the web service end to cache page by page (by specific user if the data is specific to a user) and have it expire rather quick (eg a few minuites).
I think you need to limit the total amount of data your dealing with. Change your code to not pass back extra data that might never be needed is a good place to start.
EDIT: Based on your comments:
You can't change the web service
The user can manipulate the query by filtering or sorting
There is a large amount of data returned by the web service
The data is user specific
Well I think you have a perfect case for using the Session then. This can be taxing the the server with large amounts of users and data so you might want to implement some logic to clear the data from the Session and not wait for it to expire (like on certain landing pages you know the user will go when they are done, clear the session data).
You really want to get it out of the ViewState beacuse it is a huge bandwidth hog. Just look at your physical page size and that data is being passed back and forth with every action. Moving it to the Session would eliminate that bandwidth useage and allow for you to do everything you need.
You could also look at the data the web service is bringing back and store it in a custom object that you make as 'thin' as possible. If your storing a DataSet or a DataTable in your Session, those objects have some extra overhead you probably don't need so store the data as an array of some custom thin object and just bind to that. You would need to map the result from the WS to your custom object but this is a good option you cut down on memory useage.
Let me know if there is something else I am missing.
I wouldn't put the data in either the view state or the session. Instead store the bare minimum information to re-request the dataset from the web service and store that (in either view state or session, or even on the URL). Then call the web service using that data and reaction the data on each request. If necessary, look to use some form of caching (memCache) to improve performance.

ASP.NET Ajax - Asynch request has separate session?

We are writing a search application that saves the search criteria to session state and executes the search inside of an asp.net updatepanel. Sometimes when we execute multiple searches successively the 2nd or 3rd search will sometimes return results from the first set of search criteria.
Example: our first search we do a look up on "John Smith" -> John Smith results are displayed. The second search we do a look up on "Bob Jones" -> John Smith results are displayed.
We save all of the search criteria in session state as I said, and read it from session state inside of the ajax request to format the DB query. When we put break points in VS everything behaves as normal, but without them we get the original search criteria and results.
My guess is because they are saved in session, that the ajax request somehow gets its own session and saves the criteria to that, and then retrieves the criteria from that session every time, but the non-async stuff is able to see when the criteria is modified and saves the changes to state accordingly, but because they are from two different sessions there is a disparity in what is saved and read.
EDIT:::
To elaborate more, there was a suggestion of appending the search criteria to the query string which normally is good practice and I agree thats how it should be but following our requirements I don't see it as being viable. They want it so the user fills out the input controls hits search and there is no page reload, the only thing they see is a progress indicator on the page, and they still have the ability to navigate and use other features on the current page. If I were to add criteria to the query string I would have to do another request causing the whole page to load, which depending on the search criteria can take a really long time. This is why we are using an ajax call to perform the search and why we aren't causing another full page request..... I hope this clarifies the situation.
Just another thought, I've always run into problems with updatepanel and prefer to write my atlas ajax requests through the library directly, using PageMethods. You have more control over what you send and receive. UpdatePanel sends the entire page, and receives the entire page control heirarchy, then it parses out what is 'fresh' and displays that.
Edit: What is the code you're using to save the criteria to the session? And do you have code in the method that actually checks to see if the session has some saved criteria, and passes that back instead? Maybe that's why the 2nd/3rd updatepanel postbacks are returning the first set of criteria instead of the expected results? As an aside, I know from doing some heavy atlas ajax things that there is definitely not two sessions (one for normal postback, one for async) Is there any chance you're using a webfarm?
Edit #2: I wouldn't have been able to write what I've written above (first para) if I hadn't been a fan of someone who replied as well: https://stackoverflow.com/users/60/dave-ward
There are not multiple sessions between normal ASP.NET page loads, postbacks, and ASP.NET AJAX partial postbacks. I can tell you that with certainty.
Rather than storing the search string in the session, how about just using the search TextBox's contents directly? I can't think of any reason why you'd need to shuffle it around, since it will be available throughout the entire page lifecycle anyway.
Finally, concerning your requirements... Using an UpdatePanel does not fulfill the requirement that your users should be able to use other functionality on the page if that functionality also raises partial postbacks. Only one partial postback can be in progress at a time. If another event is raised while your search is in progress, the search request will be canceled without any notification.
Using a page method or web service for the search would be a much faster, easier, and more robust way of doing it. I don't usually plug my own site, but I think a couple of my posts are exactly relevant to what you're doing:
You could use a user control to render the search results through a web service (very much faster than an UpdatePanel): http://encosia.com/2008/02/05/boost-aspnet-performance-with-deferred-content-loading/
Or, you could return the search results as JSON and render that on the client side (even faster): http://encosia.com/2008/06/26/use-jquery-and-aspnet-ajax-to-build-a-client-side-repeater/
Either of those methods could take your search functionality out of the partial postback paradigm, so that it runs faster, uses less bandwidth and server resource, and doesn't preclude other UpdatePanel activity from occurring concurrently.
You need to set the EnableSession property of the WebMethod attribute for the function you are calling.
[WebMethod( EnableSession=true )]
public static void DoSomething(){
/// ....
}
If you use generic handlers .ashx, just derive from IRequiresSessionState interface
public class ActionRequest : IHttpHandler, IRequiresSessionState
{
}

Resources