You can create customized objects that live within
the PPS world, are available from within Dashboard Designer, and can
interact with or supply data to other PPS objects. This proves useful in
the following three cases, for example:
- Creating a custom tabular data source and having the data source used in KPIs, scorecards, and filters
- Creating a custom report type and linking it on a dashboard with a filter
- Creating a custom filter that does not depend on a data source like native PPS filters do
Creating a Custom Tabular Data Source
You can create custom
tabular data sources for data sources to be used in PPS filters, KPIs,
and scorecards. The three steps to creating and using a custom tabular
data source are as follows:
1. | Create a signed class library for the custom tabular data source provider.
Note
The signing is necessary to generate a strongly named assembly and class that will later be used when deploying to SharePoint.
|
2. | Create an editor for custom tabular data source objects.
|
3. | Deploy
the data source and its associated editor by modifying the web.config
file, adding necessary files to the GAC, and deploying .aspx files to
the layouts folder.
|
After you complete these
steps, the custom tabular data source shows up as an available data
source within Dashboard Designer and is usable just like tabular data
sources that ship with PPS, such as SQL tables and SharePoint lists.
Caution
PPS supports only tabular
custom data source providers. You cannot create a multidimensional or
OLAP custom data source provider.
Creating a Class Library for the Custom Tabular Data Source Provider
Custom
tabular data source providers must implement the
Microsoft.PerformancePoint.Scorecards.DataSourceProviders.TabularDataSourceProvider
abstract class. The first step to create a custom tabular data source
provider is to create a new class library project in Visual Studio. In
this example, we create a simple example custom tabular data source that
reads files from a directory.
Caution
Make sure to set the Target
framework of the project to .NET Framework 3.5 or lower. If you set the
target framework to .NET 4.0, PPS cannot discover this assembly in the
GAC at runtime.
You can have multiple
custom tabular data sources or other custom objects defined in this one
assembly. Create a new CS class file with these using statements at the
top.
using Microsoft.PerformancePoint.Scorecards;
using Microsoft.PerformancePoint.Scorecards.DataSourceProviders;
A friendly name set in
the web.config file controls what the end user sees, so you can call
your class name whatever you would like. Ensure it inherits from the TabularDataSourceProvider class:
public class FileSystemDataSource : TabularDataSourceProvider
Several methods need to be overridden. The order they appear in the class does not matter:
GetId Method
The GetId
method contains the unique identifier in a string format. The string
value that this method returns is used later when modifying the
web.config file. In most cases, it is sufficient to return a hardcoded
string like this:
public override string GetId()
{
return "FileSystemDataSource";
}
SetDataSource Method
The SetDataSource
method defines the Dimensions and Fact columns available in this data
source. This is roughly equivalent to the column definition user
interface (UI) available when editing a PPS-supplied data source, such
as a SQL table or SharePoint list, as the same options are available for
each column. In this example, we define three columns: two dimension
columns named Name and Type, which contain the filename and file
extension, respectively, and a fact column that contains the file size:
Note
This method is called
frequently. For great performance optimization, configure this method
only if it is not already configured for the data source.
public override void SetDataSource(DataSource dataSource)
{
base.SetDataSource(dataSource);
// We only want to define column mappings if they haven't already been defined
if (dataSource.DataTableMapping.ColumnMappings.Count <= 0)
{
dataSource.DataTableMapping.ColumnMappings.Add(new DataColumnMapping
{
SourceColumnName = "Name",
FriendlyColumnName = "Name",
UniqueName = "Name",
ColumnType = MappedColumnTypes.Dimension,
FactAggregation = FactAggregations.None,
ColumnDataType = MappedColumnDataTypes.String
});
dataSource.DataTableMapping.ColumnMappings.Add(new DataColumnMapping
{
SourceColumnName = "Type",
FriendlyColumnName = "Type",
UniqueName = "Type",
ColumnType = MappedColumnTypes.Dimension,
FactAggregation = FactAggregations.None,
ColumnDataType = MappedColumnDataTypes.String
});
dataSource.DataTableMapping.ColumnMappings.Add(new DataColumnMapping
{
SourceColumnName = "FileSize",
FriendlyColumnName = "FileSize",
UniqueName = "FileSize",
ColumnType = MappedColumnTypes.Fact,
FactAggregation = FactAggregations.Sum,
ColumnDataType = MappedColumnDataTypes.Number
});
}
}
GetDataSet Method
The GetDataSet method is the method that actually does the work. We need to create a DataSet that matches the column schema that SetDataSource defines. After that DataSet object is created, it is necessary to fill the rows in the table with the correct data before finally returning the DataSet object:
Tip
This implementation uses a property inherited from the TabularDataSourceProvider base class named DataSource.CustomData. The CustomData
field is the preferred mechanism to store user supplied data and is
available as a field to change when implementing a custom tabular data
source editor.
Depending on what type of data
source you want to implement, it might be necessary to store data here
in XML or otherwise delimited format if there are multiple values that a
user would need to supply to the data source.
public override DataSet GetDataSet()
{
DataSet myDataSet = new DataSet();
DataTable myTable = myDataSet.Tables.Add();
myTable.Columns.Add("Name", typeof(string));
myTable.Columns.Add("Type", typeof(string));
myTable.Columns.Add("FileSize", typeof(int));
foreach (string filePath in Directory.GetFiles(DataSource.CustomData))
{
FileInfo oneFile = new FileInfo(filePath);
DataRow oneRow = myTable.NewRow();
oneRow["Name"] = oneFile.Name;
oneRow["Type"] = oneFile.Extension;
oneRow["FileSize"] = oneFile.Length;
myTable.Rows.Add(oneRow);
}
return myDataSet;
}
Several other methods
also need to be implemented to allow successful compilation. These
methods are all not used in any fashion in PPS, so they can all throw NotImplementedExceptions:
Tip
The IsConnectionStringSecure method is a carryover from PPS 2007, and given the new extensibility model is deprecated.
The other methods are inherited from the CustomDataSourceProvider class, which is a base class for the TabularDataSourceProvider class. It is a bug in PPS where these methods should not be virtual methods in the TabularDataSourceProvider class. These methods would be called in the case of a custom multidimensional data source, which is not supported in PPS 2010.
public override bool IsConnectionStringSecure
{
get { return false; }
}
public override void Validate()
{
throw new NotImplementedException();
}
public override string[] GetDatabaseNames()
{
throw new NotImplementedException();
}
public override string[] GetCubeNames()
{
throw new NotImplementedException();
}
public override NameInfoCollection GetCubeNameInfos()
{
throw new NotImplementedException();
}
public override Cube GetCubeMetaData(bool extendedMetadata)
{
throw new NotImplementedException();
}
Signing the Assembly
If you use Visual Studio
2010, you can easily assign the assembly. View the properties of the
Class Library project, and in the Signing tab create a new strong name
key file or select an existing one from the list. Figure 1 shows what this looks like.