创建自定义报告以在 SharePoint 2013 中显示 SSRS 报告使用情况详细信息
本文介绍如何在 SharePoint 网站中创建 SSRS 报表的自定义使用情况报告。
引言
我们将为部署在 SharePoint 网站中的 SSRS 报表生成使用情况报告。该报告的来源是配置 SharePoint 服务器上的 SSRS 服务应用程序时创建的 Reporting Service 数据库。
生成报告的步骤
- 配置 SSRS 服务应用程序
- 生成查询以从数据库中检索使用情况数据
- 使用 Asp.net 和 C#.net 代码在 GridView 中显示数据
报告概述
下图描绘了我们将如何使用 Asp.net 中的 GridView 控件在 SharePoint 页面上呈现数据。
步骤 1:配置 SSRS 服务应用程序
有关配置 SSRS 服务应用程序的详细步骤,请参阅以下链接。
步骤 2:生成查询以检索 SSRS 报表的使用情况数据
请按照以下步骤生成查询。
- 导航到已配置 SSRS 数据库的 SharePoint 服务器。
- 打开 SQL Management Studio 并连接到 Reporting Service 数据库“ReportingService_SharePoint”。数据库名称可能因您的环境而异,请记住配置服务应用程序时输入的数据库名称。
在 Reporting Service 数据库中,我们仅使用了两个表来获取执行日志详细信息。
1. Catalog 表
此表包含上传到 SharePoint 文档库的 rdl 文件/报表的元数据。
- ItemId – 项目的 guid
- Path – 文件在文档库中的位置
- Name – 上传文件到文档库时为 rdl 文件指定的名称
2. ExecutionLogStorage 表
此表包含 SharePoint 网站中每个 RDL 报表的执行详细信息。
- Parameter – 访问报表时传递的参数
- Format – 文件类型(RPL / HTML 等)
- TimeStart – 执行开始时间
- TimeEnd – 执行结束时间
- TimeDataRetrival – 数据检索时间
- TimeProcessing – 处理时间
3. 展开 View 文件夹以获取 SSRS 报表的执行日志。默认情况下,数据库中有 3 个视图,如下图所示。
ExecutionLog3 查询
SELECT [InstanceName] ,[ItemPath],[UserName],[ExecutionId],[RequestType] ,[Format],[Parameters],[ItemAction] ,[TimeStart],[TimeEnd],[TimeDataRetrieval],[TimeProcessing],[TimeRendering],[Source],[Status] ,[ByteCount],[RowCount],[AdditionalInfo] FROM [ReportingService].[dbo].[ExecutionLog3]
其中
InstanceName
– 应用程序 ID
ItemPath
– RDL 文件路径。格式为 /{Guid}/{libraryName}/{filename}
/{5901b745-d657-41cd-9969-7fddc3c7b670}/Display Message/RPT_Display_Message.rdl
UserName
– 访问报表的用户名
用于从 exutionlogview 3 检索数据的自定义查询
根据我们的需求,我们可以自定义查询来过滤执行日志详细信息。在下面的查询中,我使用了报表名称、用户名以及访问的开始和结束日期来检索数据。
SELECT [userName],ItemPath,[TimeStart] as Date, [TimeDataRetrieval],[TimeProcessing],[TimeRendering],[Status],[ByteCount],[RowCount] FROM ExecutionLog3 where ItemPath like '{0}' and CONVERT(DATE,TimeStart) between '{2}' and '{3}' and userName='{1}'order by TimeStart desc", reportName, loginName, fromDate, toDate
在 GridView 中显示数据
在本节中,我们将了解如何使用 GridView 控件在 UI 中表示执行日志详细信息。
表单代码
<table width="100%" style="padding: 5px;"> <tr> <td style="width: 10px">From</td> <td style="width: 10px"> <spuc:datetimecontrol runat="server" dateonly="true" id="ru_datefrom" /> </td> <td style="width: 10px">To</td> <td style="width: 10px"> <spuc:datetimecontrol dateonly="true" runat="server" id="ru_dateto" /> </td> <td style="width: 25px"> <asp:dropdownlist id="ru_userddl" runat="server"></asp:dropdownlist> </td> <td style="width: 25px"> <asp:dropdownlist id="ru_reportddl" runat="server"></asp:dropdownlist> </td> <td> <asp:button id="rubtnapply" runat="server" text="Apply" onclick="rubtnapply_Click" /> </td> </tr> <tr> <td colspan="9"> <asp:datagrid id="ReportUsageGrid" allowsorting="true" width="100%" cssclass="Grid" runat="server" autogeneratecolumns="False" gridlines="Vertical" cellpadding="3" borderstyle="None" borderwidth="1px" bordercolor="black" onsortcommand="ReportUsageGrid_SortCommand"> <alternatingitemstyle backcolor="Gainsboro"></alternatingitemstyle> <headerstyle font-bold="True" forecolor="white" backcolor="#00B3E3"></headerstyle> <columns> <asp:templatecolumn headertext="Report Name"> <itemtemplate> <asp:label ID="ReportName" runat="server" Text='<%#GetReportName(DataBinder.Eval(Container.DataItem, "ItemPath").ToString())%>'></asp:label> </itemtemplate> </asp:templatecolumn> <asp:templatecolumn headertext="File Name" sortexpression="ItemPath"> <itemtemplate> <asp:label ID="ItemPath" runat="server" Text='<%#FormatItemPath(DataBinder.Eval(Container.DataItem, "ItemPath").ToString())%>'></asp:label> </itemtemplate> </asp:templatecolumn> <asp:templatecolumn headertext="User Name" sortexpression="UserName"> <itemtemplate> <asp:label ID="username" runat="server" Text='<%#FormatUserName(DataBinder.Eval(Container.DataItem, "UserName").ToString())%>'></asp:label> </itemtemplate> </asp:templatecolumn> <asp:templatecolumn headertext="Execution Count" sortexpression="ExecutionCount"> <itemtemplate> <a onclick="ReportUsageReportDialog('<%#FormatReportParameter(DataBinder.Eval(Container.DataItem, " username").tostring(),databinder.eval(container.dataitem, "ItemPath" ).tostring())%>')" href="javascript:void(0);" id="ExecutionCount"><%#Eval("ExecutionCount") %></a> </itemtemplate> </asp:templatecolumn> </columns> <pagerstyle horizontalalign="Center" forecolor="white" backcolor="#999999" mode="NumericPages"></pagerstyle> </asp:datagrid> </td> </tr> </table>
单击执行次数链接时,将打开一个弹出窗口,显示报表的详细信息,包括检索时间、渲染时间和报表状态。我使用了以下脚本在 SharePoint 模态弹出窗口中打开详细信息表单。
<script type="text/javascript"> function ReportUsageReportDialog(parameter) { var options = { url: "/_layouts/15/ReportUsageDetails.aspx?" + parameter, title: "Report Usage Details", dialogReturnValueCallback: function (dialogResult) { if (dialogResult == 1) { SP.SOD.execute('sp.ui.dialog.js', 'SP.UI.ModalDialog.showModalDialog', AddAlertoptions); } }, allowMaximize: false }; SP.SOD.execute('sp.ui.dialog.js', 'SP.UI.ModalDialog.showModalDialog', options); } </script>
代码隐藏
GetReportName
此方法将从 itempath
列值中提取报表名称。
public string GetReportName(string RDLfileName) { DataTable reportMaster = (DataTable)ViewState["ReportMaster"]; if (reportMaster == null) { LoadReportMaster(); reportMaster = (DataTable)ViewState["ReportMaster"]; } RDLfileName = RDLfileName.Contains("/") ? RDLfileName.Split('/')[RDLfileName.Split('/').Length - 1].ToString() : RDLfileName; DataView view = new DataView(reportMaster); view.RowFilter = "LinkFilename2='" + RDLfileName + "'"; ; DataTable results = view.ToTable(); if (results.Rows.Count > 0) { return results.Rows[0]["Title"] != null ? results.Rows[0]["Title"].ToString().Trim() : string.Empty; } else { return string.Empty; } }
FormatItemPath
此方法将使用 itempath
列值构建报表 URL。
protected string FormatItemPath(string itempath) { return itempath.Contains("/") ? itempath.Split('/')[itempath.Split('/').Length - 1].ToString().Trim() : itempath.Trim(); }
BindReportUserNameDDL
此方法绑定用户名下拉列表的值。
void BindReportUserNameDDL() { SPUser user = null; try { record = (DataTable)ViewState["ReportUsageRecords"]; ru_userddl.Items.Clear(); if (!ru_userddl.Items.Contains(new ListItem("All"))) { ru_userddl.Items.Add(new ListItem("All")); } ru_userddl.SelectedValue = "All"; foreach (DataRow row in record.Rows) { SPContext.Current.Web.AllowUnsafeUpdates = true; try { user = SPContext.Current.Web.EnsureUser(row["UserName"].ToString()); } catch() { } if (user != null) { SPContext.Current.Web.AllowUnsafeUpdates = false; if (!ru_userddl.Items.Contains(new ListItem(user.Name, user.LoginName.Contains("|") ? user.LoginName.Split('|')[1] : user.LoginName))) { ru_userddl.Items.Add(new ListItem(user.Name, user.LoginName.Contains("|") ? user.LoginName.Split('|')[1] : user.LoginName)); } } else { if (!ru_userddl.Items.Contains(new ListItem(row["UserName"].ToString(), row["UserName"].ToString()))) { ru_userddl.Items.Add(new ListItem(row["UserName"].ToString(), row["UserName"].ToString())); } } } } catch (Exception ex) { throw; } }
SPContext.Current.Web.EnsureUser
– 这会消耗大量时间通过 SharePoint 网站中的用户名获取用户详细信息。如果用户不存在,将在 catch 块中捕获错误消息,并继续处理其他用户。
为避免性能问题,我们可以创建一个 UserMaster
表来存储用户信息,如用户密钥、用户名、电子邮件 ID 和登录名。
逻辑是,当用户首次访问报表时,会检查用户是否已在用户表中。如果不存在,则将用户添加到表中并返回用户名。如果用户已存在,则通过 exution log 表中的登录名 ID 返回用户名。
void LoadUsers(DropDownList ddl) { try { ddl.Items.Clear(); if (ViewState["UserMaster"] == null) { record = new DataTable(); query = string.Format(@"SELECT [UserKey],[UserName],[EmailId],[LoginName] FROM [dbo].[UserMaster] where isArchived=0 order by [UserName] asc"); record = objBLL.GetData(query); ViewState["UserMaster"] = record; } else { record = (DataTable)ViewState["UserMaster"]; } ddl.DataTextField = "UserName"; ddl.DataValueField = "LoginName"; ddl.DataSource = record; ddl.DataBind(); if (!ddl.Items.Contains(new ListItem("All"))) { ddl.Items.Add(new ListItem("All")); } ddl.SelectedValue = "All"; ViewState["UserMaster"] = record; } catch (Exception ex) { } }
FormatUserName
此方法在传递登录名作为参数时返回用户名。
protected string FormatUserName(string loginName) { try { if (ViewState["UserMaster"] == null) { record = new DataTable(); query = string.Format(@"SELECT [UserKey],[UserName],[EmailId],[LoginName],[GlobalUser] FROM [dbo].[UserMaster] where isArchived=0"); record = objBLL.GetData(query); ViewState["UserMaster"] = record; } else { record = (DataTable)ViewState["UserMaster"]; } row = record.Select("loginname='" + loginName.ToLower() + "'"); if ((row != null && row.Length > 0)) { username = row[0]["UserName"].ToString(); } } catch (Exception) { } return username; }
Bind Grid
此方法绑定 GridView,参数应为开始日期、结束日期、用户名和报表名称。
private void BindReportUsageGrid(DateTime objFromDate, DateTime objToDate, string UserName, string ReportName) { try { query = string.Format(@"SELECT ItemPath, UserName, COUNT(ItemPath) as ExecutionCount FROM ExecutionLog3 where (ItemPath like '%{0}%') and CONVERT(DATE,TimeStart) between '{1}' and '{2}' and UserName like '%{3}%' group by ItemPath, UserName order by ExecutionCount desc ", ReportName, objFromDate.ToString("yyyy-MM-dd"), objToDate.ToString("yyyy-MM-dd"), UserName); dt = SPtable.GetData(query); ReportUsageGrid.DataSource = dt; ReportUsageGrid.DataBind(); ViewState["ReportUsageRecords"] = dt; } catch (Exception ex) { string str = ex.Message; } }
结论
我希望本文能帮助您为在 SharePoint 网站中执行的 SSRS 报表创建自定义使用情况报告。如果您有任何疑问或评论,请告诉我。
历史
2016 年 7 月 19 日:创建初始版本。