|  Login
 Silverlight Dashboard 2

 

 Silverlight Dashboard 2

A Silverlight Dashboard to handle long queries

When you employ Silverlight to displays dashboards, you may encounter problems with long running queries timing out. This sample module demonstrates a method to generate the data needed for a dashboard using multiple queries. One query is used to display the current users, and two queries are used to display the top 10 users.

This module uses Dave Black's Silverlight Odometer and the Bar Chart from the Silverlight Toolkit.


 

The Module

When you install the module and place it on a page in your DNN site, you may see a message indicating that the Site Log must be enabled to use the module. Clicking Enable Site Log will enable the Site Log. If your Site Log is already enabled, you will not see this message. 



You will see:

Current Visitors - looks at the last 20 minutes of the Site Log and counts each unique IP address.
Top 10 Users in the past hour - A count of the entries in the Site Log for each of the top 10 visitors in the past hour.



In the Settings for the module (go to Settings then scroll to the bottom of the page) you will see an option to change the Dashboard Key (each portal gets it's own key) and the Dashboard Refresh Time. The Dashboard Refresh Time controls how long the results for the data queries are cached and how often the Silverlight application will query the website for the latest data.
 

One Dashboard Multiple Queries



The Silverlight Dashboard 2 module exposes 3 web services:

GetDashboardTopAnonymousUsers - Gets a count of the items in the Site Log for anonymous users for the past hour.

GetDashboardTopUsers - Gets a count of the items in the Site Log for the top 9 users for the past hour.

GetDashboardUserCount - Gets a count of the unique IP addresses for the past 20 minutes.



The results from all three of the web service queries are compiled and displayed on one Silverlight dashboard. The GetDashboardUserCount (in the ShowUserCount method) and GetDashboardTopUsers (in the ShowTopUsers method) are executed asynchronously by the RefreshIteration method in the Silverlight application. It is called at a frequency that is indicated by the Dashboard Refresh Time setting in the module Settings:

        #region RefreshIteration
        private void RefreshIteration(object sender, EventArgs e)
        {
            BasicHttpBinding bind = new BasicHttpBinding();
            EndpointAddress MyEndpointAddress = new EndpointAddress(strWebServiceBase   "Webservice.asmx");
            var proxy = new WebServiceSoapClient(bind, MyEndpointAddress);

            ShowUserCount(proxy);
            ShowTopUsers(proxy);
        }
        #endregion


When the method called by ShowTopUsers completes (that method is called proxy_GetDashboardTopUsersCompleted), the GetDashboardTopAnonymousUsers web service is called to get the anonymous users:

        #region proxy_GetDashboardTopUsersCompleted
        void proxy_GetDashboardTopUsersCompleted(object sender, GetDashboardTopUsersCompletedEventArgs e)
        {
            // Put the results in the collection
            colDashboardData = e.Result;

            // Get the anonymous requests
            BasicHttpBinding bind = new BasicHttpBinding();
            EndpointAddress MyEndpointAddress = new EndpointAddress(strWebServiceBase   "Webservice.asmx");
            var proxy = new WebServiceSoapClient(bind, MyEndpointAddress);

            proxy.GetDashboardTopAnonymousUsersCompleted  = 
             new EventHandler(proxy_GetDashboardTopAnonymousUsersCompleted);
            proxy.GetDashboardTopAnonymousUsersAsync(strPassword);
        }
        #endregion


When that web service call is complete, the result (e.Result[0]) is added to the collection of top users (colDashboardData) and the final result is displayed in the Bar Chart:
 

        #region proxy_GetDashboardTopAnonymousUsersCompleted
        void proxy_GetDashboardTopAnonymousUsersCompleted(object sender, GetDashboardTopAnonymousUsersCompletedEventArgs e)
        {
            // Add the results to the collection
            colDashboardData.Add(e.Result[0]);
            ((BarSeries)TopUsers.Series[0]).ItemsSource = colDashboardData;
        }  
        #endregion


If the query was still timing out, the processing could be broken up into smaller and smaller chunks. Perhaps only the last users could be retrieved and then the Site Log entry counts could be retrieved for each user one by one. The Silverlight application will never time. If a single query does time out the Silverlight application can be programmed to try the request again.
 

Caching the Data

The other concern with long running queries is that they tie up server resources. You will want to cache the data so that the web server saves the last values in memory for a period of time determined by the Dashboard Refresh Time setting in the module settings. The web server will use these values when available, rather than performing a possibly expensive query on the database server.

The following code shows the GetDashboardUserCount method that implements caching:

        #region GetDashboardUserCount
        [WebMethod]
        public int GetDashboardUserCount(string strPassword)
        {
            int intDashboardUserCount = 0;
            string CacheDashboardUserCount = "";
            DashboardPortalInfo objDashboardPortalInfo = GetDashboardPortalInfo(strPassword);

            // Password is valid only if PortalID is not -1
            if (objDashboardPortalInfo.PortalID > -1)
            {
                // Try to get the value out of the Cache
                // The cache key is preceeded by the PortalID
                CacheDashboardUserCount = HttpContext.Current.Cache.Get(String.Format("{0}{1}", 
                 objDashboardPortalInfo.PortalID.ToString(), "AdefWebserver_DashboardUserCount")) as String;

                if (CacheDashboardUserCount == null)
                {
                    // We only want the data for the 20 minutes
                    DateTime dtLastRefreshTime = DateTime.Now.AddMinutes(-20);

                    // The DashboardUserCount does not exist or has expired
                    // Get the current value
                    DashboardDALDataContext DashboardDALDataContext = new DashboardDALDataContext();
                    var SiteLogsResults = (from SiteLogData in DashboardDALDataContext.SiteLogs
                                           where SiteLogData.DateTime >= dtLastRefreshTime
                                           where SiteLogData.PortalId == objDashboardPortalInfo.PortalID
                                           group SiteLogData by SiteLogData.UserHostAddress into UserHostAddress
                                           select UserHostAddress).Count();

                    intDashboardUserCount = SiteLogsResults;

                    // Set the new time to expire and insert into Cache
                    DateTime dtTimeToExpire = DateTime.Now.AddSeconds(Convert.ToDouble(objDashboardPortalInfo.RefreshTime));
                    HttpContext.Current.Cache.Insert(String.Format("{0}{1}", objDashboardPortalInfo.PortalID.ToString(), 
                     "AdefWebserver_DashboardUserCount"), intDashboardUserCount.ToString(), null, dtTimeToExpire, 
                      Cache.NoSlidingExpiration);
                }
                else
                {
                    // The value is in the Cache 
                    intDashboardUserCount = Convert.ToInt32(CacheDashboardUserCount);
                }
            }

            return intDashboardUserCount;
        }
        #endregion

Summary

When you employ Silverlight to displays dashboards, you may encounter problems with long running queries timing out. Creating a query for each item separately can alleviate time out problems because each query can be run asynchronously. You can even perform more than one query for a single item if needed.

Silverlight provides a unique solution for displaying data based on long running queries. The Silverlight application itself will never time out. If a single query does time out, the Silverlight application can be programmed to try the request again.

 Download

Requires ASP.net 3.5 SP1 or higher on the server

Use the install directions here:

http://dnnsilverlight.adefwebserver.com/FAQ/InstallingSilverlight/tabid/80/Default.aspx

Note: in IIS you will also need to set the MIME Type: Setting .xap MIME Type for Silverlight 2.0