Tuesday, April 22, 2008

Browsable Attribute/Property of Custom Activity in ASP.Net Workflow

In continuation with my earlier article Custom Activity in ASP.Net Workflow

1) To add a browsable attribute/property in your custom activity, you have insert following code in your custom activity class:


public static DependencyProperty OwnerNameProperty = DependencyProperty.Register("OwnerName", typeof(string), typeof(MyActivity), new PropertyMetadata(DependencyPropertyOptions.Metadata, new Attribute[] { new ValidationOptionAttribute(ValidationOption.Required) }));

[DescriptionAttribute("OwnerName")]
[CategoryAttribute("Input")]
[BrowsableAttribute(true)]
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
public string OwnerName
{
get
{
return ((string)(base.GetValue(MyActivity.OwnerNameProperty)));
}
set
{
base.SetValue(MyActivity.OwnerNameProperty, value);
}
}

Here the custom property name is “OwnerName”.

2) You can access your property in your custom activity, by simply access it like “this.PropertyName”. E.g,


Console.WriteLine("OwnerName : " + this.OwnerName);

In my case, I have inserted the above code in Activity’s “Execute” method.

3) After doing the required changes. To test your custom property, remove your activity from workflow designer and again Drag-n-Drop in Workflow designer from toolbox. Now to set your property, select the activity in workflow designer. In properties window, you will see your custom property against your custom activity. Here you will see “OwnerName” property in “MyActivity”.



4) After setting the property, rebuild the whole application, i.e. Workflow and Console application project. Run the console application. Following is the output window of console application:


Monday, April 21, 2008

Custom Activity in ASP.Net Workflow

1) Open .Net IDE, create a new project. Select “Sequential Workflow Library” under Workflow project template in “New Project” dialog box.





2) Rename workflow class to your desired class name. In my case I renamed it to “MyWorkflow” from “Workflow1”.



3) Create a folder named “Actvity” where you can place your custom activities. Click the “Activity” menu that appears when you try adding new item in Actvity folder in solution explorer.




4) Select “Activity” class template from “Add New Item” dialog box. Rename the activity class to your desired one.




5) In activity class override the “Execute” method. Write your own code in that Execute method.

protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
Console.WriteLine("This is my custom Actvity");

return base.Execute(executionContext);
}


6) Build/Save the application to see your custom activity in the Workflow designer toolbox.




7) Drag-n-Drop your custom activity from toolbox to your workflow designer area.
Rename the activity name if you want.




8) This Drag-n-Drop action will insert the code automatically in “MyWorkflow.Designer.cs” file. Here you can modify the code if you want.

#region Designer generated code

///
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
///

[System.Diagnostics.DebuggerNonUserCode]
private void InitializeComponent()
{
this.CanModifyActivities = true;
this.MyActivity = new MyWorkFlow.Activity.MyActivity();
//
// MyActivity
//
this.MyActivity.Name = "MyActivity";
//
// MyWorkflow
//
this.Activities.Add(this.MyActivity);
this.Name = "MyWorkflow";
this.CanModifyActivities = false;

}

#endregion


9) Now comes the part to consume your custom workflow and custom activity. Add a new console project in your solution explorer.



10) Add references for following two dlls in your Console Application reference section:
a. System.Workflow.Activities
b. System.Workflow.ComponentModel
c. System.Workflow.Runtime
Add project reference of your Custom Workflow project, so that you need not to add your Workflow project dll again and again after each modification.


11) Add following “using” directive in your console application class:
a) using System.Threading;
b) using System.Workflow.Runtime;
c) using System.Workflow.Runtime.Hosting;

12) Add following code in your “Main” method:


using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
{
AutoResetEvent waitHandle = new AutoResetEvent(false);

workflowRuntime.WorkflowCompleted +=
delegate(object sender, WorkflowCompletedEventArgs e)
{
waitHandle.Set();
};

workflowRuntime.WorkflowTerminated +=
delegate(object sender, WorkflowTerminatedEventArgs e)
{
Console.WriteLine(e.Exception.Message);
waitHandle.Set();
};

WorkflowInstance instance =
workflowRuntime.CreateWorkflow(typeof(MyWorkFlow.MyWorkflow));
instance.Start();

waitHandle.WaitOne();
}

The above code adds your custom workflow instance in your console application.

13) Before testing the whole application, you have set your Console application project as “StartUp Project”. You can set your project as StartUp Project by clicking the desired project in solution explorer and click the “Set as StartUp Project” menu.

