在 SharePoint 中创建 PerformancePoint Services 报表编辑器

了解如何为 PerformancePoint Services 创建自定义报表扩展的编辑器组件。

什么是 PerformancePoint Services 的自定义报表编辑器?

在 PerformancePoint Services 中,自定义报表编辑器可让用户在自定义报表上设置属性。 报表编辑器还会初始化报表终结点,报表终结点将从记分卡和筛选器提供程序接收参数值。 有关编辑器要求和功能的详细信息,请参阅 用于自定义 PerformancePoint Services 对象的编辑器

下面的过程和示例以自定义对象示例中的 SampleReportViewEditor 类为依据。 借助编辑器这一精简 Web 应用,用户可以修改报表名称和说明。 有关 类的完整代码,请参阅代码示例:在 SharePoint 中创建、检索和更新自定义PerformancePoint Services报表

我们建议您将示例编辑器用作模板。 该示例演示了如何调用 PerformancePoint Services API 中的对象,提供了简化库操作(例如创建和更新对象)调用的帮助程序对象,并演示了 PerformancePoint Services 开发的最佳实践。

为自定义 PerformancePoint Services 报表创建编辑器

  1. 安装 PerformancePoint Services,或者将您的扩展使用的 DLL(步骤 3 中列出)复制到您的计算机上。 有关详细信息,请参阅 具有类库的 DLL

  2. 在 Visual Studio 中,创建一个 C# 类库。 如果您已为扩展创建了一个类库,请添加新 C# 类。

    您必须用强名称对您的 DLL 进行签名。 此外,请确保您的 DLL 所引用的所有程序集都具有强名称。 有关如何使用强名称对程序集进行签名以及如何创建公钥/私钥对的信息,请参阅 How to: Create a public/private key pair

  3. 将以下 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 的程序集引用。 根据您的扩展的功能,可能需要其他项目引用。

  4. 将示例中的以下类添加到项目中。 编辑器使用这些帮助程序类来与 PerformancePoint Services 存储库进行交互:

    • DataSourceConsumerHelper.cs
    • ExtensionRepositoryHelper.cs
    • ReportViewRepositoryHelper.cs
    • IDataSourceConsumer.cs

    注意

    由于示例报表是从筛选器获取数据,因此未使用 DataSourceConsumerHelperIDataSourceConsumer 对象。 但是,如果报表从PerformancePoint Services数据源获取数据,则可以使用 DataSourceConsumerHelper 类公开的方法检索数据源,如在 SharePoint 中创建PerformancePoint Services筛选器编辑器中所述。

  5. 在编辑器类中,为以下 PerformancePoint Services 命名空间添加 using 指令:

    • Microsoft.PerformancePoint.Scorecards
    • Microsoft.PerformancePoint.Scorecards.ServerCommon

    根据您的扩展的功能,可能需要其他 using 指令。

  6. 从支持您的编辑器实现的基类继承。 由于示例报表编辑器是 Web 应用程序,因此它继承自 Page 类。 其他实现可从基类(例如 UserControlWebPart 类)派生。

  7. 声明公开您希望用户查看或修改的属性的控件的变量。 示例报表编辑器首先声明用户界面组件(这是一个 ASPX 页)中定义的 Web 服务器控件的变量。 示例编辑器还定义使用户能够提交更改的按钮控件。 然后,编辑器调用 CreateChildControls () 方法,使控件在页面上可用。

    注意

    编辑器独立于用户界面定义编程逻辑。 有关创建编辑器的用户界面组件的说明不在本文档的讨论范围内。

    示例报表编辑器在 Page_Load 方法中执行步骤 8 至 12。 Page_Load 还用于初始化和验证变量和控件、填充控件以及保存自定义报表和帮助程序对象的状态信息。

  8. AllowUnsafeUpdates 属性设置为 true。 这使报表编辑器能够将数据写入存储库中,而无需使用表单 POST 操作。

  9. 从查询字符串中检索参数,并将它们设置为本地变量值,如下面的代码示例所示。

    // 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对象的编辑器

  10. 检索用于调用存储库的 ReportViewRepositoryHelper 对象,如下面的代码示例所示。

    reportviewRepositoryHelper = new ReportViewRepositoryHelper();
    
  11. 基于查询字符串参数设置报表位置,如以下代码示例中所示。

    RepositoryLocation repositoryReportViewLocation = RepositoryLocation.CreateFromUriString(itemLocation);
    
  12. 从查询字符串检索要执行的操作( OpenItemCreateItem),然后检索或创建自定义报表。

    • 若要检索自定义报表,请使用 ReportViewRepositoryHelper.Get 方法。
    • 若要创建自定义报表,请使用 ReportView() 构造函数,然后定义报表的 NameRendererClassNameSubTypeId 属性。

    SubTypeId 是报表的唯一标识符,它必须与您在 PerformancePoint Services web.config 文件中为自定义报表指定的 subType 属性相匹配。 RendererClassName 是定义呈现器 Web 服务器控件的类的完全限定名称。 如果没有在编辑器中定义,则此值默认为 web.config 文件中指定的呈现器类。

    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;
    }
    

    注意

    默认情况下,用户只能从 PerformancePoint 仪表板设计器创建自定义对象。 若要使用户能够在仪表板设计器外部创建自定义对象,必须添加一个菜单项,用于从存储库中的内容类型向编辑器发送 CreateItem 请求。 有关详细信息,请参阅 用于自定义 PerformancePoint Services 对象的编辑器

  13. 定义报表的终结点,这使报表能够从筛选器和记分卡检索数据。 示例报表编辑器定义了所需的端点属性,如以下代码示例中所示。

    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 属性,后者可用来存储报表信息。

  14. 使用用户定义的更改来更新报表。 示例报表编辑器中的 buttonOK_Click 方法调用 ReportViewRepositoryHelper.Update 方法来更新库中报表的 NameDescription 属性。 buttonOK_Click 还用于验证控件内容并检索自定义报表和帮助程序对象的状态信息。

    注意

    用户可以编辑自定义对象的名称说明所有者 (负责人) 属性,并直接从仪表板设计器和PerformancePoint Services存储库中删除自定义对象。

代码示例:在 SharePoint 中创建、检索和更新自定义 PerformancePoint Services 报表

以下代码示例创建、检索和更新自定义报表。 此代码来自为 ASPX 页中定义的控件提供编程逻辑的代码隐藏类。

在编译此代码示例之前,必须按照为自定义PerformancePoint Services报表创建编辑器中所述配置开发环境。

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.";
        }
    }
}

后续步骤

创建报表编辑器 (包括其用户界面后,如果需要) 和报表呈现器,请部署扩展,如如何:手动注册PerformancePoint Services扩展中所述。

另请参阅