Friday, October 17, 2008

Updating LastActivityDate in ASP.Net Membership Issue

So I've just finished rolling out the latest version of my application, which included a huge overhaul of the membership model. Essentially I replaced the entire Asp.Net Profile provider, with my own variation which fits better for my domain (Organization having many users).

I deploy out my site, and everything is running good for a couple of days, then we start to have issues (Which is a whole other story I will spare you all from). So before taking the site down I wanted to see who was using the site. I went over to my trusty administration interface and brought up the user report and what did I see?





UserLast Activity Last Login
JoeSmith10/17/08 11:00 AM10/17/08 11:00 AM
BobSmith10/17/08 11:05 AM10/17/08 11:05 AM


If you can't spot it the issue was all the users last activity date was the same as the last login. Now the kicker is that I have a client side timer invoking a web service every couple of minutes. This service makes a call to System.Web.Security.Membership.GetUser(). If you look up the msdn information you will see that GetUser() is supposed to update the LastActivityDate.

Digging around in the stored procedure [dbo].[aspnet_Membership_GetUserByName] you should see the following:

UPDATE dbo.aspnet_Users
SET LastActivityDate = @CurrentTimeUtc
WHERE @UserId=UserId



You can resolve this by modifying this to:

UPDATE dbo.aspnet_Users
SET LastActivityDate = @CurrentTimeUtc
WHERE LOWER(@UserName) = LoweredUserName


Before you purists jump down my back yes I left off ApplicationName because I only have one application, and our business currently mandates that all users in all of our applications share the same login and personalization. If you need to support multiple applications you can get the ApplicationId from the Application table. If you really need the sql drop me a comment and I will pull it out.

On a side note once the Connect site came back today I was able to confirm this is an old issue

Thursday, October 16, 2008

TypeLibBuilder.exe Crashes & DigitalPersona Software

Updated:

See the update at: http://jberke.blogspot.com/2008/10/typelibbuilderexe-crashes_21.html
=================


Hello,

This is a follow up to an earlier blog post about TypeLibBuilder.exe crashing which was caused by Digital Personas Finger Print Reader Software included in many laptops like my HP DV 9700 here.

I have had a short discussion with one of the Web Dev Tools managers via this forum post: http://forums.asp.net/p/1283140/2685200.aspx#2685200 It doesn't sound like Microsoft has any plans to publish a fix for this issue as they insist that the issue is within Digital Persona's software. I am unable to weigh in on this as I really don't know what each of the two conflicting components are doing. While I dissagree with Microsoft's position, I can understand where they are coming from.

I have also had communications with Kirill Lozin Director of Software Development for Digital Persona. When I originally discovered this issue the best I was able to do was get in touch with DP's sales team; however, since this was considered a free version of software I was unable to get further. Thankfully the manager from Microsoft provided me with Kirill's contact information who has provided the following information.

Digital Persona plans to include a resolution for this issue in the upcoming DigitalPersona Personal v. 4.0 release. This release is planned for October 31, 2008; however, this is a tenative date.

