Download: UserLogViewer_01.00.00_Install.zip (this link contains the install and source) (note: If using DNN4 install and run LinqPrep first. If using DNN5 follow these directions first)
A module intended to demonstrate the use of the "Contains" Linq extension method that allows you to handle complex parameter criteria with a single Linq query.
First enable the site log on your site, create a few test users and log into the site as those test users and click around for a bit to create some sample data. If you do not have any data the module will not show anything when you select the users.
After you install the module and place it on a page in your DNN site, you will see a list of the roles in your portal in the Role box.
When you select a role in the Role box, the users in that role will display in the Users box. You can hold down the Ctrl key and select multiple roles. The users in all the roles selected will show. If you click the *ALL* item (in either box) it will automatically select all the items in the box.
The module will display the number of requests for each of the users selected in the Users box.
As a developer you are frequently tasked with providing the user the ability to enter parameters to query data. In this example we want to allow the user to select one or more roles and then one or more users in those roles. In addition, we want to provide the ability to select all the roles or all the users who match the selected roles.
A developer might assume they need to construct the logic this way:
A closer look however, will reveal:
In this example the following query is used:
#region ShowEvents private void ShowEvents(string[] UserArray) { // Get the SiteLog as an IEnumerable list of type SiteLogInfo IEnumerable<SiteLogInfo> SiteLogList = GetSiteLog().Cast<SiteLogInfo>(); // Query the SiteLogList by determining if the Array of users // passed to the method contain any of the users in the Site log SiteLogList = from users in SiteLogList where UserArray.Contains(users.Name) select users; // Show the list of users that match gvSiteLog.DataSource = SiteLogList; gvSiteLog.DataBind(); } #endregionThe UserArray that is passed as a parameter is the only parameter needed to perform the query no matter what criteria the user selected in the list boxes. The key is this line:
where UserArray.Contains(users.Name)
The Contains extension method allows you to create an array of
criteria and test each record in your result set against that criteria to
produce the final result set.
In this example, the role list is only used to filter the users. The users are the only item needed in the final query.
Even if additional criteria such as "start" and "end" date were added to the interface, that criteria would be passed directly to the final query still resulting in only one query.
The challenge then becomes "how to you make an interface to allow the user to easily filter among multiple interlocking criteria"? This module is offered as one example with most of the code show below:
// DotNetNuke® - http://www.dotnetnuke.com // Copyright (c) 2002-2009 // by DotNetNuke Corporation // // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated // documentation files (the "Software"), to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and // to permit persons to whom the Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all copies or substantial portions // of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF // CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. // using System; using System.Collections; using System.Collections.Generic; using System.Data; using System.Linq; using System.Web.UI; using System.Web.UI.WebControls; using DotNetNuke.Entities.Modules; using DotNetNuke.Entities.Users; using DotNetNuke.Security.Roles; using DotNetNuke.Services.Exceptions; using DotNetNuke.Services.Log.SiteLog; namespace AdefWebserver.Modules.UserLogViewer { public partial class View : PortalModuleBase { protected void Page_Load(object sender, EventArgs e) { try { if ((Page.IsPostBack == false)) { ShowRoles(); } } catch (Exception ex) { Exceptions.ProcessModuleLoadException(this, ex); } } #region ShowRoles private void ShowRoles() { // Get all the Roles RoleController RoleController = new RoleController(); ArrayList colArrayList = RoleController.GetRoles(); // Create a ListItemCollection to hold the Roles ListItemCollection colListItemCollection = new ListItemCollection(); // Create the *All* option colListItemCollection.Add(GetAnAllListItem()); // Add the Roles to the List foreach (RoleInfo Role in colArrayList) { ListItem RoleListItem = new ListItem(); RoleListItem.Text = Role.RoleName; RoleListItem.Value = Role.RoleID.ToString(); colListItemCollection.Add(RoleListItem); } // Add the Roles to the ListBox ListBoxRoles.DataSource = colListItemCollection; ListBoxRoles.DataBind(); } #endregion #region ShowUsers private void ShowUsers(String[] SelectedItems) { // Get all users // If a portal has a lot of users you will want to replace this method with one that // makes a direct call to the users table using Linq to SQL ArrayList arrAllUsers = UserController.GetUsers(PortalId); IEnumerable<UserInfo> Users = from User in arrAllUsers.Cast<UserInfo>() where UserIsInRole(SelectedItems, User.Roles) == true select User; // Create a ListItemCollection to hold the Users ListItemCollection colListItemCollection = new ListItemCollection(); // Create the *All* option colListItemCollection.Add(GetAnAllListItem()); // Add the Users to the List foreach (UserInfo objUser in Users) { ListItem RoleListItem = new ListItem(); RoleListItem.Text = objUser.DisplayName; RoleListItem.Value = objUser.FirstName + ' ' + objUser.LastName; colListItemCollection.Add(RoleListItem); } // Add the Users to the ListBox ListBoxUsers.DataSource = colListItemCollection; ListBoxUsers.DataBind(); } #endregion #region ShowEvents private void ShowEvents(string[] UserArray) { // Get the SiteLog as an IEnumerable list of type SiteLogInfo IEnumerable<SiteLogInfo> SiteLogList = GetSiteLog().Cast<SiteLogInfo>(); // Query the SiteLogList by determining if the Array of users // passed to the method contain any of the users in the Site log SiteLogList = from users in SiteLogList where UserArray.Contains(users.Name) select users; // Show the list of users that match gvSiteLog.DataSource = SiteLogList; gvSiteLog.DataBind(); } #endregion #region ListBoxRoles_SelectedIndexChanged protected void ListBoxRoles_SelectedIndexChanged(object sender, EventArgs e) { // Clear the SiteLog GridView gvSiteLog.DataSource = null; gvSiteLog.DataBind(); // Get the selected items in ListBoxRoles IEnumerable<ListItem> SelectedListBoxItems = from li in ListBoxRoles.Items.Cast<ListItem>() where li.Selected == true select li; // Select all items in the list box if one of them is the "All" item (-1) if (SelectedListBoxItems.Count(X => X.Value == "-1") > 0) { // Select all items in the list box foreach (ListItem RoleListItem in ListBoxRoles.Items) { RoleListItem.Selected = true; } } // Only try to load Users if there are selected Roles if (SelectedListBoxItems.Count() > 0) { // Create an array of the Role names and call ShowUsers ShowUsers(SelectedListBoxItems.Select(x => x.Text).ToArray()); } } #endregion #region ListBoxUsers_SelectedIndexChanged protected void ListBoxUsers_SelectedIndexChanged(object sender, EventArgs e) { // Get the selected items in ListBoxUsers IEnumerable<ListItem> SelectedListBoxItems = from li in ListBoxUsers.Items.Cast<ListItem>() where li.Selected == true select li; // Select all items in the list box if one of them is the "All" item (-1) if (SelectedListBoxItems.Count(X => X.Value == "-1") > 0) { // Select all items in the list box foreach (ListItem UserListItem in ListBoxUsers.Items) { UserListItem.Selected = true; } } // Only try to load Events if there are selected Users if (SelectedListBoxItems.Count() > 0) { // Create an array of the Role names and call ShowEvents ShowEvents(SelectedListBoxItems.Select(X => X.Value).ToArray()); } } #endregion #region GetSiteLog private IEnumerable GetSiteLog() { // Get the entire Site Log SiteLogController SiteLogController = new SiteLogController(); // Call the core method to read the site log into a DataReader IDataReader SiteLog = SiteLogController.GetSiteLog(PortalId, "", 3, Convert.ToDateTime("1/1/1900"), DateTime.Now.AddDays(Convert.ToDouble(1))); // Use the DataRecord extension method to convert the DataReader to IEnumerable IEnumerable SiteLogList = (from row in SiteLog.DataRecord() select new SiteLogInfo { Name = (string)row[0], Requests = (int)row[1], LastRequest = Convert.ToDateTime(row[2]) }).ToList(); return SiteLogList; } #endregion #region UserIsInRole private bool UserIsInRole(string[] SelectedRoles, string[] RolesForUser) { bool boolRoleFound = false; foreach (string Role in SelectedRoles) { if (RolesForUser.Contains(Role)) { boolRoleFound = true; break; } } return boolRoleFound; } #endregion #region GetAnAllListItem private static ListItem GetAnAllListItem() { ListItem ListItem = new ListItem(); ListItem.Text = "*ALL*"; ListItem.Value = "-1"; return ListItem; } #endregion } }
When faced with programming an interface that allows the user to select various complex parameters, a developer may feel they will need a lot of "if... then..." statements. Usually the query only needs the parameters from the final selection. This can easily be handled using the "Contains" Linq method.
You want to minimize the amount of code that you create whenever possible to minimize bugs and the time required for other developers to add enhancements. In addition, This module demonstrates helpful extension methods that allow you to transform Arraylists and IDataReaders that the DNN Core methods produce, into a format that can be used by Linq. Linq is always the best method to use rather than manipulating collections using loops.
Note: the module uses Linq but it does not use Linq to SQL.
[Back to: The ADefWebserver DotNetNuke HELP WebSite]
Buy DotNetNuke Modules from Snowcovered |
DotNetNuke™ is a registered trademark of DotNetNuke Corporation.