Also write following code as a last line in your Console application’s main method:

Console.ReadLine();

The above code keep the console screen open, for getting the user response.

14) Now run the application, you will get following console screen:


The above message is written in your Custom activity “Execute” method.

Friday, April 18, 2008

OLAP Cube generation programmatically in C#

OLAP cube generation is divided into 6 major steps:

1) Connect to the Analysis Services :
    Create a connection of AnalysisServices server.

2) Create a Database :
    Create a database in AnalysisServices server and save it.

3) Create a DataSource :
    Add a datasource to the database and set its connection string.

4) Create a DataSourceView :
    a) Create a DataSet.
    b) Add Fact tables in DataSet.
    c) Add Dimension tables in DataSet and Relation between them.
    d) Create a DataSourceView based on the created DataSet.

5) Create the Dimension, Attribute, Hierarchy, and MemberProperty Objects :
    a) Add Dimension to the Database.
    b) Add Dimension Attributes.
    c) Set Attribute usage and source.

6) Create the Cube, MeasureGroup, Measure, and Partition Objects :
    a) Add Cube to the Database and set Cube source to the Data Source View.
    b) Add Measure Group to the Cube.
    c) Add Measure to the Measure Group and set Measure source.
    d) Generate Cube :
        A) Add Dimension to the Cube.
        B) Use Regular Relationship Between Dimension and FactTable Measure Group.
        C) Link TableKey in DimensionTable with TableKey in FactTable Measure Group.
    d) Save Cube and all major objects to the Analysis Services.


After creating the cube, process the cube programmatically else we can process it manually from AnalysisServices Server.


To test the above implementation :
1) Create a console application.
2) Add DLL reference of Microsoft.AnalysisServices and Microsoft.SqlServer.Smo
3) Add CubeGenerator.cs file in project (or copy the code snippet given at the end of this article).
4) Run the Console Application.
    Console window will displays various steps of cube generationg. Press key to exit the application.



We can see the newly generated cube in AnalysisServices server. Drag-n-Drop the Dimension tables and Fact table to see the Cube.




Note : The mentioned code here is self explainatory and commented to understand the cube generation logic.


Following is the complete code snippet to create the OLAP cube programmatically in C# ( for better readability click here ):




using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.AnalysisServices;
using System.Data.SqlClient;
using System.Data;
using System.Data.OleDb;

