A most interesting way of sharing session state between Classic ASP and ASP.Net



  • So, I'm digging through this application based on some tickets. Any errors I hit while trying to fix the tickets (even if they're unrelated), I go about fixing, and do some general housekeeping work as I go.

    As mentioned in a previous post, some settings were stored in the registry for the legacy COM objects. These include the database server and the database name. Previously, the registry was hit several times per request, opening and closing the key each time, in order to build the connection string, which was rebuilt every single time (There were also some loops that read in all the registry keys, found the one it was looking for... and then kept reading them until no more were left). This was rather quickly replaced with a static class that reads the registry once, stores the values in a collection, which is then used from then on out.

    However, sometimes, the bits for the connection string are stored in session state. The bits responsible for initially setting up the session state? The COM objects running in legacy ASP. How do they pull those session variables over? By making an HTTP request per variable to a legacy ASP page from .Net. For each of the 10 variables it pulls over. On every page load. Twice: Once for the master page, once for the content page.

    It looks like my next bit of work is pulling that logic up into global.asax, and handle that on session start, so it's done once. And maybe adding a new legacy ASP page that will just dump all the session variables out in an easy to parse format, that way there's just one HTTP request to get it all, done once on session start.

    I know a better way would be to store session information in the database, but my goal is to also not modify any of the legacy COM objects.



  • A quick update... I just implemented the legacy ASP page to dump out all session variables so I can read them in. In addition to what I was expecting (database server, database name, etc). There's a session variable called Password. That stores the password the user logged in with. In plain text.



  • One of the better marshalling mechanisms I've seen in my career involved two client side applications. The first exe essentially allowed the user to browse records in a database and invoke another executable to operate on selected records. The second exe was invoked via out of proc COM which is normal enough.

    But rather than pass the id of the record or a record set or something via the COM interface that the first app was already using to interact with the second, the first app wrote the record id in a "known" location in the registry. The second app would look at that known location, connect to the database and retrieve the record by that id.

     Both side of the equation were controlled by the same team so there was no issue with a COM contract that couldn't be changed. It was written back in the 95 days so of course used local_machine instead of current_user so this came to light with a "doesn't work if not admin" on NT.

     But in full disclosure did I change the COM interface and pass the id that way? Of course not. I changed the registry path in both apps, recompiled and marked it fixed.


  • Considered Harmful

    @dkackman said:

    One of the better marshalling mechanisms I've seen

    I'd hate to see one of the worse ones.


  • Trolleybus Mechanic

    @bardofspoons42 said:

    It looks like my next bit of work is pulling that logic up into global.asax, and handle that on session start, so it's done once. And maybe adding a new legacy ASP page that will just dump all the session variables out in an easy to parse format, that way there's just one HTTP request to get it all, done once on session start.
     

    I had to do something similar for one of our webapps that transitioning between Classic and .Net. Half the system is in one, half the system in the other. Meaning it had to be a two-way exchange of session states.

    I ended up writing a function that would

    1) Create a new GUID
    2) Write all the current session variables into the DB keyed to that GUID
    3) Make a server-side webcall to a asp (or aspx) page with the GUID and the user's asp or asp.net session cookie

    The receiving page would receive the GUID, open the DB, read the dataset (and delete it to keep things tidy), and put everything it read into session.  Since it had received the user's session cookie, it would automatically go into the correct session.

    There were only a few pages past the Login page that actually made changes to the session that were important enough to transfer.  Those pages, after making their changes, would just call the asp.net function (or the asp function, which was in StupidGlobalFunctions.inc).

    A couple funtime fun times you might hit:

    1) Save the datatype. You'll want to cast it back to an int where needed
    2) Objects in the Session? UNPOSSIBLE!  IGNORE THEM!
    3) You might think you can just serialize the entire sessionstate bag and deserialize it. Sure, as long as every single object type exists in both .net and classic.
    4) You'll need to manually add the session cookie into your backend webrequest. And manually parse it out from the response.
    5) Make sure your production server firewall allows for the server to make a request to itself on port 80...

     If it helps, here's a code dump of the files. You'll probably need to strip away a couple things, change the DBUtility to whatever you use. It isn't pretty, it's fairly hacky, but it works:

    .Net Utility: http://pastebin.com/Z5WEMc8T

    asp Utility:  http://pastebin.com/dc1ZCcfR

    Transfer To Asp webpage: http://pastebin.com/vMtzFXsp

    Transfer To .Net webpage:  http://pastebin.com/AdRUiV47

     


  • Discourse touched me in a no-no place

    @joe.edwards said:

    @dkackman said:
    One of the better marshalling mechanisms I've seen

    I'd hate to see one of the worse ones.

    No kidding--even converting the record ID to a string and passing it via a COM method would be much better than using the registry for IPC.


  • Considered Harmful

    You put the data temporarily in the database, why not leave it there for the duration of the session where both apps can get at it?



  • @bardofspoons42 said:

    It looks like my next bit of work is pulling that logic up into global.asax, and handle that on session start, so it's done once.
    But what will you do if the DB connection must be changed in mid-session?

    The original method easily allows for such a scenario. The performance tradeoff is a small price compared to the increased flexibility.



  • @joe.edwards said:

    You put the data temporarily in the database, why not leave it there for the duration of the session where both apps can get at it?

    This is what I would have expected straight off. If the DB's not fast enough, stick the session data in memcached or similar.

    There might be some fiddliness with making sure the two sides don't ruin each other's data, but not any more than with the current, desperate shoving strategy.



  • @Anonymouse said:

    @bardofspoons42 said:

    It looks like my next bit of work is pulling that logic up into global.asax, and handle that on session start, so it's done once.
    But what will you do if the DB connection must be changed in mid-session?

    The original method easily allows for such a scenario. The performance tradeoff is a small price compared to the increased flexibility.

    The connection string in use is based on the current customer, which is established on sign-in, and then doesn't change. So, in this instance, that is not a concern.

    There's no mechanism for ASP.Net to push session state back into the legacy ASP bits, so there's no need for more advanced setups that allow for that. In addition, I really don't want to touch the legacy stuff if I don't have to. My general strategy is to contain it as much as possible, so when it gets phased out, it's all the easier to do, so my plan of pulling session variables once after they're set up does seem to be the best approach.

    Though, before I mess with that, I'm going to delete this

    SqlQuote
    function, and work my way through the app making SQL statements parameterized.



  • @bardofspoons42 said:

    @Anonymouse said:

    @bardofspoons42 said:

    It looks like my next bit of work is pulling that logic up into global.asax, and handle that on session start, so it's done once.
    But what will you do if the DB connection must be changed in mid-session?

    The original method easily allows for such a scenario. The performance tradeoff is a small price compared to the increased flexibility.

    The connection string in use is based on the current customer, which is established on sign-in, and then doesn't change. So, in this instance, that is not a concern.

    Too subtle?

     



  • @Anonymouse said:

    @bardofspoons42 said:

    @Anonymouse said:

    @bardofspoons42 said:

    It looks like my next bit of work is pulling that logic up into global.asax, and handle that on session start, so it's done once.
    But what will you do if the DB connection must be changed in mid-session?

    The original method easily allows for such a scenario. The performance tradeoff is a small price compared to the increased flexibility.

    The connection string in use is based on the current customer, which is established on sign-in, and then doesn't change. So, in this instance, that is not a concern.

    Too subtle?

     

    Too jaded. I wouldn't be surprised at all if a system did that.


Log in to reply