This is great news; however there is a catch. At this time Kirill Lozin is not aware if this release will be made available to those of us who recieved the free version of Digital Persona (I contest that this wasn't free since it was bundled with Vista but anyways...). Keep in mind he is not indicating that it won't be available or that will be available just that he doesn't know what the plans are.

He has promissed to push the patch ideas as strongly as possible; however, there are some complications which has stopped this idea already due to all the notebook manufacturers requiring being required to approve any patch.

I will update my blog as new information is made available.

Thanks,

Josh

Monday, October 13, 2008

Limiting Concurent Users in ASP.Net Sites

I've recently finished implementing a membership model enhancement for my current companies application. This model has a notion of an organization, which then has one or more user accounts. This allows users at a single organization to share data between their accounts.

With this enhancement, a business requirement came in to prevent multiple physical users from sharing a single user account. When I sat down to solve this problem, the first thing I did was fire up google and see what other people have done. All of the recommendations I found was focused on preventing a user from logging to the site and worked like this:
  1. User tries to login, site checks for some identifying piece of information from the client like a guid stored in a cookie.
  2. If there is no cookie then create one.
  3. The site then takes the cookie and looks up in a table (in memory or DB for example) and checks if this cookie is the same one for this user.
  4. If there is no entry in the table or the cookie is the same the user is able to login.
  5. If the cookie doesn't match the user is locked out.

This is an ok algorithm, but its main weakness is that it assumes that we know when a user logs off, which is impossible in an ASP.Net page. One idea and I forgot where I saw this was to use ASP.Net cache to store this entry, we can then set it to auto expire so that if a user gets locked out it would only be for a couple of minutes.

When I thought about this model, the biggest thing I didn't like is that it punishes the user, if for example his browser crashes. It would be even worse if it crashes because of my site and then I prevent him from logging in for five minutes.

I wanted to come up with a solution which works like many of the IM's out there. I wanted a last one in wins model. So how did I achieve this within Asp.Net?

  1. User logs in, and a new Guid is generated, and stored in a non-persistent cookie, and its stored in HttpContext.Current.Cache, using the user's login as a key.
  2. A client side timer is initialized in the main page of the application. This works nicely for us since the user never navigates away from this page currently; however, this same approach could be adapted to other navigation structures.
  3. This timer kicks of a call to a very simple Ajax enabled WCF service.
  4. The service checks the guid stored in the user's cookie.
  5. The services looks into cache for the guid, if no guid is found the value in the cookie is stored. This handles the case of the cache being flushed out.
  6. If the cookie doesn't match the cached item, then a false value is returned to the client.
  7. If the cookie matches the value in the cache a true value is returned.
  8. The client then navigates to an error page if the value is true, it also tracks any dialogs that were opened and navigates them as well.

This algorithm allows us to enforce the requirement to limit concurrent users, while still preventing frustration of a user being locked out because their browser crashed.

Enjoy

- Josh

ps. If I ever get around to building any diagrams I will update this.

Response.Redirect() & ASP.Net Pipeline

I've just finished debugging a fun a bug related my nHibernate code. Essentially I was getting an error that indicated that I was trying to associate a collection with more then one active nHibernate session.

This made no sense within my architechure. I am using a static session manager which essentially creates and caches nHibernate sessions on demand. It stores the session within HttpContext or within CallContext depending upon the environment its loaded in. I then implemented a very simple HttpModule which would flush and close the session after the request is done processing. I was relying upon the PostRequestHandlerExecute event to do this cleanup.

What I discovered is that in one of my pages which had a Response.Redirect() in it, this event is never actually being called. The solution is simple. Use the EndRequest event instead.

One concern I have within the context of my nHibernate architecure is the idea of doing work on the database after the page has finished executing for the user. What happens if an error occurs? I might have shown the user that everything was ok but in fact it wasn't. I'd be curious if anyone has any advice about this one?

Enjoy
-Josh

Wednesday, October 1, 2008

Preparing for IE8

My boss recently installed IE8 Beta 2 just to see what would happen. Of course he decided to go and navigate to our application which resulted in the usual phone call we all dread:

Boss: So Josh I just installed IE8.
Me: Huh huh, and how'd it go?
Boss: Our site looks like crap...

And I am sure you can imagine the rest of the conversation. Our site is optimized for IE7 standards mode, which isn't exactly compatible with IE8 standards mode.

There are a couple of ways we can resolve this. We can invest the time to bring our site up to IE8 standards mode compliance (and in the process hopefully add support for the other browsers which we don't support); however, this takes time which costs money which new startup companies don't always have the luxury of.

Another solution is for the site to lock in to a particular rendering engine. This is a brilliant addition to the architechure of IE, and I hope other browsers follow suit. Its the same concept of being able to lock in your client application to a particular version of .net.

I won't regurgitate how to do this. A really good article is available here.