namespace OLAPCube
{
class CubeGenerator
{
static void Main(string[] args)
{
BuildCube();
}

#region Cube Generation.

private static void BuildCube()
{
try
{
Console.WriteLine("Cube creation process started.");
Console.WriteLine("");

string strDBServerName = "LocalHost";
string strProviderName = "msolap";
string strFactTableName = "FactResellerSales";
string strDBName = "AdventureWorksDW";
string strCubeDBName = "OLAPDB";
string strCubeDataSourceName = "OLAPDS";
string strCubeDataSourceViewName = "OLAPDSView";
int intDimensionTableCount = 6;

string[,] strTableNamesAndKeys = { { "DimCurrency", "CurrencyKey", "FactResellerSales", "CurrencyKey" },
{ "DimEmployee", "EmployeeKey", "FactResellerSales", "EmployeeKey" },
{ "DimProduct", "ProductKey", "FactResellerSales", "ProductKey" },
{ "DimPromotion", "PromotionKey", "FactResellerSales", "PromotionKey" },
{ "DimReseller", "ResellerKey", "FactResellerSales", "ResellerKey" },
{ "DimSalesTerritory", "SalesTerritoryKey", "FactResellerSales", "SalesTerritoryKey" },
};


Server objServer = new Server();
Database objDatabase = new Database();
RelationalDataSource objDataSource = new RelationalDataSource();
DataSourceView objDataSourceView = new DataSourceView();
DataSet objDataSet = new DataSet();
Dimension[] objDimensions = new Dimension[intDimensionTableCount];

//Connecting to the Analysis Services.
objServer = (Server)ConnectAnalysisServices(strDBServerName, strProviderName);
//Creating a Database.
objDatabase = (Database)CreateDatabase(objServer, strCubeDBName);
//Creating a DataSource.
objDataSource = (RelationalDataSource)CreateDataSource(objServer, objDatabase, strCubeDataSourceName, strDBServerName, strDBName);
//Creating a DataSourceView.
objDataSet = (DataSet)GenerateDWSchema(strDBServerName, strDBName, strFactTableName, strTableNamesAndKeys, intDimensionTableCount);
objDataSourceView = (DataSourceView)CreateDataSourceView(objDatabase, objDataSource, objDataSet, strCubeDataSourceViewName);
//Creating the Dimension, Attribute, Hierarchy, and MemberProperty Objects.
objDimensions = (Dimension[])CreateDimension(objDatabase, objDataSourceView, strTableNamesAndKeys, intDimensionTableCount);
//Creating the Cube, MeasureGroup, Measure, and Partition Objects.
CreateCube(objDatabase, objDataSourceView, objDataSource, objDimensions, strFactTableName, strTableNamesAndKeys, intDimensionTableCount);

objDatabase.Process(ProcessType.ProcessFull);

Console.WriteLine("Cube created successfully.");
}
catch (Exception ex)
{
Console.WriteLine("Error -> " + ex.Message);
}

Console.WriteLine("");
Console.WriteLine("Press any key to exit.");
Console.ReadLine();
}

#region Connecting to the Analysis Services.
/// <summary>
/// Connecting to the Analysis Services.
/// </summary>
/// <param name="strDBServerName">Database Server Name.</param>
/// <param name="strProviderName">Provider Name.</param>
/// <returns>Database Server instance.</returns>
private static object ConnectAnalysisServices(string strDBServerName, string strProviderName)
{
try
{
Console.WriteLine("Connecting to the Analysis Services ...");

Server objServer = new Server();
string strConnection = "Data Source=" + strDBServerName + ";Provider=" + strProviderName + ";";
//Disconnect from current connection if it's currently connected.
if (objServer.Connected)
objServer.Disconnect();
else
objServer.Connect(strConnection);

return objServer;
}
catch (Exception ex)
{
Console.WriteLine("Error in Connecting to the Analysis Services. Error Message -> " + ex.Message);
return null;
}
}
#endregion Connecting to the Analysis Services.

#region Creating a Database.
/// <summary>
/// Creating a Database.
/// </summary>
/// <param name="objServer">Database Server Name.</param>
/// <param name="strCubeDBName">Cube DB Name.</param>
/// <returns>DB instance.</returns>
private static object CreateDatabase(Server objServer, string strCubeDBName)
{
try
{
Console.WriteLine("Creating a Database ...");

Database objDatabase = new Database();
//Add Database to the Analysis Services.
objDatabase = objServer.Databases.Add(objServer.Databases.GetNewName(strCubeDBName));
//Save Database to the Analysis Services.
objDatabase.Update();

return objDatabase;
}
catch (Exception ex)
{
Console.WriteLine("Error in Creating a Database. Error Message -> " + ex.Message);
return null;
}
}
#endregion Creating a Database.

#region Creating a DataSource.
/// <summary>
/// Creating a DataSource.
/// </summary>
/// <param name="objServer">Database Server Name.</param>
/// <param name="objDatabase">Database Name.</param>
/// <param name="strCubeDataSourceName">Cube DataSource Name.</param>
/// <param name="strDBServerName">DB Server Name.</param>
/// <param name="strDBName">DB Name.</param>
/// <returns>DataSource instance.</returns>
private static object CreateDataSource(Server objServer, Database objDatabase, string strCubeDataSourceName, string strDBServerName, string strDBName)
{
try
{
Console.WriteLine("Creating a DataSource ...");
RelationalDataSource objDataSource = new RelationalDataSource();
//Add Data Source to the Database.
objDataSource = objDatabase.DataSources.Add(objServer.Databases.GetNewName(strCubeDataSourceName));
//objDataSource.ConnectionString = "Provider=SQLOLEDB.1;Initial Catalog=AdventureWorksDW;Data Source=LocalHost;Integrated Security=True;";
objDataSource.ConnectionString = "Provider=SQLNCLI.1; Data Source=" + strDBServerName + "; Initial Catalog=" + strDBName + "; Integrated Security=SSPI;";
objDataSource.Update();

return objDataSource;
}
catch (Exception ex)
{
Console.WriteLine("Error in Creating a DataSource. Error Message -> " + ex.Message);
return null;
}
}
#endregion Creating a DataSource.

#region Creating a DataSourceView.
/// <summary>
/// Creating a DataSourceView.
/// </summary>
/// <param name="strDBServerName">DB Server Name.</param>
/// <param name="strDBName">DB Name.</param>
/// <param name="strFactTableName">FactTable Name.</param>
/// <param name="strTableNamesAndKeys">Array of TableNames and Keys.</param>
/// <param name="intDimensionTableCount">Dimension Table Count.</param>
/// <returns>DataSet instance.</returns>
private static object GenerateDWSchema(string strDBServerName, string strDBName, string strFactTableName, string[,] strTableNamesAndKeys, int intDimensionTableCount)
{
try
{
Console.WriteLine("Creating a DataSourceView ...");
//Create the connection string.
string conxString = "Data Source=" + strDBServerName + "; Initial Catalog=" + strDBName + "; Integrated Security=True;";
//Create the SqlConnection.
SqlConnection objConnection = new SqlConnection(conxString);
DataSet objDataSet = new DataSet();
//Add FactTable in DataSet.
objDataSet = (DataSet)FillDataSet(objConnection, objDataSet, strFactTableName);
//Add table in DataSet and Relation between them.
for (int i = 0; i < intDimensionTableCount; i++)
{
//Retrieve table's schema and assign the table's schema to the DataSet.
//Add primary key to the schema according to the primary key in the tables.
objDataSet = (DataSet)FillDataSet(objConnection, objDataSet, strTableNamesAndKeys[i, 0]);
objDataSet = (DataSet)AddDataTableRelation(objDataSet, strTableNamesAndKeys[i, 0], strTableNamesAndKeys[i, 1], strTableNamesAndKeys[i, 2], strTableNamesAndKeys[i, 3]);
}

return objDataSet;
}
catch (Exception ex)
{
Console.WriteLine("Error in Creating a DataSourceView - GenerateDWSchema. Error Message -> " + ex.Message);
return null;
}
}
/// <summary>
/// Fill the DataSet with DataTables.
/// </summary>
/// <param name="objConnection">Connection instance.</param>
/// <param name="objDataSet">DataSet instance.</param>
/// <param name="strTableName">TableName.</param>
/// <returns>DataSet instance.</returns>
private static object FillDataSet(SqlConnection objConnection, DataSet objDataSet, string strTableName)
{
try
{
string strCommand = "Select * from " + strTableName;
SqlDataAdapter objEmpData = new SqlDataAdapter(strCommand, objConnection);
objEmpData.MissingSchemaAction = MissingSchemaAction.AddWithKey;
objEmpData.FillSchema(objDataSet, SchemaType.Source, strTableName);

return objDataSet;
}
catch (Exception ex)
{
Console.WriteLine("Error in Creating a DataSourceView - FillDataSet. Error Message -> " + ex.Message);
return null;
}
}
/// <summary>
/// Add relations between DataTables of DataSet.
/// </summary>
/// <param name="objDataSet">DataSet instance.</param>
/// <param name="strParentTableName">Parent Table Name (Dimension Table).</param>
/// <param name="strParentTableKey">Parent Table Key.</param>
/// <param name="strChildTableName">Child Table Name (Fact Table).</param>
/// <param name="strChildTableKey">Child Table Key.</param>
/// <returns>DataSet instance.</returns>
private static object AddDataTableRelation(DataSet objDataSet, string strParentTableName, string strParentTableKey, string strChildTableName, string strChildTableKey)
{
try
{
objDataSet.Relations.Add(strChildTableName + "_" + strParentTableName + "_FK", objDataSet.Tables[strParentTableName].Columns[strParentTableKey], objDataSet.Tables[strChildTableName].Columns[strChildTableKey]);

return objDataSet;
}
catch (Exception ex)
{
Console.WriteLine("Error in Creating a DataSourceView - AddDataTableRelation. Error Message -> " + ex.Message);
return null;
}
}


/// <summary>
/// Creating a DataSourceView.
/// </summary>
/// <param name="objDatabase">DB instance.</param>
/// <param name="objDataSource">DataSource instance.</param>
/// <param name="objDataSet">DataSet instance.</param>
/// <param name="strCubeDataSourceViewName">Cube DataSourceView Name.</param>
/// <returns>DataSourceView instance.</returns>
private static object CreateDataSourceView(Database objDatabase, RelationalDataSource objDataSource, DataSet objDataSet, string strCubeDataSourceViewName)
{
try
{
DataSourceView objDataSourceView = new DataSourceView();
//Add Data Source View to the Database.
objDataSourceView = objDatabase.DataSourceViews.Add(objDatabase.DataSourceViews.GetNewName(strCubeDataSourceViewName));
objDataSourceView.DataSourceID = objDataSource.ID;
objDataSourceView.Schema = objDataSet;
objDataSourceView.Update();

return objDataSourceView;
}
catch (Exception ex)
{
Console.WriteLine("Error in Creating a DataSourceView - CreateDataSourceView. Error Message -> " + ex.Message);
return null;
}
}
#endregion Creating a DataSourceView.

#region Creating a Creating the Dimension, Attribute, Hierarchy, and MemberProperty Objects.
/// <summary>
/// Creating the Dimension, Attribute, Hierarchy, and MemberProperty Objects.
/// </summary>
/// <param name="objDatabase">DB instance.</param>
/// <param name="objDataSourceView">DataSource instance.</param>
/// <param name="strTableNamesAndKeys">Array of Table names and keys.</param>
/// <param name="intDimensionTableCount">Dimension table count.</param>
/// <returns>Dimension Array.</returns>
private static object[] CreateDimension(Database objDatabase, DataSourceView objDataSourceView, string[,] strTableNamesAndKeys, int intDimensionTableCount)
{
try
{
Console.WriteLine("Creating the Dimension, Attribute, Hierarchy, and MemberProperty Objects ...");

Dimension[] objDimensions = new Dimension[intDimensionTableCount];
for (int i = 0; i < intDimensionTableCount; i++)
{
objDimensions[i] = (Dimension)GenerateDimension(objDatabase, objDataSourceView, strTableNamesAndKeys[i, 0], strTableNamesAndKeys[i, 1]);
}

////Add Hierarchy and Level
//Hierarchy objHierarchy = objDimension.Hierarchies.Add("ProductByCategory");
//objHierarchy.Levels.Add("Category").SourceAttributeID = objCatKeyAttribute.ID;
//objHierarchy.Levels.Add("Product").SourceAttributeID = objProdKeyAttribute.ID;
////Add Member Property
////objProdKeyAttribute.AttributeRelationships.Add(objProdDescAttribute.ID);
//objDimension.Update();

return objDimensions;
}
catch (Exception ex)
{
Console.WriteLine("Error in Creating the Dimension, Attribute, Hierarchy, and MemberProperty Objects. Error Message -> " + ex.Message);
return null;
}
}
/// <summary>
/// Generate single dimension.
/// </summary>
/// <param name="objDatabase">DB instance.</param>
/// <param name="objDataSourceView">DataSourceView instance.</param>
/// <param name="strTableName">Table name.</param>
/// <param name="strTableKeyName">Table key.</param>
/// <returns>Dimension instance.</returns>
private static object GenerateDimension(Database objDatabase, DataSourceView objDataSourceView, string strTableName, string strTableKeyName)
{
try
{
Dimension objDimension = new Dimension();

//Add Dimension to the Database
objDimension = objDatabase.Dimensions.Add(strTableName);
objDimension.Source = new DataSourceViewBinding(objDataSourceView.ID);
DimensionAttributeCollection objDimensionAttributesColl = objDimension.Attributes;
//Add Dimension Attributes
DimensionAttribute objAttribute = objDimensionAttributesColl.Add(strTableKeyName);
//Set Attribute usage and source
objAttribute.Usage = AttributeUsage.Key;
objAttribute.KeyColumns.Add(strTableName, strTableKeyName, OleDbType.Integer);

objDimension.Update();

return objDimension;
}
catch (Exception ex)
{
Console.WriteLine("Error in Creating the Dimension, Attribute, Hierarchy, and MemberProperty Objects - GenerateDimension. Error Message -> " + ex.Message);
return null;
}
}
#endregion Creating a Creating the Dimension, Attribute, Hierarchy, and MemberProperty Objects.

#region Creating the Cube, MeasureGroup, Measure, and Partition Objects.
/// <summary>
/// Creating the Cube, MeasureGroup, Measure, and Partition Objects.
/// </summary>
/// <param name="objDatabase">DB instance.</param>
/// <param name="objDataSourceView">DataSourceView instance.</param>
/// <param name="objDataSource">DataSource instance.</param>
/// <param name="objDimensions">Dimensions array instance.</param>
/// <param name="strFactTableName">FactTable Name.</param>
/// <param name="strTableNamesAndKeys">Array of Table Names and Keys.</param>
/// <param name="intDimensionTableCount">DimensionTable Count.</param>
private static void CreateCube(Database objDatabase, DataSourceView objDataSourceView, RelationalDataSource objDataSource, Dimension[] objDimensions, string strFactTableName, string[,] strTableNamesAndKeys, int intDimensionTableCount)
{
try
{
Console.WriteLine("Creating the Cube, MeasureGroup, Measure, and Partition Objects ...");
Cube objCube = new Cube();
Measure objSales = new Measure();
Measure objQuantity = new Measure();
MdxScript objTotal = new MdxScript();
String strScript;

Partition objPartition = new Partition();
Command objCommand = new Command();
//Add Cube to the Database and set Cube source to the Data Source View
objCube = objDatabase.Cubes.Add("SampleCube");
objCube.Source = new DataSourceViewBinding(objDataSourceView.ID);
//Add Measure Group to the Cube
//MeasureGroup objMeasureGroup = objCube.MeasureGroups.Add("FactSales");
MeasureGroup objMeasureGroup = objCube.MeasureGroups.Add(strFactTableName);

//Add Measure to the Measure Group and set Measure source
objSales = objMeasureGroup.Measures.Add("Amount");
objSales.Source = new DataItem(strFactTableName, "SalesAmount", OleDbType.Currency);

objQuantity = objMeasureGroup.Measures.Add("Quantity");
objQuantity.Source = new DataItem(strFactTableName, "OrderQuantity", OleDbType.Integer);

////Calculated Member Definition
//strScript = "Calculated; Create Member CurrentCube.[Measures].[Total] As [Measures].[Quantity] * [Measures].[Amount]";
////Add Calculated Member
//objTotal.Name = "Total Sales";
//objCommand.Text = strScript;
//objTotal.Commands.Add(objCommand);
//objCube.MdxScripts.Add(objTotal);

for (int i = 0; i < intDimensionTableCount; i++)
{
GenerateCube(objCube, objDimensions[i], objMeasureGroup, strFactTableName, strTableNamesAndKeys[i, 3]);
}

objPartition = objMeasureGroup.Partitions.Add(strFactTableName);
objPartition.Source = new TableBinding(objDataSource.ID, "dbo", strFactTableName);

objPartition.ProcessingMode = ProcessingMode.Regular;
objPartition.StorageMode = StorageMode.Molap;
//Save Cube and all major objects to the Analysis Services
objCube.Update(UpdateOptions.ExpandFull);
}
catch (Exception ex)
{
Console.WriteLine("Error in Creating the Cube, MeasureGroup, Measure, and Partition Objects. Error Message -> " + ex.Message);
}
}
/// <summary>
/// Generate cube.
/// </summary>
/// <param name="objCube">Cube instance.</param>
/// <param name="objDimension">Dimension instance.</param>
/// <param name="objMeasureGroup">MeasureGroup instance.</param>
/// <param name="strFactTableName">FactTable Name.</param>
/// <param name="strTableKey">Table Key.</param>
private static void GenerateCube(Cube objCube, Dimension objDimension, MeasureGroup objMeasureGroup, string strFactTableName, string strTableKey)
{
try
{
CubeDimension objCubeDim = new CubeDimension();
RegularMeasureGroupDimension objRegMGDim = new RegularMeasureGroupDimension();
MeasureGroupAttribute objMGA = new MeasureGroupAttribute();
//Add Dimension to the Cube
objCubeDim = objCube.Dimensions.Add(objDimension.ID);
//Use Regular Relationship Between Dimension and FactTable Measure Group
objRegMGDim = objMeasureGroup.Dimensions.Add(objCubeDim.ID);
//Link TableKey in DimensionTable with TableKey in FactTable Measure Group
objMGA = objRegMGDim.Attributes.Add(objDimension.KeyAttribute.ID);

objMGA.Type = MeasureGroupAttributeType.Granularity;
objMGA.KeyColumns.Add(strFactTableName, strTableKey, OleDbType.Integer);
}
catch (Exception ex)
{
Console.WriteLine("Error in Creating the Cube, MeasureGroup, Measure, and Partition Objects - GenerateCube. Error Message -> " + ex.Message);
}
}
#endregion Creating the Cube, MeasureGroup, Measure, and Partition Objects.

#endregion Cube Generation.
}
}


