Wednesday, October 29, 2008
New version of Goto Meeting
In the latest version their audio-conference is smart enough to detect when I am talking through the phone, and it updates the UI telling all the participants that I am talking. I find this simply amazing, and maybee its because I am tired, sick, and have been sitting here for 8 hours straight looking at code, but I really wonder what it takes to do that.
Anyways its a great inexpensive tool for hosting virtual meetings. Go check it out.
Monday, October 27, 2008
nHibernate Transaction & Session Mgmt
I have an Organization object, and there's a screen where a user can modify the properties and save the object back to the database. I wanted to add additional error handling around the app to make it friendlier, so I removed one of my safeguards that let me generate an error (passing in a string larger then what the DB is configured for), and ran through my test. Essentially the page method doing the save looked like:
protected void saveOrgInfo_Click(object sender, EventArgs e){try
{DoSave();this.saveStatus.Text = "Your changes have been saved.";this.saveStatus.Visible = true;this.saveStatus.CssClass = "successText";}catch (Exception ex){CutterLogEntry.LogError("Error saving OrgInfo", ex);this.saveStatus.Text = "There was an error saving your changes. Please try again.";this.saveStatus.Visible = true;this.saveStatus.CssClass = "warnText";}}private void DoSave(){NHibernateSessionManager.Instance.BeginTransactionOn();
MembershipService memService = new MembershipService();this.orgInfo.UpdateOrganizationInfo(Util.CurrentUser.Organization);memService.SaveOrganization(Util.CurrentUser.Organization);
NHibernateSessionManager.Instance.CommitTransactionOn();
}
One of my modifications was to add overloads to his methods which don't accept a path to the config file, and when this is used it defaults to the Web.Config / App.Config file.
What I found interesting was that I was being redirected to an error page, when based on this code my catch should have handled this. The call stack in the error page indicated that the error was originating in my httpModule which tries to close any open session.
When we tried to call Close on the session the nHibernateSessionManager also calls a flush() which will cause nHibernate to try and save the Organization entity again. The interesting thing here is if we look at the logic in the Commit method, when it fails the SessionManager tries to rollback the transaction:
public void CommitTransactionOn(string sessionFactoryConfigPath) {ITransaction transaction = (ITransaction)ContextTransactions[sessionFactoryConfigPath];try {
if (HasOpenTransactionOn(sessionFactoryConfigPath)) {
transaction.Commit();ContextTransactions.Remove(sessionFactoryConfigPath);}}catch (HibernateException) {
RollbackTransactionOn(sessionFactoryConfigPath);throw;
}}
If we follow the source the Rollback will call the rollback transaction and then call the CloseSessionOn() method. The CloseSessionOn() method will attempt to flush and then close the session. The call to flush will generate an exception here. Because of this exception, the close method is never called.
So when the HttpModule kicks off it sees there is an active session, and then trying to close it calls a flush which generates the exception again. All in all this one exception was thrown three times so far.
I find it strange that nHibernate would try and save an object that was "Saved" within a transactional context. I would imagine that a Rollback should clear out all dirty entities; however, it doesn't. The quick fix is as I said to modify the Rollback method so that it closes (but not flush).
Enjoy
Josh
Tuesday, October 21, 2008
TypeLibBuilder.exe Crashes & DigitalPersona Software Update III
- http://jberke.blogspot.com/2008/05/typelibbuilderexe-crashes-javascript.html
- http://jberke.blogspot.com/2008/10/typelibbuilderexe-crashes.html
I do not know when or where the patch will be made available, but as soon as I know more, I will update this blog entry.
I want to thank the Microsoft & Digital Persona development teams for working together, to get a resolution to this issue. While this issue didn't prevent someone from doing their work, it did require that they choose btw two great features (Java Script Intellisense, or using BioMetrics to save typing and remembering all those passwords).
Enjoy
-Josh
Friday, October 17, 2008
Firefox & GoDaddy SSL Certs
When installing a GoDaddy SSL Certificate make sure you install the intermediaries from: https://certs.godaddy.com/Repository.go. the one you need is: Go Daddy PKCS7 Certificate Intermediates Bundle (for Windows IIS). If your not using IIS you will need to find the right file on that site.
To install follow these steps:
- Open MMC and add Certification Store for the local computer account.
- Go to the Intermediate Certs => Certificates folder, right click on it and select import.
- Browse to the intermediary file and select it, and complete the wizard
Enjoy
Josh
Unrelated Google Add Words Adds
At first I figured the content wasn't focused on the things I blog about because it was so new, and google hadn't scanned enough content. But after 9 months now I figure the ads should become more appropiate. Yet today I am always seeing ads for some type of Surgery, or today was for a Cookie School of some sort (Which was right next to an ASP.Net School).
Anyone reading this want to provide some insight into what I am doing wrong?
Updating LastActivityDate in ASP.Net Membership Issue
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?
User | Last Activity | Last Login |
---|---|---|
JoeSmith | 10/17/08 11:00 AM | 10/17/08 11:00 AM |
BobSmith | 10/17/08 11:05 AM | 10/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
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
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:
- User tries to login, site checks for some identifying piece of information from the client like a guid stored in a cookie.
- If there is no cookie then create one.
- 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.
- If there is no entry in the table or the cookie is the same the user is able to login.
- 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?
- 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.
- 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.
- This timer kicks of a call to a very simple Ajax enabled WCF service.
- The service checks the guid stored in the user's cookie.
- 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.
- If the cookie doesn't match the cached item, then a false value is returned to the client.
- If the cookie matches the value in the cache a true value is returned.
- 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
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
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.