ASP.NET Membership – Show list of users online

by Arnold Matusz 13 7 2009

The .NET Framework 2.0+ comes with a set of functionality for easily building security enforced web applications mainly with the ASP.NET Membership API and the Security web controls. The Membership class has most of the feature one would need with user management, and because it is based on a Provider Model you can write a provider for any Database you wish.

While working on an intranet application I often faced the following situation. Several people were online, logged in, when I needed to upload a new version of the web application. Because I personally know all the people who have access to this application it’s important for me to see who is online so I can announce them before taking the application down and uploading a new version.

The MembershipProvider Class exposes the GetNumberOfUsersOnline() method which returns the number of users online apparently. Well theoretically there is no 100% true way to tell who is online, because HTTP is a stateless protocol and it works simply on a Request-Response basis. There is no guarantee that somebody is still there in 5 seconds after the Response has ended.

Therefore the MembershipProvider can be set to consider a user as online for a certain amount of minutes after the last request. The aspnet_Users table contains a column which stores the LastActivityDate for each user which is then compared to the current time – the UserIsOnlineTimeWindow Property that is set in your web.config file.

This is all very nice and useful except it’s not enough for me. It’s not enough to know that there are 7 people online, I would like to show a list of users online, I would like to know who exactly is online and interesting enough … there is no implementation for this.

So it wouldn’t be a big deal to write a little code to replicate the same functionality to return the usernames aswell. For sake of speed, simplicity and because it’s the most accessible at the moment I’m using an Entity Data Model which is generated for a standard Database (which has been prepared for ASP.NET Application Services with aspnet_regsql.exe). So I won’t be writing any SQL manually, I’ll just use LINQ to Entities to query the data model.

Entities entities = new Entities();
IEnumerable<aspnet_Users> users = entities.aspnet_Users.Include("aspnet_Membership");
var result = (from usr in users
              select new
              {
                  UserID = usr.UserId,
                  Username = usr.UserName,
                  LastActivityDate = usr.LastActivityDate
              }).AsQueryable()
                .Where(u => DateTime.Now.Subtract(u.LastLoginDate).TotalMinutes < 10);

Although everything seems fine, interestingly this doesn’t yield the expected results. And after you take a look at the stored procedure that the  SqlMembershipProvider executes when you call GetNumberOfUsersOnline() it’s not difficult to understand why.

CREATE PROCEDURE [dbo].[aspnet_Membership_GetNumberOfUsersOnline]
    @ApplicationName            nvarchar(256),
    @MinutesSinceLastInActive   int,
    @CurrentTimeUtc             datetime
AS
BEGIN
    DECLARE @DateActive datetime
    SELECT  @DateActive = DATEADD(minute,  -(@MinutesSinceLastInActive), @CurrentTimeUtc)

    DECLARE @NumOnline int
    SELECT  @NumOnline = COUNT(*)
    FROM    dbo.aspnet_Users u(NOLOCK),
            dbo.aspnet_Applications a(NOLOCK),
            dbo.aspnet_Membership m(NOLOCK)
    WHERE   u.ApplicationId = a.ApplicationId                  AND
            LastActivityDate > @DateActive                     AND
            a.LoweredApplicationName = LOWER(@ApplicationName) AND
            u.UserId = m.UserId
    RETURN(@NumOnline)
END
GO

When you take a look at the CurrentTimeUtc declaration everything becomes clear. Because SQL Server and IIS instances may not run from the exact same computer the result of DateTime.Now can be very far apart (imagine the web server in America and the SQL Server in Australia –> totally different time zones –> totally different values for DateTime.Now). Also to avoid any sort of confusion @MinutesSinceLastInActive represents the UserIsOnlineTimeWindow property.

To show a list of users online only slight modification is needed to achieve the desired results, you only need to call ToUniversalTime() on DateTime.Now because this is how SQL Servers stores the LastActivityDate.

Entities entities = new Entities();
IEnumerable<aspnet_Users> users = entities.aspnet_Users.Include("aspnet_Membership");
var result = (from usr in users
              select new
              {
                  UserID = usr.UserId,
                  Username = usr.UserName,
                  LastActivityDate = usr.LastActivityDate
              }).AsQueryable()
                .Where(u => DateTime.Now.ToUniversalTime().Subtract(u.LastLoginDate).TotalMinutes < 10);
gv.DataSource = rez.OrderByDescending(u => u.LastActivityDate); gv.DataBind();

Binding this result to the following GridView will display the list of the users online.

<asp:GridView ID="gv" runat="server" AutoGenerateColumns="false">
    <Columns>
        <asp:BoundField DataField="Username" HeaderText="Username" />
        <asp:BoundField DataField="LastActivityDate" HeaderText="Last activity date" />
    </Columns>
</asp:GridView>

Throughout my example I’ve used the value of 10 for the UserIsOnlineTimeWindow property, but this could come directly from web.config, from an appSetting or anything convenient to you.

image

Any feedback is welcome, I appreciate all of your comments, questions and opinions.

DZone it Digg it Submit to StumbleUpon Submit to Technorati Submit to reddit.com Submit to del.icio.us Submit to NewsVine Submit to Furl Submit to BlinkList

Tags: , , ,

Programming | ASP.NET

Comments

7/13/2009 1:12:59 AM #

trackback

ASP.NET Membership – Show list of users online | Arnold Matusz's Blog

Thank you for submitting this cool story - Trackback from DotNetShoutout

DotNetShoutout |

7/13/2009 8:27:29 PM #

Thao

Dear Sir,
I have just read your article in your blog and i think that is very meaningful.
Could you please send me the Code (asp.net page)  that you guided?

Once again thanks so much for your good information
Looking froward to hearing from you soonest

thanks and best regards

Nguyen Van Thao
Email: thaonv7780@gmail.com

Thao Vietnam |

7/15/2009 7:26:17 PM #

trackback

Daily tech links for .net and related technologies - July 14-17, 2009

Daily tech links for .net and related technologies - July 14-17, 2009 Web Development ASP.NET Membership

Sanjeev Agarwal |

8/19/2009 4:10:30 AM #

eli

where can i find this Entities();
what namespace is it?

eli Israel |

8/23/2009 11:26:26 PM #

Arnold Matusz

Entities is a class that has been generated with the Entity Data Model. If you are not using .NET Framework 3.5 SP1, you will not be able to use this.
But the whole idea is to create your query using the datetime in the UTC "format".

Arnold Matusz Romania |

9/9/2009 9:18:34 AM #

Rahn

Hello Arnold...

I thing what U did is very impressive, Is there some way to produce the Entities localy?

I do have .NET Framework 3.5 SP1...

Rahn Israel |

9/9/2009 9:25:06 AM #

Arnold Matusz

Hi Rahn

No, you'll need .NET Framework 3.5 SP1 to work with the entity framework. But this does not present any problem, because you can use a simple SqlCommand to query the table you only need to send it the date in the above format.

Arnold Matusz Romania |

9/14/2009 1:14:53 PM #

trackback

ASP.NET Membership – Show list of users online

DotNetBurner - burning hot .net content

DotNetBurner - ASP.net |

9/19/2009 4:22:21 AM #

Ashish Suman

Its really nice article but I have a point to raise. As LastActivityDate column updates only when any read or update action is performed on the table. If we use the membership only for the login purpose then after certain time results will not be shown to us even if the user is online.

Ashish Suman India |