I have a ASPX page which queries from a database. Once we have the dataset it is bound to a gridview and displayed on the page. All this happens in the Page_Load event.
Ofcourse this a simplistic approach. What is the best way to inform the user that data is being retrieved and when we have the data to update the page with the results in the dataset.
I want all this to happen within the same ASPX page and do not want to hop around pages to achieve this. I looked at update panels however it wasn't clear to me how this could be done with an update panel without having a control which triggers the update for the update panel. There are no controls on my page whhich initiate the database query, it occurs as the page is loaded.
If I do the query in a worker thread and then call the Update method on a UpdatePanel with the gridview as part of it, it doesn't work. Nothing happens.
Any thoughts or help? Thanks.
Well, this is a good question. Personally I have two pretty similar methods to do this:
Have a java script that will make an UpdatePanel reload with a short interval. This will create a series of post-backs to the server. During each post-back you should chek you worker thread and return immediately with the state report, usually one of error, pending, success + data
With a java script, make an asynchronous request to a web-service that will block until the data is fetched. This method brings no latency as compared to the previous one (the time between polls), but may suffer from some browsers/servers attitude to hanging open connections. This is normally solved by some interval (say, 1 minute) introduced, so that the hanging request will return with a message like need more time, in which case the java script should simply repeat the request.
Related
I have a table in MSSQL database, and I have an ASPX page, I need to push all new rows to the page in a descending order. I found this awesome tutorial which is using SignalR and SqlDependency and it shows only the last row descarding the previous rows which have been added when I'm online, it does that because it has a span element to show data and every time it overwrites this span, so I modified the JavaScript code to append the new data and it works fine.
The problem now is when I refreshed the page for the first time, I'll get the new rows twice, and if I refreshed the page again I'll get the new rows triple .. and so on.
The only solution is to close the application and reopen it again, it looks like reset the IIS.
So, what can I do to avoid duplicating data in the online show?
It is not a SignalR issue, that happens because the mentioned tutorial has a series of mistakes, the most evident being the fact that it continuously creates SqlDependency instances but then it trashes them without never unsubscribing from the OnChange event. You should start by adding something like this:
SqlDependency dependency = sender as SqlDependency;
dependency.OnChange -= dependency_OnChange;
before calling SendNotifications inside your event handler. Check this for some inspiration.
UPDATE (previous answer not fully accurate but kept in place for context)
The main problem here is that this technique creates a sort of auto-regenerating infinite sequence of SqlDependencies from inside instances of Web Forms pages, which makes them unreachable as soon as you page has finished rendering. This means, once your page lifecycle is complete and the page is rendered, the chain of dependencies stays alive and keeps on working even if the page instance which created has finished its cycle. The event handler also keeps the page instance alive even if unreachable, causing a memory leak.
The only way you can control this is actually to generate these chains somewhere else, for example within a static type you can call passing some unique identifier (maybe a combination of page name and username? that depends on your logic). At the first call it will do what currently happens in your current code, but as soon as you do another call with the same parameters it will do nothing, hence the previously created chain will go on being the only one notifying, with no duplicate calls.
It's just a suggestion, there would be many possible solutions, but you need to understand the original problem and the fact that it is practically impossible to remove those chains of auto-regenerating dependencies if you don't find a way to keep track of them and create them only when necessary. I hope that part is clear.
PS: this behavior is very similar to what you get sometimes with event handlers getting leaked and keeping alive objects which should be killed, this is what fooled me with the previous answer. It is in a way a similar problem (leaked objects), but with a totally different cause. The tutorial you follow does not clarify that and brings you to this situation where phantom code keeps on executing and memory is lost.
I got it, although I don't like this way absolutely, I have declared a static member in the Global.asax file and in the Page_Load event I checked its value, if it was true don't run a new instance of SqlDependency, otherwise run it.
if (!Global.PageIsFired)
{
Global.PageIsFired = true;
SqlDependency.Stop(ConfigurationManager.ConnectionStrings["db"].ConnectionString);
SqlDependency.Start(ConfigurationManager.ConnectionStrings["db"].ConnectionString);
SendNotifications();
}
Dear #Wasp,
Your last update helped me a lot to understand the problem, so thank you so much for your time and prompt support.
Dear #dyatchenko,
Thanks a lot for your comments, it was very useful too.
I have a table of records that has a column processed. In my web page i'm using sessions.. because every user that opens the page should see different data from the table.. so i initially have processed=0 and when i'm selecting my data i'm updating the column where processed=0 and then i'm updating the column to processed=2 so that way if another opens the page he gets other data... but the problem is that if the user closes the page without changing anything about the page i need to put my column back to 0 processed=0 but i can't handle an event on the close button of the page... and also not on the log out because they may close the page without logging out... so does anyone has any idea how can i manage this?
note that i'm using asp.net with vb.net
for what you need, don't rely on some browser action, i.e. browser close button (what if internet goes down for one of the users :) ).
The simple way to achieve this is to perform somekind of polling at both levels, i.e. in the db(since your flag is stored in the db) and at the code. Polling implies, constantly making request for certain operation after a fixed interval of time. Obviously, polling is taxing, but it is one of the solution.
Another way to do is to as soon as your user Logs in, you create a Http Long lived request, which neither of the parties(client and server) break and as soon as it ends, you set the flag to 0 again, but having a parallel long lasting request along with all those others is not simple. It is termed as Comet
So I would recommend, to constantly make an ajax request say every 2minutes, to update a certain field, say LastActive in user accounts table. This would constitute your Code side Polling
and Then create a sql server job, which constantly monitors this LastActive field and say, if the difference between it and current DateTime is more than 2.10 minutes, it sets the processed=0 for that user.
You can also look into SessionExpire fields(or whatever it is called), if you are using Forms Authentication of ASP.NET through Session
I have a standard web page with Ajax update panel. WorkFlow of the page is : The user can add some entity, delete some entity(on click of their respective buttons) to create some definition. And then user can save these definition, edit it and delete it.
Upon adding/deleting the entities, a complex calculation needs to take place which would be time intensive. What I want is, when the user adds or deletes some entity, a separate thread should do the computation and update the UI. The point to be kept in mind here is, when the entity are added or deleted , the corresponding server side code need to be run first, which adds/deletes the entities from a collection stored in session(that means I can not launch a ajax call on the button, because the server side code for the button needs to run first), and then the logic for computation.
What I have thought of doing is
1. Make the server call for button click
2. When response returns, use AJAX client life cycle to catch the response before page is rendered. This is the place where I would make ajax call, if request was for add/delete entity.
This how ever seems over complicated. I am sure, there must be a easy way to do this.
Found out answer to my problem. What I needed was PageAsyncTask which is in built in asp.net for these kind of jobs.
Google
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
I have a situation in which I select an account and I want to bring back its details. This is a single UpdatePanel round trip and its quite quick.
In addition, I need to bring back some transactional information which is from a much bigger table and takes a couple of seconds for the query to come back.
Ideally, I would like to put this into a second update panel and update this additional information once it has been received, but after the first update panel has updated i.e. the user sees:
Change account
See account details (almost instant)
See transactional info (2 seconds later)
The only way I can think of doing this is to use javascript to cause a SECOND postback once the account details have been retrieved to get the transaction information. Is there a better way?
You cannot run two asynchronous postbacks using UpdatePanels at once.
(Otherwise, the ViewState would get messed up)
However, you can make two "raw" AJAX requests (without UpdatePanels) at once, if you're willing to process the results yourself.