Friday, April 4, 2008

Nested Master Pages

To demonstrate the use of Nested Master Pages, I will create an application that display the Home page and Project pages of the application. This application consists of 3 Master pages and 2 Content pages. Out of 3 master pages, 1 is the main or parent master page and 2 are secondary or child master pages. One content page is for Home page and second content page is for Project pages.

1) To start with, first you have to create a Parent or Main master page, named ParentMasterPage.master. Following is the code snippet for it:


<%@ Master Language="C#" AutoEventWireup="true" CodeFile="ParentMasterPage.master.cs"
Inherits="BCLMasterPage" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>ParentMasterPage Page</title>

<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
if (!object.Equals(Session["Projects"], null))
{
if (!object.Equals(Request.QueryString["deleteProjectName"], null))
{
string strPageLink = Request.QueryString["deleteProjectName"];

string strExistingProjects = Session["Projects"].ToString();
strExistingProjects = strExistingProjects.Replace(strPageLink + ";", "");

Session["Projects"] = strExistingProjects;
}

string strExistingProjs = Session["Projects"].ToString();
string[] strProjs = strExistingProjs.Split(new char[] { ';' });
for (int i = 0; i < strProjs.Length - 1; i++)
{
string strProj = strProjs[i];

StringBuilder strbNewTab = new StringBuilder();
strbNewTab.AppendFormat(@"<div style=""display:inline;background-color:Yellow;"">");
strbNewTab.AppendFormat(@"<a href=""ProjectDefault.aspx?projectName={0}"">{0}</a>", strProj);
strbNewTab.AppendFormat(@"<a href=""Home.aspx?deleteProjectName={0}"">", strProj);
strbNewTab.AppendFormat(@"<img alt=""Close"" src=""Images/Close.GIF"" />");
strbNewTab.AppendFormat(@"</a>");
strbNewTab.AppendFormat(@"</div>&nbsp;&nbsp;");

//string strExisting = divTabs.InnerHtml;
divTabs.InnerHtml += strbNewTab.ToString();
}


}
}
</script>

