如何:为 PerformancePoint Services 报告创建编辑器
上次修改时间: 2011年8月30日
在 Microsoft SharePoint Server 2010 中的 PerformancePoint Services 中,自定义编辑器使用户能够设置自定义对象的属性。它们提供了编辑控件并在库中检索和更新自定义对象。有关编辑器要求和功能的详细信息,请参阅用于自定义 PerformancePoint Services 对象的编辑器。
适用范围: SharePoint Server 2010
报表编辑器还必须初始化报表端点,该端点从记分卡和筛选器提供程序接收参数值。
本主题中的过程和示例基于自定义对象示例中的 SampleReportViewEditor 类。编辑器是一个使用户能够修改报表的名称和说明的瘦 Web 应用程序。本主题的"示例"一节中提供了该类的完整代码。
备注
我们建议您将示例编辑器用作模板。该示例演示了如何调用 PerformancePoint Services API 中的对象,提供了简化库操作(例如创建和更新对象)调用的帮助程序对象,并演示了 PerformancePoint Services 开发的最佳实践。
通过执行两个基本过程来创建报表编辑器,如下所示:
创建和配置编辑器类
定义编辑功能
若要创建自定义编辑器,请首先创建编辑器类。
创建和配置编辑器类
安装 PerformancePoint Services,或者将您的扩展使用的 DLL(步骤 3 中列出)复制到您的计算机上。有关详细信息,请参阅 开发方案中使用的 PerformancePoint Services DLL。
在 Visual Studio 中,创建一个 C# 类库。如果您已为扩展创建了一个类库,请添加新 C# 类。
将以下 PerformancePoint Services 和 SharePoint Server 2010 DLL 作为程序集引用添加到项目中:
Microsoft.PerformancePoint.Scorecards.Client.dll
Microsoft.PerformancePoint.Scorecards.ServerCommon.dll
Microsoft.PerformancePoint.Scorecards.Store.dll(由帮助程序类使用)
Microsoft.SharePoint.dll(由帮助程序类使用)
示例编辑器还包含对 System.Web.dll 和 System.Web.Services.dll 的程序集引用。根据您的扩展的功能,可能需要其他项目引用。
将示例中的以下类添加到项目中。编辑器使用这些帮助程序类来与 PerformancePoint Services 存储库进行交互:
DataSourceConsumerHelper.cs
ExtensionRepositoryHelper.cs
ReportViewRepositoryHelper.cs
IDataSourceConsumer.cs
备注
示例报表从筛选器获取数据,所以它没有使用 DataSourceConsumerHelper 或 IDataSourceConsumer 对象。不过,如果报表从 PerformancePoint Services 数据源获取数据,则可以使用 DataSourceConsumerHelper 类公开的方法来检索数据源,如如何:为 PerformancePoint Services 筛选器创建编辑器中所述。
在编辑器类中,为以下 PerformancePoint Services 命名空间添加 using 指令:
Microsoft.PerformancePoint.Scorecards
Microsoft.PerformancePoint.Scorecards.ServerCommon
根据您的扩展的功能,可能需要其他 using 指令。
从支持您的编辑器实现的基类继承。因为示例报表编辑器是 Web 应用程序,所以它从 Page 类继承。其他实现可从基类(例如 UserControl 或 WebPart 类)派生。
创建和配置编辑器类后,必须定义编辑器的功能。
定义编辑功能
声明公开您希望用户查看或修改的属性的控件的变量。示例报表编辑器首先声明用户界面组件(这是一个 ASPX 页)中定义的 Web 服务器控件的变量。示例编辑器还定义使用户能够提交更改的按钮控件。然后,编辑器调用 CreateChildControls() 方法使控件可在该页上使用。
备注
编辑器独立于用户界面定义编程逻辑。有关创建编辑器的用户界面组件的说明不在本文档的讨论范围内。
将 AllowUnsafeUpdates 属性设置为 true。这使报表编辑器能够将数据写入库中,而无需使用表单发布操作。
示例报表编辑器在 Page_Load 方法中执行步骤 2 至 6。Page_Load 还用于初始化和验证变量和控件、填充控件以及保存自定义报表和帮助程序对象的状态信息。
从查询字符串检索参数并将它们设置为本地变量的值,如以下代码示例中所示。
// The URL of the site collection that contains the PerformancePoint Services repository. string server = Request.QueryString[ClickOnceLaunchKeys.SiteCollectionUrl]; // The location of the report in the repository. string itemLocation = Request.QueryString[ClickOnceLaunchKeys.ItemLocation]; // The operation to perform: OpenItem or CreateItem. string action = Request.QueryString[ClickOnceLaunchKeys.LaunchOperation];
有关查询字符串参数的信息,请参阅用于自定义 PerformancePoint Services 对象的编辑器。
检索 ReportViewRepositoryHelper 对象,它用于调用库,如以下代码示例中所示。
reportviewRepositoryHelper = new ReportViewRepositoryHelper();
基于查询字符串参数设置报表位置,如以下代码示例中所示。
RepositoryLocation repositoryReportViewLocation = RepositoryLocation.CreateFromUriString(itemLocation);
从查询字符串检索要执行的操作(OpenItem 或 CreateItem),然后检索或创建自定义报表,如以下代码示例中所示。
if (ClickOnceLaunchValues.OpenItem.Equals(action, StringComparison.OrdinalIgnoreCase)) { // Use the repository-helper object to retrieve the report. reportview = reportviewRepositoryHelper.Get(repositoryReportViewLocation); if (reportview == null) { displayError("Could not retrieve the report view for editing."); return; } } else if (ClickOnceLaunchValues.CreateItem.Equals(action, StringComparison.OrdinalIgnoreCase)) { reportview = new ReportView { RendererClassName = typeof(SampleReportRenderer).AssemblyQualifiedName, SubTypeId = "SampleReportView" }; } else { displayError("Invalid Action."); return; }
若要检索自定义报表,请使用 ReportViewRepositoryHelper.Get 方法。
若要创建自定义报表,请使用 ReportView() 构造函数,然后定义报表的 Name、RendererClassName 和 SubTypeId 属性。
SubTypeId 是报表的唯一标识符,它必须与您在 PerformancePoint Services web.config 文件中为自定义报表指定的 subType 属性相匹配。RendererClassName 是定义呈现器 Web 服务器控件的类的完全限定名称。如果没有在编辑器中定义,则此值默认为 web.config 文件中指定的呈现器类。
备注
默认情况下,用户只能从 PerformancePoint 仪表板设计器创建自定义对象。若要使用户能够在仪表板设计器之外创建自定义对象,您必须添加一个菜单项以将 CreateItem 请求从库中的内容类型发送到编辑器。有关详细信息,请参阅用于自定义 PerformancePoint Services 对象的编辑器。
定义报表的端点,这使报表能够从筛选器和记分卡检索数据。示例报表编辑器定义了所需的端点属性,如以下代码示例中所示。
if (0 == reportview.EndPoints.Count) { EndPoint endpoint = new EndPoint { Category = EndPointCategory.None, UniqueName = "SampleReportView_EndPoint", // The display name is shown to users in Dashboard Designer. // It represents the endpoint that can be connected // to a filter or scorecard. DisplayName = "Sample Report View EndPoint" }; reportview.EndPoints.Add(endpoint); }
示例编辑器在 VerifyReportView 方法中定义端点。它还使用 VerifyReportView 来验证是否设置了所需属性并定义可选的 CustomData 属性,后者可用来存储报表信息。
使用用户定义的更改来更新报表。示例报表编辑器中的 buttonOK_Click 方法调用 ReportViewRepositoryHelper.Update 方法来更新库中报表的 Name 和 Description 属性。buttonOK_Click 还用于验证控件内容并检索自定义报表和帮助程序对象的状态信息。
备注
用户可以编辑自定义对象的 Name、Description 和 Owner("负责人")属性,并直接从仪表板设计器和 PerformancePoint Services 库中删除自定义对象。
**下一步:**在创建报表编辑器(如果需要,包括其用户界面)和报表呈现器后,部署扩展,如如何:手动注册 PerformancePoint Services 扩展中所述。有关如何安装和配置示例报表扩展的说明,请参阅代码示例:自定义报表、筛选器和表格数据源对象中的"安装示例报表、筛选器和数据源对象"一节。
示例
以下代码示例在库中创建、检索和更新自定义报表并为 ASPX 页中定义的控件提供编程逻辑。
备注
在编译此代码示例之前,您必须配置开发环境,如创建和配置编辑器类中所述。
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.PerformancePoint.Scorecards;
using Microsoft.PerformancePoint.Scorecards.ServerCommon;
namespace Microsoft.PerformancePoint.SDK.Samples.SampleReport
{
// Represents the class that defines the sample report editor.
public class SampleReportViewEditor : Page
{
// Declare private variables for the ASP.NET controls defined in the user interface.
// The sample's user interface is an ASPX page that defines the controls in HTML.
private TextBox textboxName;
private TextBox textboxDescription;
private Label labelErrorMessage;
private Button buttonOK;
// Make the controls available to this class.
protected override void CreateChildControls()
{
base.CreateChildControls();
if (null == textboxName)
textboxName = FindControl("textboxName") as TextBox;
if (null == textboxDescription)
textboxDescription = FindControl("textboxDescription") as TextBox;
if (null == labelErrorMessage)
labelErrorMessage = FindControl("labelErrorMessage") as Label;
if (null == buttonOK)
buttonOK = FindControl("buttonOK") as Button;
}
// Handles the Load event of the Page control.
// Methods that use a control variable should call the Control.EnsureChildControls
// method before accessing the variable for the first time.
protected void Page_Load(object sender, EventArgs e)
{
// Required to enable custom report and filter editors to
// write data to the repository.
ServerUtils.AllowUnsafeUpdates = true;
// Initialize controls the first time the page loads only.
if (!IsPostBack)
{
EnsureChildControls();
ReportViewRepositoryHelper reportviewRepositoryHelper = null;
try
{
// Get information from the query string parameters.
string server = Request.QueryString[ClickOnceLaunchKeys.SiteCollectionUrl];
string itemLocation = Request.QueryString[ClickOnceLaunchKeys.ItemLocation];
string action = Request.QueryString[ClickOnceLaunchKeys.LaunchOperation];
// Validate the query string parameters.
if (string.IsNullOrEmpty(server) ||
string.IsNullOrEmpty(itemLocation) ||
string.IsNullOrEmpty(action))
{
displayError("Invalid URL.");
return;
}
// Retrieve the repository-helper object.
reportviewRepositoryHelper =
new ReportViewRepositoryHelper();
// Set the report location by using the location from the query string.
RepositoryLocation repositoryReportViewLocation = RepositoryLocation.CreateFromUriString(itemLocation);
ReportView reportview;
// Retrieve or create the report object, depending on the operation
// passed in the query string (OpenItem or CreateItem).
if (ClickOnceLaunchValues.OpenItem.Equals(action, StringComparison.OrdinalIgnoreCase))
{
// Retrieve the report object by using the repository-helper object.
reportview = reportviewRepositoryHelper.Get(repositoryReportViewLocation);
if (reportview == null)
{
displayError("Could not retrieve the report view for editing.");
return;
}
}
else if (ClickOnceLaunchValues.CreateItem.Equals(action, StringComparison.OrdinalIgnoreCase))
{
// Create a report view.
// CreateItem requests can be sent from a SharePoint list, but
// you must create a custom menu item to send the request.
// Dashboard Designer can send edit requests only.
reportview = new ReportView
{
RendererClassName = typeof(SampleReportRenderer).AssemblyQualifiedName,
SubTypeId = "SampleReportView"
};
}
else
{
displayError("Invalid Action.");
return;
}
VerifyReportView(reportview);
// Save the original report and helper objects across page postbacks.
ViewState["action"] = action;
ViewState["reportview"] = reportview;
ViewState["reportviewrepositoryhelper"] = reportviewRepositoryHelper;
ViewState["itemlocation"] = itemLocation;
// Populate the child controls.
textboxName.Text = reportview.Name.ToString();
textboxDescription.Text = reportview.Description.ToString();
}
catch (Exception ex)
{
displayError("An error has occurred. Please contact your administrator for more information.");
if (reportviewRepositoryHelper != null)
{
// Add the exception detail to the server event log.
reportviewRepositoryHelper.HandleException(ex);
}
}
}
}
// Handles the Click event of the buttonOK control.
protected void buttonOK_Click(object sender, EventArgs e)
{
EnsureChildControls();
// Verify that the textboxName control contains a value.
if (string.IsNullOrEmpty(textboxName.Text))
{
labelErrorMessage.Text = "A report view name is required.";
return;
}
// Clear any pre-existing error message.
labelErrorMessage.Text = string.Empty;
// Retrieve the report and helper objects from view state.
string action = (string)ViewState["action"];
string itemLocation = (string) ViewState["itemlocation"];
ReportView reportview = (ReportView)ViewState["reportview"];
ReportViewRepositoryHelper reportviewRepositoryHelper = (ReportViewRepositoryHelper)ViewState["reportviewrepositoryhelper"];
// Update the report object with form changes.
reportview.Name.Text = textboxName.Text;
reportview.Description.Text = textboxDescription.Text;
// Save the report object to the PerformancePoint Services repository.
try
{
reportview.Validate();
if (ClickOnceLaunchValues.CreateItem.Equals(action, StringComparison.OrdinalIgnoreCase))
{
reportview.CreatedDate = DateTime.Now;
ReportView newReportView = reportviewRepositoryHelper.Create(
string.IsNullOrEmpty(reportview.Location.ItemUrl) ? itemLocation : reportview.Location.ItemUrl,
reportview);
ViewState["reportview"] = newReportView;
ViewState["action"] = ClickOnceLaunchValues.OpenItem;
}
else
{
reportviewRepositoryHelper.Update(reportview);
}
}
catch (Exception ex)
{
displayError("An error has occurred. Please contact your administrator for more information.");
if (reportviewRepositoryHelper != null)
{
// Add the exception detail to the server event log.
reportviewRepositoryHelper.HandleException(ex);
}
}
}
// Displays the error string in the labelErrorMessage label.
void displayError(string msg)
{
EnsureChildControls();
labelErrorMessage.Text = msg;
// Disable the OK button because the page is in an error state.
buttonOK.Enabled = false;
return;
}
// Verifies that the properties for the report object are set.
static void VerifyReportView(ReportView reportview)
{
// Verify that all required properties are set.
if (string.IsNullOrEmpty(reportview.SubTypeId))
{
// This value must match the subType attribute specified
// in the web.config file.
reportview.SubTypeId = "SampleReportView";
}
if (string.IsNullOrEmpty(reportview.RendererClassName))
{
reportview.RendererClassName = typeof (SampleReportRenderer).AssemblyQualifiedName;
}
// Reports are consumers and do not use provider endpoints.
reportview.BeginPoints.Clear();
// If there are no consumer endpoints, create one so we can connect a filter or a scorecard to the report.
if (0 == reportview.EndPoints.Count)
{
EndPoint endpoint = new EndPoint
{
Category = EndPointCategory.None,
UniqueName = "SampleReportView_EndPoint",
// The display name is shown to users in Dashboard
// Designer to represent the endpoint that can be
// connected to a filter or scorecard.
DisplayName = "Sample Report View EndPoint"
};
reportview.EndPoints.Add(endpoint);
}
// Set optional properties for reports.
reportview.CustomData = "You can use this property to store custom information for this filter as a string or a serialized object.";
}
}
}
编译代码
在编译此代码示例之前,您必须配置开发环境,如创建和配置编辑器类中所述。
安全性
必须使用强名称对 DLL 进行签名。另外,确保 DLL 引用的所有程序集都具有强名称。有关如何使用强名称对程序集进行签名以及如何创建公钥/私钥对的信息,请参阅How to: Create a Public/Private Key Pair。
请参阅
任务
如何:为 PerformancePoint Services 报告创建呈现器
概念
用于自定义 PerformancePoint Services 对象的编辑器