Coffeehouse Thread

21 posts

Forum Read Only

This forum has been made read only by the site admins. No new threads or comments can be added.

Maybe a dumb question...ASP.NET

Back to Forum: Coffeehouse
  • User profile image
    spivonious

    I have a web site that uses a membership provider. Some pages can trigger a long database operation. It seems that once this operation is started, that session can't go to any other page until the operation completes.

    Would async page loading solve this problem, or is there some property I'm missing?

  • User profile image
    W3bbo

    'async page loading' is for something else - you should make page generation as fast as possible. If your application performs any task that typically takes longer than 20ms you should move it to a different thread and return a "Doing operation in background" message to the user - that page should then automatically refresh every 2-3 seconds until the operation is completed and it returns the result.

  • User profile image
    spivonious

    Hmm, maybe I can rig something up where it loads the page and then does a callback for the grid to load itself.

  • User profile image
    cbae

    What does the long database operation have to do with the membership provider specifically? Does a long database operation have to run in order to determine identity or authorization?

  • User profile image
    ManipUni

    Alternative design strategy: Page within a page. Load the outer-page, that page loads an AJAX component which then makes the call to the inner-page which actually handles the request. You can even draw a little "loading" animation for the object using JavaScript.    

    This is how Google+ works. Page within a page.     

    Also saves you from having to write any of that complex multi-threading code. Just have to write complicated JavaScript instead (or JQuery).    

    PS - Don't use Frames, it isn't 1985. Plus if you do I will kill this kitten

  • User profile image
    spivonious

    , ManipUni wrote

    Alternative design strategy: Page within a page. Load the outer-page, that page loads an AJAX component which then makes the call to the inner-page which actually handles the request. You can even draw a little "loading" animation for the object using JavaScript.    

    This is how Google+ works. Page within a page.     

    Also saves you from having to write any of that complex multi-threading code. Just have to write complicated JavaScript instead (or JQuery).    

    PS - Don't use Frames, it isn't 1985. Plus if you do I will kill this kitten

    lol, do browsers even support frames anymore?

    Page-within-a-page is essentially what I ended up doing. I'm using the DevExpress ASPxGridView control, which provides a PerformCallback() javascript method. I handle that and perform the binding in the callback method.

    @cbae - I don't know if membership has anything to do with it. If the session "thread" is busy, it won't serve up other pages. Pretty annoying, and prevents me from doing other things while I wait for the data to load.

  • User profile image
    magicalclick

    @spivonious:

    Just FYI, don't flood Grid in HTML in IE9. It will have nasty impact on performance, regardless it is visible or not.

    Leaving WM on 5/2018 if no apps, no dedicated billboards where I drive, no Store name.
    Last modified
  • User profile image
    W3bbo

    , cbae wrote

    What does the long database operation have to do with the membership provider specifically? Does a long database operation have to run in order to determine identity or authorization?

    I'm guessing a membership table containing millions of rows but without an index. Ouch.

    SELECT operations used on typical page requests should execute in under 10ms or so - any longer and you've either got a complicated query (time to de-normalise) or missing something obvious (like an index).

  • User profile image
    cbae

    , W3bbo wrote

    *snip*

    I'm guessing a membership table containing millions of rows but without an index. Ouch.

    SELECT operations used on typical page requests should execute in under 10ms or so - any longer and you've either got a complicated query (time to de-normalise) or missing something obvious (like an index).

    It's definitely not out of the question for something like this is to be the cause. It would be kind of strange though if it all of sudden started happening. You usually don't have to muck around with membership tables all that much, even if you choose to roll your own rather than using the default ASP.NET membership tables.

  • User profile image
    figuerres

    , spivonious wrote

    I have a web site that uses a membership provider. Some pages can trigger a long database operation. It seems that once this operation is started, that session can't go to any other page until the operation completes.

    Would async page loading solve this problem, or is there some property I'm missing?

     

    might help if you said more about *what* is going on?

    for example, are you trying to show a bunch of data in a large grid ?

    is the user selecting to do this or are you doing it on the server for some reason that the user has no choise on?

    in general i say if it takes more than about 30 seconds to have the server comple the page responce then you need to re-think what's going on. pages should generally get served up in less than 5-10 seconds. and thats with a lot of back end work and some really complex stuff.

    so > 5 seconds - start digging cause it's wrong and you need to find out why.

    more than 15 seconds server time and you are in deep smelly stuff and you better get it cleaned up.

  • User profile image
    spivonious

    It's not the membership data that is slow; I only mentioned that because I thought it might be causing the apparent single-threaded session.

    I'm loading in lab data for users to view. It's at five levels: groups, samples, analyses, invoice, and contacts. Because of certain search requirements, I'm joining all of the tables and then storing the returned data in the session. If the user search terms change, I check to see if I already have the data they're looking for, and if not, go back to the database again.

    For most users, this works and performs fine. But for some users that we do a ton of work for, even querying for a week's worth of data is taking 30-45 seconds to return from the DB. Everything is properly indexed and normalized; it's just a ton of data. "De-normalizing" the DB is not an option as its used by a lot of other programs.

    The slowness is all on the DB side. The actual page rendering is fast.

    My main problem is that if a user comes in, clicks to view the lab data, and then decides they want to go somewhere else on the site, it won't take them anywhere until the lab data is retrieved. How can I get around this? I've tried polling the "IsClientConnected" property but it seems to always return true, even if the user has moved on to another server entirely. (Maybe I misunderstand what this property is for).

    I haven't done much web development before, so I'm sure it's something simple that I'm missing.

  • User profile image
    cbae

    @spivonious: What event actually triggers the query on the backend--the loading of the page itself or clicking of a user control (e.g. "Search" or "OK" or "Go" button)?

    If it's the former, then you will most definitely need to check IsPostBack (not IsClientConnected). This will let you distinguish between first load and postbacks triggered by a user control action. Here's a very valuable reference for any ASP.NET developer.

    Note that all of these events (except control events) are fired on every page load (i.e. first load as well as every single postback triggered by a user control).

    So, if you happen to have bound the code to invoke the query to the wrong event, you could very well be invoking the query BEFORE ASP.NET figures out that you actually clicked a control to simply navigate to a different page, in which case you've hit the backend for no reason at all.

     

  • User profile image
    figuerres

    well here are the first things that come to mind:

    1) do not use the session to hold data that is any larger than say 1 simple class that is no more than say 5K bytes, in fact as much as possible do not put anything in session larger than a simple type like an int , or a guid or a datetime.

    there are a *LOT* of reasons why this is .... some of them may not be super critical to this app but it's kind of a "best practice" thing to always do so you do not have issues down the road.

    2)  if the data may be largeish at time and if the work takes (possibley) a long time then what about a second db that just has a stash of the data with a date created and a few other bits of data so that you can run a sql job to delete rows when they are too old or the user does not need them ?

    this way you can use a simple key to fech the data from a table in the format you need and not hold it in session. you can also re-load the data w/o going back to the main db if and when it is ok to do so, like they close the browser and 5 minutes later they need the exact same data.

    you may want to look up the XML / Blob functions and have a standard class with collections that you can serialize back and forth ... that way you make a simple table in the "temp data" and have a common interface to the web app.

    3) then you can look at some thing like setting up a "Job Queue"  to allow you to move the long running data prep into a windows service or some other method like MSMQ

    the user inputs the parameters, you write them to the temp db and setup flags that it's a new job and has not been completed. then the service can do the work and update the data.

    the user gets a simple page back with the confimration of processing and you can use some ajax and links to re-fresh the page and let them get the data when it's ready fro them.

    if the job finishes and they are on the status page the ajax can just push them to the view results page .... if the job is fast they may never see the processing status page.

    and this kind of design will scale up to work with large datasets and more users w/o breaking or locking up the client or the server.

     

  • User profile image
    blowdart

    This shouldn't lock up the client, not really, as database connections would linked to the request ... unless you're doing something like putting a database connection in session state?

    Mind you, you should consider paging the data at a minimum and just asking for 50 rows at a time and allowing the user to navigate to the next x results or previous x results.

  • User profile image
    magicalclick

    Don't you guys just use Views in DB? I thought views are already cached in DB. But in all honesty, I think the slow join is something to look at. You really don't want to have a query run that long at any given moment.

    Leaving WM on 5/2018 if no apps, no dedicated billboards where I drive, no Store name.
    Last modified
  • User profile image
    spivonious

     @cbae:

    The grid we're using doesn't store the data in its viewstate, so it must be bound on every call, postback or not. Once loaded, the data is cached in the session, so performance on postbacks and callbacks is fast enough.

    @figuerres:

    1. Where should I keep it otherwise?

    2. We thought of doing this with Oracle's "materialized views", but the data is changing constantly and was estimated to take over a day to synchronize with the master DB. Serialization is a thought, but we'd still want to keep it close to real-time updated, and I don't think our user base (right now about 50 users, expected to grow to a few hundred) would look at enough common data to take advantage of it.

    3. This seems like a lot of extra work to duplicate Oracle's materialized views.

    @blowdart:

    It's not locking up the client, it just seems to queue requests. If I click on "Groups", and then click on "Contacts", the browser is still responsive, but it's not taking me to contacts until the "Groups" data finishes loading from the DB.

    I'd love to do DB-side paging, but we'd lose a ton of features from the grid we're using if we did (grouping being the most important).

    @magicalclick:

    At least in Oracle, views are treated like stored subqueries. No data is cached AFAIK.

  • User profile image
    magicalclick

    How about this in your

    _PageStart.cshtml?

    And make sure it is synchronous, so that the DB will indeed finish before the thread is completed. Otherwise there wouldn't be exception thrown.

    Or there should be other ways, like using a Collection storing what queries are running (with pointers or something), and when you render a new page, terminal all read-queries of the customer from that Collection.

        try
        {
            RunPage();
        }
        catch (System.Threading.ThreadAbortException ex)
        {
          // Do some DB query termination here.
    
        }
        catch (Exception ex)
        {
            Response.Redirect("~/Error");
        }
    

    Leaving WM on 5/2018 if no apps, no dedicated billboards where I drive, no Store name.
    Last modified
  • User profile image
    cbae

    , spivonious wrote

     @cbae:

    The grid we're using doesn't store the data in its viewstate, so it must be bound on every call, postback or not. Once loaded, the data is cached in the session, so performance on postbacks and callbacks is fast enough.

    The grid doesn't have to be bound during a postback if the user is just going to be redirected to another page. That's why I'm saying that binding your code to the correct events is important to prevent hitting the database when it isn't absolutely necessary. I'm not saying that this will solve the query take so long, but at least this won't cause a delay in redirecting to another page.

Conversation locked

This conversation has been locked by the site admins. No new comments can be made.