</head>
<body style="margin: 0px 0px 0px 0px;">
<form id="form1" runat="server">
<table border="1" cellpadding="0" cellspacing="0" style="height: 100%; width: 100%;">
<tr style="height: 60px;">
<td align="center" style="background-">
<asp:ContentPlaceHolder ID="ProjectHeader" runat="server">
<span style="font-weight: bold; ">PARENT MASTER PAGE SECTION</span>
</asp:ContentPlaceHolder>
</td>
</tr>
<tr style="height: 20px;">
<td>
<div id="divTabs" runat="server">
<div style="display: inline; background-color: Yellow;">
<a href="Home.aspx">Home</a></div>
&nbsp;&nbsp;
</div>
</td>
</tr>
<tr>
<td>
<asp:ContentPlaceHolder ID="ProjectBody" runat="server">
</asp:ContentPlaceHolder>
</td>
</tr>
</table>
</form>
</body>
</html>
Note: For time being please ignore the JavaScript section.

2) Then create secondary master page for Home page, named PersonalMasterPage.master. Following is the code snippet for it:

<%@ Master Language="C#" MasterPageFile="~/ParentMasterPage.master" AutoEventWireup="true"
CodeFile="PersonalMasterPage.master.cs" Inherits="PersonalMasterPage" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ProjectBody" runat="Server">
<table border="1" cellpadding="0" cellspacing="0" style="height: 660px; width: 100%;">
<tr>
<td align="center" style="width: 200px; height: 100%; background-">
<span style="font-weight: bold; ">PERSONAL LEFT <br />PANE SECTION</span>
</td>
<td valign="top" style="height: 100%;">
<asp:ContentPlaceHolder ID="ProjectData" runat="server">
</asp:ContentPlaceHolder>
</td>
</tr>
</table>
</asp:Content>

