views:

60

answers:

3

Are we "doing it wrong"?

A colleague and I are messing around with an ASP.NET page to act as a "portal" to view the results from a diagnostic program on a UniData server. Although we do the odd-job of ASP/ASP.NET at work, it is not our primary language.

To access this server, we have to use UniObjects, which is an API for authenticating and using the UniData server.

We needed each user visiting the website to have to authenticate with UniData and get their own session via the UniObjects library, then be able to use it without signing in again (unless the session isn't used with in 'x' minutes).

The method we have come up with is as follows:

We have a singleton with a Hashtable. It maps Windows username with a session object.

If the user goes to our page and 'username' doesn't exist in the Hashtable, it redirects to a login page where the session object is created and added to the Hashtable if authentication succeeds. Otherwise, it grabs the users existing session object from the Hashtable and uses that for the request (unless it has expired, in which case we remove it and redirect to the login page).

Each session object (which is a wrapper object for stuff from UniObjects) has a "lastUsed" method. We need to clean-up user's sessions since we have license restrictions on users logged into the UniData server, so every time a user gets redirected to the sign-in page, it checks if any sessions have not been used in 'x' mins, in which case it closes that session and removes it from the Hashtable. It is done here so users won't experience any delay related to checking all sessions on every request, only at login.


Something is telling me that this solution smells, but I don't have enough ASP.NET experience to work out what we should be doing? Is there a better method for doing this or is it actually okay?

+2  A: 

Since all of your users seem to be authenticated, I would suggest you think about using a different way of managing session state and timeout.

Part of the issue you have is that if a user just closes the browser without logging out, or stops using the application, you have to wait until the session times out to kill it off and free up UniObjects for your licensing issues.

My suggestion is as follows:

  1. Add an invisible IFRAME to your MasterPage template, or to each page in the site if you aren't using MasterPages.
  2. That MasterPage will load a KeepAlive.aspx page, that contains a META Refresh, reloading the page every 5 minutes.
  3. You can reduce the session timeout to 10 minutes (maybe even 6)

Now, if a user closes their browser windows, their session times out much quicker than usual, but if their browser window is left open, their session is persistent.

A code example and walkthrough can be seen here.

You now need to solution to prevent the user from leaving their browser window open all night and hogging your UniData licences. In this case I would implement a similar methodology, where a stagnant page (i.e. user has done nothing for 20 minutes) is refreshed to a logout ASPX page, clearing the session.

Junto
Thanks for the link to the keep alive article, it makes sense.
Dan McGrath
+2  A: 

When you say you are using UniObjects... are you using the COM or .NET object set? The easiest would be to use UniObject Conneciton pooling.

When you create your Singleton, are you storing it in the Application object, Session Object, or Cache Object?

I would suggest Application object, as the Session object is can do strange things. One way to handle and check timeouts would be to use the Cache Key with a CacheRemoveCallback. This way you can use a File/Path Monitor dependency to watch for a windows file change to cause a remove manually, or a timeout from the Cache dependency.

Draw back to this is that timeouts on Cache Dependencies are only driven by page activity, and if the asp.net session recycles, it may/will destory the cache dependencies.

Nathan Rector

International Spectrum
Hi Nathan, it is stored in a static Hashtable, so it is in the App Domain. We are using the COM library at the moment since we are testing this in a legacy development environment which already uses the COM library. As to connection pooling, we already have excess in user licences, so we can't justify the costs of connection pooling.
Dan McGrath
+2  A: 

If you are using UniObjects COM, make sure you get your COM marshalling working correctly. Take a look at:

SafeCOMWrapper - Managed Disposable Strongly Typed safe wrapper to late bound COM http://www.codeproject.com/KB/COM/safecomwrapper.aspx

Another thing to watch out for is that the dynamic array class in UniObjects COM has a threading issue that doesn't play nice with .NET. If you can, use your own dynamic array class or array splits in .NET instead of the Dynamic array class in UniObjects COM.

Sometimes when you try to access the data from the class, it shows an empty string, but when you debug it, the data is there. Don't know the root cause of this.

If you need a generic dynamic array class that works with .NET, I can supply you one.

UniObjects.NET does not have these problems to my knowledge.

Nathan Rector

International Spectrum