3) Now create another secondary master page for Project pages, named ProjectMasterPage.master. Following is the code snippet for it:

<%@ Master Language="C#" MasterPageFile="~/ParentMasterPage.master" AutoEventWireup="true"
CodeFile="ProjectMasterPage.master.cs" Inherits="ProjectMasterPage" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ProjectBody" runat="Server">
<table border="1" cellpadding="0" cellspacing="0" style="height: 660px; width: 100%;">
<tr>
<td align="center" style="width: 200px; height: 100%; background-">
<span style="font-weight: bold; ">PROJECT LEFT <br />PANE SECTION</span>
</td>
<td valign="top" style="padding:10 10 10 10;">
<asp:ContentPlaceHolder ID="ProjectData" runat="server">
</asp:ContentPlaceHolder>
</td>
</tr>
</table>
</asp:Content>

4) Create Home content page named Home.aspx that inherits Personal Master Page. Following is the code snippet for it:

<%@ Page Language="C#" MasterPageFile="~/PersonalMasterPage.master" AutoEventWireup="true"
CodeFile="Home.aspx.cs" Inherits="Home" Title="Home Page" %>

<asp:Content ID="Content1" ContentPlaceHolderID="ProjectData" runat="Server">
<table cellpadding="0" cellspacing="0" border="1" style="width: 100%;">
<tr>
<td valign="top">
<table border="0" cellpadding="5" cellspacing="0" style="width: 100%; margin: 10px 10px 10px 10px;">
<tr>
<td style="height: 20px;" valign="top">
<b>Project OverView Links</b>
</td>
</tr>
<tr>
<td valign="top">
<table cellpadding="0" cellspacing="0">
<tr>
<td>
<a href="ProjectDefault.aspx?projectName=Gene">Gene</a><br />
<a href="ProjectDefault.aspx?projectName=Cancer">Cancer</a><br />
<a href="ProjectDefault.aspx?projectName=Brain">Brain</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<br />
<em>Other Data Section</em>
</td>
</tr>
</table>
</asp:Content>

5) Create Project content page named ProjectDefault.aspx that inherits Project Master Page. Following is the code snippet for it:

<%@ Page Language="C#" MasterPageFile="~/ProjectMasterPage.master" AutoEventWireup="true"
CodeFile="ProjectDefault.aspx.cs" Inherits="ProjectDefault" Title="Project Page" %>

<asp:Content ID="Content1" ContentPlaceHolderID="ProjectData" runat="Server">
<table cellpadding="0" cellspacing="0" border="1" style="width: 100%;">
<tr>
<td>
<div style="color: Blue; font-style: italic; font-weight: bold;" id="divPage" runat="server">
</div>
<b><em>Tab is selected</em></b>
</td>
</tr>
<tr>
<td>
<br />
<em>Other Project Data</em>
</td>
</tr>
</table>
</asp:Content>
CS file code:

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class ProjectDefault : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string strRequestedPage = Request.QueryString["projectName"];
divPage.InnerHtml = strRequestedPage;

if (object.Equals(Session["Projects"], null))
{
Session["Projects"] = strRequestedPage + ";";
}
else
{
string strExistingProjs = Session["Projects"].ToString();
if (!strExistingProjs.Contains(strRequestedPage))
Session["Projects"] = strExistingProjs + strRequestedPage + ";";
}
}
}




Following are the snapshots for Home and Project pages:











Top Green color section refers to Main Master Page and left Gray and Olive color sections refers to Personal Master Page and Project Master Page section respectively in above two figures.


Following is the snapshot of solution explorer of above application:






Now how the above application works:

I have created 3 links in Home page, on clicking of which I am entering its value in session and opens the Project page with modified query string. Similarly on clicking the cross of tab I am deleting that project entry from session and redirect the application to home page.

Wednesday, April 2, 2008

Custom theme in SharePoint

1. On the SharePoint Server go to the Themes folder e.g. C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\THEMES

2. Copy one of the theme folders from there and paste it in the same directory and give the folder a unique name, say MyTheme.



3. Find the .inf file in the copied folder, and rename it with the name given to the folder i.e. in this example rename that .inf file with MyTheme.INF

4. Open the .inf file and assign the same name i.e. MyTheme to the title in the [info] section of the file, and in the [titles] section replace the previous names with your new name.



5. There is one theme.css file in that MyTheme folder, open that, delete all the classes from that file and place your own css classes in that file.

6. Open “C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS\1033\SPTHEMES.XML” file with notepad



7. Add the following lines under tag



<templates>

<templateid>MyTheme</templateid>

<displayname>MyTheme</displayname>

<description>This is custom theme.</description>

<thumbnail>images/MyTheme.gif</thumbnail>

<preview>images/MyTheme.gif</preview>

</templates>




8. Where Template ID must be that of same name as that of the folder.

9. In order to display thumbnail and preview correctly, you will need to capture the screen and save the file in "C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\IMAGES" folder with MyTheme.gif name. You can change the .gif file name if you change the thumbnail and preview file names in tag.

10. Do an iisrest for the server to recognize the new theme.

11. Open your SharePoint site and go to the theme page by typing following URL in address bar: _layouts/themeweb.aspx


12. Select the theme and apply it to your site by clicking the Apply button.

Google